User defined macros

I have just finished hacking in user defined macros. For the moment they look like they will be up to any use I want to make of them at the moment. They are fairly simple, they are syntactically similar to functions. They must return a list. This then replaces the invoking code during compilation.

In this example, calls to “example” are replaced with “print”. Not especially useful, but it illustrates the point.

(macro example args
(local result ‘(print))
(while args
(set result (append_element result (head args)))
(set args (tail args)))

Macros live in a different namespace to other variables and functions, which could potentially be the source of bugs or confusion. If the list returned contains variable declarations, then these could conflict with ones in the calling environment. I am going to see if I find a way around this. Another issue is that functions are not created during compilation, they wait until runtime. This means that functions defined in the same chunk are not available in a macro. Functions that have been defined in previous chunks are available.

The compiler took some extending to support this.

Other changes include supporting vararg functions, changing the comments to C++ style and the beginnings of a set of unit tests. I plan to slowly build up a set of tests, especially for anything that I find doesn’t work and I then fix. I have a few tests that fail still, but I will come back to them when I have finished some other things.

The var arg functions support two calling modes. If called normally, then the parameter variable gets the value of a list containing all the arguments. If called with a single list argument, then this becomes the parameter variable. This can be seen in the macro above. If we call (example 1 2 3), then args is the list (1 2 3). If we call (example ‘(a b c)), then in theory args should be the list (a b c). However, having just tried this it doesn’t appear to work. Oh well, yet another entry in my unit tests to fix up later.

There are two things I’d like to do next. The first is to allow macros to return bytecode. This means that the things that are currently functions, including “if” and “while” can be changed to bytecode level jumps and conditions. Mathematical operators should get a similar treatment.

Another thing would be to try to evaluate as much at compile time. Since my implementation forces all variables to be declared, if I can evaluate an expression at compile time without getting an error then I can probably safely replace the expression with the result. For example (+ 2 4) could be replaced with 6 without getting errors.

I also want to work on the error handling. Right now there isn’t a very well though out approach to errors. The main problem is by the time the code is compiled there is no link between the bytecode and the source code. Actually this information is lost pretty quickly in the compile process, making it difficult to provide good error messages. I have reasonable syntax error messages, all with associated line numbers and “chunk names” (typically a filename).

Other errors are not so good. Most of these, for example a type error or unbound variable error, occur a few functions deep. Some of these functions are in C++ and others are in Lisp. There is a limited traceback facility provided by the interpreter. But it isn’t great. It treats fundamentals like “if” and “while” like regular functions, which tends to make the errors more difficult to parse. Ideally, I would like to be able to handle the errors cleanly from either Lisp or C++.

Until next time…


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: