Class: Macro::Node

Inherits:
Object show all
Defined in:
lib/macro.rb

Instance Method Summary collapse

Instance Method Details

#eval(binding = nil, file = nil, line = nil) ⇒ Object

just like Kernel#eval, but allows macros (and forms) and input is a RedParse parse tree (as receiver). beware: default for binding is currently broken. best practice is to pass an explicit binding (see Kernel#binding) for now.

binding

the binding in which to evaluate the node

file

for purpose of evaluation, the name of the file this node came from

line

for purpose of evaluation, the line number this node came from



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/macro.rb', line 284

def eval(binding=nil,file=nil,line=nil)
  #binding should default to Binding.of_caller, but.... that's expensive

  if String===binding
    file=binding
    binding=nil
  end
 
  #references to 'self' (implicit and explicit) within this parse tree
  #should be forced to refer to the self from binding, (if any)...

  expanded_tree=self   #Macro.expand(deep_copy,::Macro::GLOBALS)

  unparsed=expanded_tree.unparse
  #puts unparsed
  ::Kernel.eval unparsed, binding||::Object.new_binding,file||'(eval)',line||1
end

#load(name = '', wrap = false) ⇒ Object

A helper for Macro.load and Macro.eval. The source code for the node is saved to a file so that it can be viewed in the debugger.

name

the name of the file being loaded

wrap

whether to wrap the loaded file in an anonymous module



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/macro.rb', line 308

def load(name='',wrap=false)
  expanded_tree=self    #Macro.expand(deep_copy,::Macro::GLOBALS)

  #replace __FILE__ in tree with the correct file name
  #(otherwise, it will point to some tmp file)
  filenamenode=nil
  expanded_tree.walk{|parent,i,subi,node|
    if VarLikeNode===node and node.ident=="__FILE__"
      filenamenode||=Macro.quote name #StringNode[name.gsub(/['\\]/){|ch| '\\'+ch},{:@open=>"'", :@close=>"'"}]
      if parent
        subi ? parent[i][subi]=filenamenode : parent[i]=filenamenode
      else
        expanded_tree=filenamenode
      end
    end
    true
  }
  
  unparsed=expanded_tree.unparse
  #p expanded_tree
  #puts unparsed
  Tempfile.open("macroexpanded_"+name.gsub("/","__")){|tf|
    tf.write unparsed
    tf.flush
    ::Kernel::load tf.path, wrap
  }
  return true
end

#to_sexp(session) ⇒ Object

Convert this node to an S-expression

session

the context in which this macro is being processed



341
342
343
344
345
346
347
348
349
350
351
352
353
# File 'lib/macro.rb', line 341

def to_sexp session
  # TODO: this (and all other functions similarly named) is possibly
  # dead code
  self.class.name+"["+
    map{|param| call_to_sexp param,session }.join(", ")+
    ", {"+instance_variables.map{|iv| 
            iv=="@data" and next
            val=instance_variable_get(iv)
            val=call_to_sexp(val,session)
            ":"+iv+"=>"+val
          }.join(", ")+"}"+
  "]"
end