Class: Astrolabe::Node

Inherits:
Parser::AST::Node
  • Object
show all
Defined in:
lib/astrolabe/node.rb

Overview

Astrolabe::Node is a subclass of Parser::AST::Node. It provides an access to parent node and an object-oriented way to handle AST with the power of Enumerable.

Though not described in the auto-generated API documentation, it has predicate methods for every node type. These methods would be useful especially when combined with Enumerable methods.

Examples:

node.send_type?    # Equivalent to: `node.type == :send`
node.op_asgn_type? # Equivalent to: `node.type == :op_asgn`

# Non-word characters (other than a-zA-Z0-9_) in type names are omitted.
node.defined_type? # Equivalent to: `node.type == :defined?`

# Find the first lvar node under the receiver node.
lvar_node = node.each_descendant.find(&:lvar_type?)

Instance Method Summary collapse

Constructor Details

#initialize(type, children = [], properties = {}) ⇒ Node

Returns a new instance of Node.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/astrolabe/node.rb', line 23

def initialize(type, children = [], properties = {})
  @mutable_attributes = {}

  # ::AST::Node#initialize freezes itself.
  super

  # #parent= would be invoked multiple times for a node because there are pending nodes while
  # constructing AST and they are replaced later.
  # For example, `lvar` and `send` type nodes are initially created as an `ident` type node and
  # fixed to each type later.
  # So, the #parent attribute needs to be mutable.
  each_child_node do |child_node|
    child_node.parent = self
  end
end

Instance Method Details

#ancestorsArray<Node>

Returns an array of ancestor nodes. This is a shorthand for node.each_ancestor.to_a.

Returns:

  • (Array<Node>)

    an array of ancestor nodes



102
103
104
# File 'lib/astrolabe/node.rb', line 102

def ancestors
  each_ancestor.to_a
end

#child_nodesArray<Node>

Returns an array of child nodes. This is a shorthand for node.each_child_node.to_a.

Returns:

  • (Array<Node>)

    an array of child nodes



144
145
146
# File 'lib/astrolabe/node.rb', line 144

def child_nodes
  each_child_node.to_a
end

#descendantsArray<Node>

Returns an array of descendant nodes. This is a shorthand for node.each_descendant.to_a.

Returns:

  • (Array<Node>)

    an array of descendant nodes



184
185
186
# File 'lib/astrolabe/node.rb', line 184

def descendants
  each_descendant.to_a
end

#each_ancestorself, Enumerator #each_ancestor(type) ⇒ self, Enumerator #each_ancestor(type_a, type_b, ...) ⇒ self, Enumerator #each_ancestor(types) ⇒ self, Enumerator

Calls the given block for each ancestor node in the order from parent to root. If no block is given, an Enumerator is returned.

Overloads:

  • #each_ancestorself, Enumerator

    Yield all nodes.

  • #each_ancestor(type) ⇒ self, Enumerator

    Yield only nodes matching the type.

    Parameters:

    • type (Symbol)

      a node type

  • #each_ancestor(type_a, type_b, ...) ⇒ self, Enumerator

    Yield only nodes matching any of the types.

    Parameters:

    • type_a (Symbol)

      a node type

    • type_b (Symbol)

      a node type

  • #each_ancestor(types) ⇒ self, Enumerator

    Yield only nodes matching any of types in the array.

    Parameters:

    • types (Array<Symbol>)

      an array containing node types

Yield Parameters:

  • node (Node)

    each ancestor node

Returns:

  • (self)

    if a block is given

  • (Enumerator)

    if no block is given



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/astrolabe/node.rb', line 84

def each_ancestor(*types, &block)
  return to_enum(__method__, *types) unless block_given?

  types.flatten!

  if types.empty?
    visit_ancestors(&block)
  else
    visit_ancestors_with_types(types, &block)
  end

  self
end

#each_child_nodeself, Enumerator #each_child_node(type) ⇒ self, Enumerator #each_child_node(type_a, type_b, ...) ⇒ self, Enumerator #each_child_node(types) ⇒ self, Enumerator

Calls the given block for each child node. If no block is given, an Enumerator is returned.

Note that this is different from node.children.each { |child| ... } which yields all children including non-node element.

Overloads:

  • #each_child_nodeself, Enumerator

    Yield all nodes.

  • #each_child_node(type) ⇒ self, Enumerator

    Yield only nodes matching the type.

    Parameters:

    • type (Symbol)

      a node type

  • #each_child_node(type_a, type_b, ...) ⇒ self, Enumerator

    Yield only nodes matching any of the types.

    Parameters:

    • type_a (Symbol)

      a node type

    • type_b (Symbol)

      a node type

  • #each_child_node(types) ⇒ self, Enumerator

    Yield only nodes matching any of types in the array.

    Parameters:

    • types (Array<Symbol>)

      an array containing node types

Yield Parameters:

  • node (Node)

    each child node

Returns:

  • (self)

    if a block is given

  • (Enumerator)

    if no block is given



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/astrolabe/node.rb', line 127

def each_child_node(*types)
  return to_enum(__method__, *types) unless block_given?

  types.flatten!

  children.each do |child|
    next unless child.is_a?(Node)
    yield child if types.empty? || types.include?(child.type)
  end

  self
end

#each_descendantself, Enumerator #each_descendant(type) ⇒ self, Enumerator #each_descendant(type_a, type_b, ...) ⇒ self, Enumerator #each_descendant(types) ⇒ self, Enumerator

Calls the given block for each descendant node with depth first order. If no block is given, an Enumerator is returned.

Overloads:

  • #each_descendantself, Enumerator

    Yield all nodes.

  • #each_descendant(type) ⇒ self, Enumerator

    Yield only nodes matching the type.

    Parameters:

    • type (Symbol)

      a node type

  • #each_descendant(type_a, type_b, ...) ⇒ self, Enumerator

    Yield only nodes matching any of the types.

    Parameters:

    • type_a (Symbol)

      a node type

    • type_b (Symbol)

      a node type

  • #each_descendant(types) ⇒ self, Enumerator

    Yield only nodes matching any of types in the array.

    Parameters:

    • types (Array<Symbol>)

      an array containing node types

Yield Parameters:

  • node (Node)

    each descendant node

Returns:

  • (self)

    if a block is given

  • (Enumerator)

    if no block is given



166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/astrolabe/node.rb', line 166

def each_descendant(*types, &block)
  return to_enum(__method__, *types) unless block_given?

  types.flatten!

  if types.empty?
    visit_descendants(&block)
  else
    visit_descendants_with_types(types, &block)
  end

  self
end

#each_nodeself, Enumerator #each_node(type) ⇒ self, Enumerator #each_node(type_a, type_b, ...) ⇒ self, Enumerator #each_node(types) ⇒ self, Enumerator

Calls the given block for the receiver and each descendant node with depth first order. If no block is given, an Enumerator is returned.

This method would be useful when you treat the receiver node as a root of tree and want to iterate all nodes in the tree.

Overloads:

  • #each_nodeself, Enumerator

    Yield all nodes.

  • #each_node(type) ⇒ self, Enumerator

    Yield only nodes matching the type.

    Parameters:

    • type (Symbol)

      a node type

  • #each_node(type_a, type_b, ...) ⇒ self, Enumerator

    Yield only nodes matching any of the types.

    Parameters:

    • type_a (Symbol)

      a node type

    • type_b (Symbol)

      a node type

  • #each_node(types) ⇒ self, Enumerator

    Yield only nodes matching any of types in the array.

    Parameters:

    • types (Array<Symbol>)

      an array containing node types

Yield Parameters:

  • node (Node)

    each node

Returns:

  • (self)

    if a block is given

  • (Enumerator)

    if no block is given



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/astrolabe/node.rb', line 209

def each_node(*types, &block)
  return to_enum(__method__, *types) unless block_given?

  types.flatten!

  yield self if types.empty? || types.include?(type)

  if types.empty?
    visit_descendants(&block)
  else
    visit_descendants_with_types(types, &block)
  end

  self
end

#parentNode?

Returns the parent node, or nil if the receiver is a root node.

Returns:

  • (Node, nil)

    the parent node or nil



49
50
51
# File 'lib/astrolabe/node.rb', line 49

def parent
  @mutable_attributes[:parent]
end

#root?Boolean

Returns whether the receiver is a root node or not.

Returns:

  • (Boolean)

    whether the receiver is a root node or not



62
63
64
# File 'lib/astrolabe/node.rb', line 62

def root?
  parent.nil?
end