November 2nd, 2004


Ruby Sexps

Ruby's builtin classes are ok, things like Array are pretty easy to read. The Ruby interpreter itself is messy, there's so much black magic packed into eval.c that it is very difficult to figure everything out.

To make things easier on zenspider and myself we've rewritten some of the AST nodes in terms of others. Here's a list of what we've done so far:

Ruby has separate nodes for each of its three method call syntaxes: a NODE_CALL is built for, a NODE_FCALL is built for call(args) and a NODE_VCALL is built for a plain call. These we've collapsed into a single call node that uses nil for unused fields.

A method definition is a NODE_DEFN which contains a NODE_SCOPE, which may or may not contain a NODE_BLOCK, but in either case contains a NODE_ARGS to hold the list of arguments to the method. We've pulled the args up to be a direct child of the defn node.

NODE_CASE and NODE_WHEN are rewritten as nested if statements.

We still have some cleanups to be made that will make writing an interpreter easier, arg lists are held inside a NODE_ARGS, which could be flattened out inline, for example in a NODE_CALL:

 [:call, [:gvar, "$stderr"], "fputs", [:array, [:str, "blah"]]] 

Is currently rewritten to:

 [:call, "fputs", [:gvar, "$stderr"], [:array, [:str, "blah"]]] 

But could be rewritten to:

 [:call, "fputs", [:gvar, "$stderr"], [:str, "blah"]] 


 [:call, "fputs", [:gvar, "$stderr"], 1, [:str, "blah"]] 

Note that after rewriting a NODE_VCALL currently looks like:

 [:call, "puts", nil, nil] 

And a NODE_FCALL looks like:

 [:call, "puts", nil, [:array, [:str, "blah"]]] 

Now, why is Ruby's AST so complicated? Well, an RNode contains some flags, a string, and three fields. With only three fields some trade-offs needed to be made, and I imagine the designers traded memory for simplicity.

Since we have not yet written an interpreter for our rewritten Sexp, some of the magic of eval.c may take on more clarity.