|
Clambda or the happy hacker C programming environment |
Introduction
Learning common lisp and the power of having code as data and the good experience of having a regular
syntax lead to one fundamental point. Another one is that on top of lisp there is a more pure functional
languish called Qi that inter operates with common lisp quite well. In Qi you have prolog and yacc like functionality
that should be decent and more especially, you can explore and prove type related questions with the sequent calculus.
Finally there is quite a large code-base of C, it is not as large and complicated as c++ and many applications is written
in C. The idea is to explore what you get by marrying CL, Qi and C together into one system. There are some interesting
motivations or ideas explaining why I would like to test this out.
Main ideas
Idea 1, A live code object
You keep a live code object inside the memory that knows of all the types of all the parsing states and everything
in one environment, the macros and facilities you write should be close to the parser and the type manager.
You should be able to do advanced quires and refactoring operations. The integrated programming environment should not be a flashy
gui, it should be a command prompt. The gui, the editor, is just serving as a communicator to the programming environment
and human beings. I chooses to use the common lisp engine as a host. Maybe this is a bad choice, but there is some logic behind
this: the interpreter environment in slime is excellent. I would actually prefer to have an Ipython environment but python
is too slow for my purpose, java and C# is not interpreted. Finally lisp is a good guidance due to
the fact that the task of parsing lisp is on an order of magnitude easier than to parse most other languishes.
Idea 2, C is commonly used why not make it more potent in a new direction then c++ c# and java
In a sense C is simplistic and in many ways a glorified assembler but I actually like it. I usually come to activities
where C is the right languish to use (I need speed and closeness to hardware but the programs is too small to actually benifit from
object oriented programming). People are familiar with this languish so other people might be able to take advantage
of my tool. Basically I will make what I call a programming environment for C, and then later perhaps C++. It will not
be entirely C, but there will be a hopefully clear logical jump from C to Clambda. What I will mainly do is just to kick out the
c pre-processor and then let something more potent enter it's place.
Idea 3
My code should be targeted to be easy for humans to read and walk through and navigate in. My
experience is that I tend to code complex stuff (at work at least) and this coder reads the code not once but 50 times
before the code is debugged, I should not be concentrate on writing fast, I should actually optimize for read speed
and help my own understanding of the code.
Random things that can go into this languish
No operator precedence
operator precedence is a source of bugs, makes it more complex to do a correct parser, makes it more difficult to add
a new operator here and there.
An anonymous parenthesis
a * a+b
will be the same as a * (b + c) this particular case should be avoided but
makes significant less cluttered code. This is a clear style choice and should not be difficult to manage usually
writing something like a+b * c
almost certainly never happens in mono space code and a + b * c, will probably
signal an error (to say that + and - can be used together and (* /) can be used together is much much easier
than to specify a precedence order for a ton of variables (look at the C languish the precedence order are there to
capture some common cases in a compact and logical way, not easy). My experience after some experimenting is that
you will decrease the parenthesis overhead to an acceptable limit by allowing this.
We will use infix notation
You can here arguments that it is more difficult to automate code with infix notation. This is basically moot.
we will allow
(+ 1 + 2)
constructs as well as
(1 + 2)
In my book the valid reason why to complain about infix syntax is that it is against the style.
The lisp style is to fix the beginning of the parenthesis and then look next to it and in lisp voila you know what
the parenthesis does. On the other hand (1 + 2 + a*b) creates a pattern which your eyes more easily can recognize
without focusing. I want to leave the option open to both forms so that the good programmers can format the code
for good readability. One should use the automatic parenthesing option with care though.
We will signal right to left evaluation of the expression
The main source of right to left evaluation order is the assignment operator. expressions and assignments should give
different signals to the reader without a need to focus. I'm experimenting with the following form of assignment
expression
(-< x = a->data += 12)
The -< operator is a very good operator to show that we are evaluating from right to left, and will mostly be used
together with asignments and it visually gives a special character to asignments.
Lot's of parenthesis
If you think the code is bad because you get parenthesises everywhere you are most probably a sloppy hacker
when coding or did not use the right tool. Always when I feel this about lisp like code I play around with some
formatting of the expressions, aligning stuff, rearrange stuff to organize the code to look better and it does.
This activity of concentrating on style is what I want to promote and is a guiding line in this project. Actually
I think that these kind of activity lower your stress level and frees your mind without loosing too much productivity.
Quick Macros
Code should not be too wide, but today we have wide screens!! At some point simplified names for stuff went out of
style. And you know what, I think that this is not entirely good. Because the activity to find good short notions of
something makes the code so much more wonderful with respect to readability. if the text is shorter you find things
much faster and when trying to understand code you need to go up and down with your eyes trying to find stuff you
forgot about. A good coder is someone with short memory ;-) because he need to concentrate on good style. Well actually
short names is really bad for understandability, this is a common fact and the code should
be the documentation in many respects, I do not dispute that. But I will suggest in this languish that you keep your
code in multi column format, and keep one column with fast macros in site of their use, make sure that the ordering
of the macros are well structured and not to many and explore the cool space of short names. Quick macros should be
simple and not too complex and used often - experiment!!! The quick macros will be a pure
pre-processor kind of operation
% ( . = black-color-> )
(-< .part_0 = tzar_e ) % ( _e = _(.tzar-length - 1) )
(-< index = .longlist_Ai ) % ( _Ai = _(A-long-map-name _ i) )
Essentially A nomenclature has to be used and here we have been using . as representing a common structure prepath, _e as
being the end of a special array and _Ai to mean the index i maped to another index via map A = A-long... I do not want
to fix the nomenclature just promote the creation of nomenclature and let people at their taste use them and make sure
that a quick glance to the right can quickly decode the meaning of stuff. Basically if you see a short non
real word at the post or prefix position you will glance to the right to translate. Then at some point things can get
standardized. (Don't use this: my-name_a-long-index. It is terrible to read. The choise of _ as an index operator was
intentinally made to promote the use of the quick macros.)
hyphens as separators
AlongFile
A_long_file
A-long-file
I so much prefer the A-long-file, and the rule is that names should flow at the center line and _ and . brakes
the symmetry at the end causing attention to the post fix and prefixes. If you need to use long names use this instead:
(data->list _ longindex)
C version:
data->list[longindex]
See, if you use a long index the overhead of doing this is not much just three characters and it's
much more readable. Actually combining hyphen and minus is uggly so this choise has drawbacks but let's
go for hyphen as a separator.
make it possible to evaluate stuff in reverse order eg present the abstraction and below
present the details in the appendix a simple macro here
Make it easy to use Emacs lisp mode or the slime mode so we do not need to rework the amacs modes too much
Have some name space environments like constructs
Make some kind of demo of a more elaborate extension, introduce a poor mans finite domains for example
Example code
Here is a small example code to suggest the syntax, I continually code some algorithmes and experiment with
ideas.
(-rev-
(defun free (obj_ o)
(let (( .part_ part ( obj-to-part o) )
( uint mask ( 1 << part=>dist) )
( int unlucky? 0 )
( .node_ node ( part-to-node part) ))
(report-nfree-to-main node)
(if (full-mask node)
(-< unlucky? = 1 ))
(unset node mask)
(while ( (! node=>mask) && node=>parent )
(-< mask = node=>umask )
(-< node = node=>parent )
(-< node=>mask &= mask ))
(if unlucky?
(progn
(if (mid--unlucky) (update--mid))
(if (head-unlucky) (update-head))))))
(appendix free
(defun report-nfree-to-main ((.node_ node) -> void)
(node=>mem=>tot-free += node=>part-size))
(defmacro full-mask ((.node_ node) -> uint)
(node=>mask == 0xFFFFFFFF))
(defmacro unset ((.node_ node) (uint mask) -> void)
(node=>mask &= ~mask))
(defmacro head-unlucky ()
(if ( osp=>head-addr > _node >= mem=>head-addr ) 1 0))
(defmacro update-mid ()
(-< osp=>head-addr = _node ))
(defmacro mid--unlucky ()
(if (osp=>mid-addr < _node < mem=>head-addr ) 1 0))
(defmacro update-head ()
(-< osp=>mid-addr = _node ))))
The current state is to experiment and try out things.
Contact
If there is any questions or suggestions, use the forum on the sourceforge project page for Clambda