On Jan 3, 2008, at 15:50 , Giles Bowkett wrote:

>>>>> Sort of. It is obviously full of nifty and then some, and I  
>>>>> think you
> could use it to unit test metaprogramming, which is something the
> metaprogramming-averse complain about the absence of.
>
> But say I do this:
>
>>> pt = ParseTree.new.parse_tree_for_string("1 + 2 ; 1 * 2")
> (string):1: warning: useless use of + in void context
> => [[:block, [:call, [:lit, 1], :, [:array, [:lit, 2]]], [:call,
> [:lit, 1], :, [:array, [:lit, 2]]]]]
>>> Ruby2Ruby.new.process(pt.first)
> => "(1 + 2)\n(1 * 2)\n"
>
> What if I just want 1 * 2?

It depends on what sort of '1 * 2' you want... Do you want the last  
expression in a block/defn/whatever? Like, are you trying to analyze  
what the return type is? Or do you want to be aware of that void  
context warning and discard the crap? Or do you simply want the second  
thingy? Or do you want something entirely different that I am not  
anticipating?

There are a couple ways to go about it, depending on your answer  
above. The easiest is Sexp/Array manipulation. Let's say you were  
interested in the arg list of the last call in the block:

> >> sexp = Sexp.from_array pt.first
> => s(:block, s(:call, s(:lit, 1), :+, s(:array, s(:lit, 2))),  
> s(:call, s(:lit, 1), :*, s(:array, s(:lit, 2))))
> >> sexp.last
> => s(:call, s(:lit, 1), :*, s(:array, s(:lit, 2)))
> >> sexp.last.array
> => s(:array, s(:lit, 2))

This is a bad example because it has two calls in the block. With  
unique sub-sexp types in a sexp, you can just pull them out by name:

> >> sexp.call.array

But it balks when it is ambiguous.

But... if that isn't what you want, there are more powerful means of  
dealing with stuff:

class CallArgAnalyzer < SexpProcessor
   def process_call sexp
     sexp.shift # :call
     recv = sexp.shift
     name = sexp.shift
     args = sexp.shift

     # do something with args

     return s(:nil) # or whatever... depends on context
   end
end

> >> CallArgAnalyzer.new.process(sexp.first)
> => s(:nil)

Granted, this doesn't actually DO anything, but the framework to do  
something is there and solid... Do note that SexpProcessor is meant  
for transformational processing so it generally expects a sexp back  
(you can set what the return type should be for all process_*  
methods). The real point is that it is very easy to get at what you  
want and mess with it.