class CodeTools::AST::Node
Attributes
Public Class Methods
# File lib/rubinius/code/ast/node.rb, line 36 def self.match_arguments?(arguments, count) case arguments when ArrayLiteral arguments.body.size == count when nil count == 0 else false end end
# File lib/rubinius/code/ast/node.rb, line 30 def self.match_send?(node, receiver, method, name) node.kind_of? ConstantAccess and node.name == receiver and method == name end
# File lib/rubinius/code/ast/node.rb, line 47 def initialize(line) @line = line end
# File lib/rubinius/code/ast/node.rb, line 7 def self.transform(category, name, comment) Transforms.register category, name, self @transform_name = name @transform_comment = comment @transform_kind = :call end
# File lib/rubinius/code/ast/node.rb, line 18 def self.transform_comment @transform_comment end
# File lib/rubinius/code/ast/node.rb, line 22 def self.transform_kind @transform_kind end
# File lib/rubinius/code/ast/node.rb, line 26 def self.transform_kind=(k) @transform_kind = k end
# File lib/rubinius/code/ast/node.rb, line 14 def self.transform_name @transform_name end
Public Instance Methods
# File lib/rubinius/code/ast/node.rb, line 122 def ascii_graph AsciiGrapher.new(self).print end
Yields each attribute and its name to the block.
# File lib/rubinius/code/ast/node.rb, line 187 def attributes instance_variables.each do |var| child = instance_variable_get var name = var.to_s[1..-1] yield child, name end end
# File lib/rubinius/code/ast/node.rb, line 92 def bytecode(g) end
Yields each child of this Node
to the block. Additionally, for any attribute that is an Array, yields each element that is a Node
.
# File lib/rubinius/code/ast/node.rb, line 144 def children instance_variables.each do |var| child = instance_variable_get var if child.kind_of? Node yield child elsif child.kind_of? Array child.each { |x| yield x if x.kind_of? Node } end end end
# File lib/rubinius/code/ast/node.rb, line 95 def defined(g) g.push_rubinius g.push_scope g.send :active_path, 0 g.push_int @line g.send :unrecognized_defined, 2 g.pop g.push_tagged_nil 0 end
# File lib/rubinius/code/ast/node.rb, line 55 def new_block_generator(g, arguments) blk = g.class.new blk.name = g.state.name || :__block__ blk.file = g.file blk.for_block = true blk.required_args = arguments.required_args blk.post_args = arguments.post_args blk.total_args = arguments.total_args blk.splat_index = arguments.splat_index blk.block_index = arguments.block_index blk.arity = arguments.arity blk.keywords = arguments.keywords.entries if arguments.keywords blk.kwrest_index = arguments.kwrest_index blk end
# File lib/rubinius/code/ast/node.rb, line 73 def new_generator(g, name, arguments=nil) meth = g.class.new meth.name = name meth.file = g.file if arguments meth.required_args = arguments.required_args meth.post_args = arguments.post_args meth.total_args = arguments.total_args meth.splat_index = arguments.splat_index meth.block_index = arguments.block_index meth.arity = arguments.arity meth.keywords = arguments.keywords.entries if arguments.keywords meth.kwrest_index = arguments.kwrest_index end meth end
The equivalent of Some::Module.demodulize.underscore in ActiveSupport. The code is shamelessly borrowed as well.
# File lib/rubinius/code/ast/node.rb, line 157 def node_name name = self.class.name.gsub(/^.*::/, '') name.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') name.gsub!(/([a-z\d])([A-Z])/,'\1_\2') name.downcase! name end
Called if used as the lhs of an ||=. Expected to yield if the value was not found, so the bytecode for it to be emitted.
# File lib/rubinius/code/ast/node.rb, line 128 def or_bytecode(g) found = g.new_label bytecode(g) g.dup g.goto_if_true found g.pop yield found.set! end
# File lib/rubinius/code/ast/node.rb, line 51 def pos(g) g.set_line @line end
Called by transform
to update the child of a Node
instance. The default just calls the attr_accessor for the child. However, Node
subclasses that must synchronize other internal state can override this method.
# File lib/rubinius/code/ast/node.rb, line 182 def set_child(name, node) send :"#{name}=", node end
# File lib/rubinius/code/ast/node.rb, line 138 def to_sexp [:node, self.class.name] end
A fixed-point algorithm for transforming an AST
with a visitor. The traversal is top-down. The visitor object's method corresponding to each node (see node_name
) is called for each node, passing the node and its parent.
To replace the node in the tree, the visitor method should return a new node; otherwise, return the existing node. The visitor is free to change values in the node, but substituting a node causes the entire tree to be walked repeatedly until no modifications are made.
# File lib/rubinius/code/ast/node.rb, line 204 def transform(visitor, parent=nil, state=nil) state ||= TransformState.new node = visitor.send :"node_#{node_name}", self, parent state.modify unless equal? node node.attributes do |attr, name| if attr.kind_of? Node child = attr.transform visitor, node, state unless attr.equal? child state.modify node.set_child name, child end elsif attr.kind_of? Array attr.each_with_index do |x, i| if x.kind_of? Node child = x.transform visitor, node, state unless x.equal? child state.modify attr[i] = child end end end end end # Repeat the walk until the tree is not modified. if parent.nil? and state.modified? state.unmodify node = transform visitor, nil, state end node end
# File lib/rubinius/code/ast/node.rb, line 105 def value_defined(g, f) bytecode(g) end
Supports the Visitor pattern on a tree of Nodes. The visitor
should be an object that responds to methods named after the Node
subclasses. The method called is determined by the node_name
method. Passes both the node and its parent so that the visitor can maintain nesting information if desired.
The visit
implements a read-only traversal of the tree. To modify the tree, see the transform
methed.
# File lib/rubinius/code/ast/node.rb, line 173 def visit(visitor, parent=nil) visitor.__send__ self.node_name, self, parent children { |c| c.visit visitor, self } end
This method implements a sort of tree iterator, yielding each Node
instance to the provided block with the first argument to walk
. If
the block returns a non-true value, the walk is terminated.
This method is really an iterator, not a Visitor pattern.
# File lib/rubinius/code/ast/node.rb, line 114 def walk(arg=true, &block) children do |child| if ch_arg = block.call(arg, child) child.walk(ch_arg, &block) end end end