This is part of a series I started in March 2008 - you may want to go back and look at older parts if you're new to this series.
The code as at the end of this part can be found here
- exps = [:do] + zero_or_more(:defexp)
+ exps = zero_or_more(:defexp)
+ vars = deep_collect(exps,Array) {|node| node[0] == :assign ? node[1] : nil}
+ exps = [:let,vars] + exps
It leaves the method looking like this:
# Visit all objects in an array recursively.
# yield any object that #is_a?(c)
def deep_collect node, c = Array, &block
ret = []
if node.is_a?(c)
ret << yield(node)
end
if node.is_a?(Array)
node.each do |n|
if n.is_a?(Array) || n.is_a?(c)
ret << deep_collect(n,c,&block)
end
end
end
ret.flatten.uniq.compact
end
I am sure there's cleaner way of doing this, but the purpose is to walk through the tree of arrays we use as a syntax tree, and yield any object that #is_a?(c). #parse_defexp use that to check if one of the Array nodes in the tree starts with :assign, and assumes that the first argument to :assign will be a variable name (in the future we'll need to expand on that to walk through any trees there instead of just expecting a variable name), and return an array of the identified variable names.
Then #parse_defexp will create a :let node instead of a :do node like it used to.
That's all there's too it. The next part will look at something more interesting: I'm plugging in an adaptation of my operator precedence parser. Also note that code is already on Github to handle "while" - I won't be going through those changes as they're pretty straightforward, and uses exactly the same approach as I did to handle "def".