class CodeTools::AST::Node

Attributes

line[RW]

Public Class Methods

match_arguments?(arguments, count) click to toggle source
# 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
match_send?(node, receiver, method, name) click to toggle source
# 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
new(line) click to toggle source
# File lib/rubinius/code/ast/node.rb, line 47
def initialize(line)
  @line = line
end
transform(category, name, comment) click to toggle source
# 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
transform_comment() click to toggle source
# File lib/rubinius/code/ast/node.rb, line 18
def self.transform_comment
  @transform_comment
end
transform_kind() click to toggle source
# File lib/rubinius/code/ast/node.rb, line 22
def self.transform_kind
  @transform_kind
end
transform_kind=(k) click to toggle source
# File lib/rubinius/code/ast/node.rb, line 26
def self.transform_kind=(k)
  @transform_kind = k
end
transform_name() click to toggle source
# File lib/rubinius/code/ast/node.rb, line 14
def self.transform_name
  @transform_name
end

Public Instance Methods

ascii_graph() click to toggle source
# File lib/rubinius/code/ast/node.rb, line 122
def ascii_graph
  AsciiGrapher.new(self).print
end
attributes() { |child, name| ... } click to toggle source

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
bytecode(g) click to toggle source
# File lib/rubinius/code/ast/node.rb, line 92
def bytecode(g)
end
children() { |child| ... } click to toggle source

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
defined(g) click to toggle source
# 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
new_block_generator(g, arguments) click to toggle source
# 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
new_generator(g, name, arguments=nil) click to toggle source
# 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
node_name() click to toggle source

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
or_bytecode(g) { || ... } click to toggle source

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
pos(g) click to toggle source
# File lib/rubinius/code/ast/node.rb, line 51
def pos(g)
  g.set_line @line
end
set_child(name, node) click to toggle source

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
to_sexp() click to toggle source
# File lib/rubinius/code/ast/node.rb, line 138
def to_sexp
  [:node, self.class.name]
end
transform(visitor, parent=nil, state=nil) click to toggle source

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
value_defined(g, f) click to toggle source
# File lib/rubinius/code/ast/node.rb, line 105
def value_defined(g, f)
  bytecode(g)
end
visit(visitor, parent=nil) click to toggle source

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
walk(arg=true, &block) click to toggle source

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