Class: Mirah::AST::Node

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/mirah/ast.rb,
lib/mirah/jvm/source_generator/precompile.rb

Overview

The top of the AST class hierarchy, this represents an abstract AST node. It provides accessors for children, an array of all child nodes, parent, a reference to this node’s parent (nil if none), and newline, whether this node represents a new line.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent, position, children = []) {|self| ... } ⇒ Node

Returns a new instance of Node.

Parameters:

  • parent (Mirah::AST::Node)

    the parent node

  • position (JMetaPosition)

    the location in the source code of the node

  • children (Array) (defaults to: [])

    the list of child nodes

Yields:

  • (self)

    yields the node being initialized, expects the list of children as the result. takes priority over the ‘children` argument.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/mirah/ast.rb', line 75

def initialize(parent, position, children = [])
  # JRuby 1.6.x doesn't seem to like become_java! as much (see bottom of class)
  if JRUBY_VERSION < '1.7'
    JRuby.reference(self.class).setRubyClassAllocator(JRuby.reference(self.class).reified_class)
  end
  
  unless parent.nil? || Mirah::AST::Node === parent
    raise "Mirah::AST::Node.new parent #{parent.class} must be nil or === Mirah::AST::Node."
  end

  @parent = parent
  @newline = false
  @inferred_type = nil
  @resolved = false
  @position = position
  if block_given?
    @children ||= []
    @children = yield(self) || []
  else
    @children = children
  end
end

Instance Attribute Details

#childrenObject

Returns the value of attribute children.



35
36
37
# File 'lib/mirah/ast.rb', line 35

def children
  @children
end

#inferred_typeObject

Returns the value of attribute inferred_type.



39
40
41
# File 'lib/mirah/ast.rb', line 39

def inferred_type
  @inferred_type
end

#newlineObject

Returns the value of attribute newline.



38
39
40
# File 'lib/mirah/ast.rb', line 38

def newline
  @newline
end

#parentObject

Returns the value of attribute parent.



36
37
38
# File 'lib/mirah/ast.rb', line 36

def parent
  @parent
end

#positionObject

Returns the value of attribute position.



37
38
39
# File 'lib/mirah/ast.rb', line 37

def position
  @position
end

Class Method Details

.===(other) ⇒ Object



259
260
261
# File 'lib/mirah/ast.rb', line 259

def self.===(other)
  super || (other.kind_of?(NodeProxy) && (self === other.__getobj__))
end

._load(vars) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/mirah/ast.rb', line 118

def self._load(vars)
  node = self.allocate
  Marshal.load(vars).each do |name, value|
    node.instance_variable_set(name, value)
  end
  node.children.each do |child|
    node._set_parent(child)
  end
  node.validate_children
  node
end

.child(name) ⇒ Object

defines children of a node by name, respecting call order.

Parameters:

  • name (Symbol)

    the name of the child node



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/mirah/ast.rb', line 45

def self.child(name)
  @children ||= []
  index = @children.size
  class_eval <<-EOF
    def #{name}
      @children[#{index}]
    end

    def #{name}=(node)
      @children[#{index}] = _set_parent(node)
    end
  EOF
  @children << name
end

.child_name(i) ⇒ Object



60
61
62
# File 'lib/mirah/ast.rb', line 60

def self.child_name(i)
  @children[i] if @children
end

Instance Method Details

#<<(node) ⇒ Object



230
231
232
233
# File 'lib/mirah/ast.rb', line 230

def <<(node)
  @children << _set_parent(node)
  self
end

#[](index) ⇒ Object



221
# File 'lib/mirah/ast.rb', line 221

def [](index) children[index] end

#[]=(index, node) ⇒ Object



223
224
225
226
# File 'lib/mirah/ast.rb', line 223

def []=(index, node)
  node.parent = self
  @children[index] = node
end

#_dump(depth) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/mirah/ast.rb', line 98

def _dump(depth)
  to_skip = %w(@parent @newline @inferred_type @resolved @proxy @scope @class_scope @static_scope @typer)
  vars = {}
  instance_variables.each do |name|
    next if to_skip.include?(name)
    vars[name] = instance_variable_get(name)
    begin
      Mirah::AST::Unquote.extract_values do
        Marshal.dump(vars[name]) if AST.verbose
      end
    rescue
      puts "#{self}: Failed to marshal #{name}"
      puts inspect
      puts $!, $@
      raise $!
    end
  end
    Marshal.dump(vars)
end

#_set_parent(node) ⇒ Object



263
264
265
266
267
268
269
270
271
# File 'lib/mirah/ast.rb', line 263

def _set_parent(node)
  case node
  when Node
    node.parent = self
  when ::Array
    node.each {|x| x.parent = self if x}
  end
  node
end

#child_nodesObject



64
65
66
# File 'lib/mirah/ast.rb', line 64

def child_nodes
  java.util.ArrayList.new(@children)
end

#each(&b) ⇒ Object



228
# File 'lib/mirah/ast.rb', line 228

def each(&b) children.each(&b) end

#empty?Boolean

Returns:



240
241
242
# File 'lib/mirah/ast.rb', line 240

def empty?
  @children.empty?
end

#expr?(compiler) ⇒ Boolean

Returns:



41
42
43
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 41

def expr?(compiler)
  true
end

#inferred_type!Object



293
294
295
296
297
298
299
# File 'lib/mirah/ast.rb', line 293

def inferred_type!
  unless @inferred_type
    raise Mirah::InternalCompilerError.new(
        "Internal Error: #{self.class} never inferred", self)
  end
  inferred_type
end

#initialize_copy(other) ⇒ Object



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/mirah/ast.rb', line 273

def initialize_copy(other)
  # bug: node is deferred, but it's parent isn't
  #      parent gets duped
  #      duped parent is inferred so it's children aren't
  #      original node gets inferred, but not the duplicate child
  @inferred_type = @resolved = nil
  @parent = nil
  @children = []
  other.children.each do |child|
    case child
    when ::Array
      self << child.map {|x| x.dup}
    when nil
      self << nil
    else
      self << child.dup
    end
  end
end

#insert(index, node) ⇒ Object



235
236
237
238
# File 'lib/mirah/ast.rb', line 235

def insert(index, node)
  node.parent = self
  @children.insert(index, node)
end

#inspect(indent = 0) ⇒ Object



206
207
208
209
# File 'lib/mirah/ast.rb', line 206

def inspect(indent = 0)
  indent_str = ' ' * indent
  indent_str << to_s << inspect_children(indent)
end

#inspect_children(indent = 0) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/mirah/ast.rb', line 161

def inspect_children(indent = 0)
  indent_str = ' ' * indent
  str = ''
  children.each_with_index do |child, i|
    extra_indent = 0
    if child
      name = self.class.child_name(i)
      
      wrong_parent = lambda do |child|
        if Node === child && child.parent != self 
          "\n#{indent_str} (wrong parent)"
        else
          ""
        end
      end
      
      if Mirah::AST.verbose && name
        str << "\n#{indent_str} #{name}:"
        extra_indent = 1
      end
      
      case child
      when ::Array
        child.each do |ary_child|
          
          str << wrong_parent[ary_child] if Mirah::AST.verbose
          
          str << "\n#{ary_child.inspect(indent + extra_indent + 1)}"
        end
      when ::Hash, ::String
        str << "\n#{indent_str} #{child.inspect}"
      else
        str << wrong_parent[child] if Mirah::AST.verbose
        
        begin
          str << "\n#{child.inspect(indent + extra_indent + 1)}"
        rescue ArgumentError => ex
          str << "\n#{indent_str} #{child.inspect}"
        end
      end
    end
  end
  str
end

#line_numberObject



149
150
151
152
153
154
155
# File 'lib/mirah/ast.rb', line 149

def line_number
  if @position
    @position.start_line + 1
  else
    0
  end
end

#log(message) ⇒ Object



157
158
159
# File 'lib/mirah/ast.rb', line 157

def log(message)
  puts "* [AST] [#{simple_name}] " + message if AST.verbose
end

#precompile(compiler) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 45

def precompile(compiler)
  if expr?(compiler)
    self
  else
    temp(compiler)
  end
end

#resolve_if(typer) ⇒ Object



251
252
253
254
255
256
257
# File 'lib/mirah/ast.rb', line 251

def resolve_if(typer)
  unless resolved?
    @inferred_type = yield
    @inferred_type ? resolved!(typer) : typer.defer(self)
  end
  @inferred_type
end

#resolved!(typer = nil) ⇒ Object



244
245
246
247
# File 'lib/mirah/ast.rb', line 244

def resolved!(typer=nil)
  log "#{to_s} resolved!"
  @resolved = true
end

#resolved?Boolean

Returns:



249
# File 'lib/mirah/ast.rb', line 249

def resolved?; @resolved end

#simple_nameObject



211
212
213
# File 'lib/mirah/ast.rb', line 211

def simple_name
  self.class.name.split("::")[-1]
end

#string_valueObject

Raises:



217
218
219
# File 'lib/mirah/ast.rb', line 217

def string_value
  raise Mirah::SyntaxError.new("Can't use #{self.class} as string literal")
end

#temp(compiler, value = nil) ⇒ Object



53
54
55
# File 'lib/mirah/jvm/source_generator/precompile.rb', line 53

def temp(compiler, value=nil)
  TempValue.new(self, compiler, value)
end

#to_sObject



215
# File 'lib/mirah/ast.rb', line 215

def to_s; simple_name; end

#top_level?Boolean

Returns:



301
302
303
# File 'lib/mirah/ast.rb', line 301

def top_level?
  false
end

#validate_child(child, i) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mirah/ast.rb', line 137

def validate_child(child, i)
  name = self.class.child_name(i)
  validator = :"validate_#{name}"
  if name && respond_to?(validator)
    send validator
  else
    if UnquotedValue === child
      self[i] = child.node
    end
  end
end

#validate_childrenObject



130
131
132
133
134
135
# File 'lib/mirah/ast.rb', line 130

def validate_children
  validate_name if respond_to?(:validate_name)
  children.each_with_index do |child, i|
    validate_child(child, i)
  end
end