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