rltk 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +21 -22
  3. data/lib/rltk/ast.rb +185 -118
  4. data/lib/rltk/cfg.rb +157 -103
  5. data/lib/rltk/cg/basic_block.rb +19 -19
  6. data/lib/rltk/cg/bindings.rb +16 -16
  7. data/lib/rltk/cg/builder.rb +129 -129
  8. data/lib/rltk/cg/context.rb +7 -7
  9. data/lib/rltk/cg/contractor.rb +7 -7
  10. data/lib/rltk/cg/execution_engine.rb +30 -30
  11. data/lib/rltk/cg/function.rb +37 -37
  12. data/lib/rltk/cg/generated_bindings.rb +3932 -3932
  13. data/lib/rltk/cg/generic_value.rb +17 -17
  14. data/lib/rltk/cg/instruction.rb +116 -116
  15. data/lib/rltk/cg/llvm.rb +22 -22
  16. data/lib/rltk/cg/memory_buffer.rb +7 -7
  17. data/lib/rltk/cg/module.rb +73 -73
  18. data/lib/rltk/cg/pass_manager.rb +35 -35
  19. data/lib/rltk/cg/target.rb +41 -41
  20. data/lib/rltk/cg/triple.rb +7 -7
  21. data/lib/rltk/cg/type.rb +75 -75
  22. data/lib/rltk/cg/value.rb +161 -161
  23. data/lib/rltk/lexer.rb +57 -57
  24. data/lib/rltk/lexers/calculator.rb +7 -7
  25. data/lib/rltk/lexers/ebnf.rb +5 -5
  26. data/lib/rltk/parser.rb +338 -295
  27. data/lib/rltk/parsers/infix_calc.rb +7 -7
  28. data/lib/rltk/parsers/postfix_calc.rb +3 -3
  29. data/lib/rltk/parsers/prefix_calc.rb +3 -3
  30. data/lib/rltk/token.rb +13 -13
  31. data/lib/rltk/version.rb +6 -6
  32. data/test/cg/tc_basic_block.rb +17 -17
  33. data/test/cg/tc_control_flow.rb +41 -41
  34. data/test/cg/tc_function.rb +4 -4
  35. data/test/cg/tc_generic_value.rb +3 -3
  36. data/test/cg/tc_instruction.rb +53 -53
  37. data/test/cg/tc_math.rb +12 -12
  38. data/test/cg/tc_module.rb +14 -14
  39. data/test/cg/tc_transforms.rb +11 -11
  40. data/test/cg/tc_type.rb +12 -12
  41. data/test/cg/tc_value.rb +35 -35
  42. data/test/cg/ts_cg.rb +5 -5
  43. data/test/tc_ast.rb +137 -60
  44. data/test/tc_cfg.rb +34 -34
  45. data/test/tc_lexer.rb +42 -42
  46. data/test/tc_parser.rb +250 -173
  47. data/test/tc_token.rb +2 -2
  48. data/test/ts_rltk.rb +8 -8
  49. metadata +84 -85
  50. data/lib/rltk/cg/old_generated_bindings.rb +0 -6152
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7aea9d6131d23f28ce6f81eabf14d4074719716
4
- data.tar.gz: da39fb4ebfa9591f50889406b5b71f50beb7d42f
3
+ metadata.gz: 99843025256c5d1cdcd1b826714ccc48fc2ebd36
4
+ data.tar.gz: fd8b9750f1fa95c9a810a3395820c4c9e88c6e99
5
5
  SHA512:
6
- metadata.gz: ad2d8ada835e7e81b2565ef9eec47d63c85460adff03336b85bddbb9bd05ab13ce3b82d26808bbf389f9babd22618ab396f95a717e33d9dd925efcb62a361bea
7
- data.tar.gz: eba4da2a9be4bb468e5c1127394320af284efa014b7a0a49e1967885db3c52817d2e62c689ebf4ed0a7820c3ffbf591cd32c0a8f5a3d8bd2a6cc451b114ce8d5
6
+ metadata.gz: 6bfb8a1cad07ed24d3f26453a028878e4e18875ad1c417d55aa9c42f065f9b2bdcf5491139bf0355b0d6b4027317309823983dbd7ca164e00b8c3320980ea614
7
+ data.tar.gz: 6e55e4df8368b686d966aa6bcd2d5431b81b59d25327f41b20bd1df3c23c89e4fac12d8d4d4e6b0836ad7b2467170582a30fc2f5bdce30f2fda6d41b0c77c354
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
- # Author: Chris Wailes <chris.wailes@gmail.com>
2
- # Project: Ruby Language Toolkit
3
- # Date: 2011/04/06
4
- # Description: This is RLTK's Rakefile.
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2011/04/06
4
+ # Description: This is RLTK's Rakefile.
5
5
 
6
6
  ##############
7
7
  # Rake Tasks #
@@ -91,7 +91,7 @@ end
91
91
  request_file('yard', 'Yard is not installed.') do
92
92
  YARD::Rake::YardocTask.new do |t|
93
93
  yardlib = File.join(File.dirname(__FILE__), 'yardlib/rltk.rb')
94
-
94
+
95
95
  t.options = [
96
96
  '-e', yardlib,
97
97
  '--title', 'The Ruby Language Toolkit',
@@ -99,7 +99,7 @@ request_file('yard', 'Yard is not installed.') do
99
99
  '-M', 'redcarpet',
100
100
  '--private'
101
101
  ]
102
-
102
+
103
103
  t.files = Dir['lib/**/*.rb'] +
104
104
  ['-'] +
105
105
  Dir['examples/kazoo/**/*.md'].sort
@@ -113,20 +113,20 @@ end
113
113
  desc 'Generate the bindings for LLVM.'
114
114
  task :gen_bindings do
115
115
  require 'ffi_gen'
116
-
116
+
117
117
  # Generate the standard LLVM bindings.
118
-
118
+
119
119
  deprecated = [
120
120
  # BitReader.h
121
121
  'LLVMGetBitcodeModuleProviderInContext',
122
122
  'LLVMGetBitcodeModuleProvider',
123
-
123
+
124
124
  # BitWriter.h
125
125
  'LLVMWriteBitcodeToFileHandle',
126
-
126
+
127
127
  # Core.h
128
128
  'LLVMCreateFunctionPassManager',
129
-
129
+
130
130
  # ExectionEngine.h
131
131
  'LLVMCreateExecutionEngine',
132
132
  'LLVMCreateInterpreter',
@@ -134,10 +134,10 @@ task :gen_bindings do
134
134
  'LLVMAddModuleProvider',
135
135
  'LLVMRemoveModuleProvider'
136
136
  ]
137
-
137
+
138
138
  headers = [
139
139
  'llvm-c/Core.h',
140
-
140
+
141
141
  'llvm-c/Analysis.h',
142
142
  'llvm-c/BitReader.h',
143
143
  'llvm-c/BitWriter.h',
@@ -151,13 +151,13 @@ task :gen_bindings do
151
151
  'llvm-c/Support.h',
152
152
  'llvm-c/Target.h',
153
153
  'llvm-c/TargetMachine.h',
154
-
154
+
155
155
  'llvm-c/Transforms/IPO.h',
156
156
  'llvm-c/Transforms/PassManagerBuilder.h',
157
157
  'llvm-c/Transforms/Scalar.h',
158
158
  'llvm-c/Transforms/Vectorize.h'
159
159
  ]
160
-
160
+
161
161
  FFIGen.generate(
162
162
  module_name: 'RLTK::CG::Bindings',
163
163
  ffi_lib: "LLVM-#{RLTK::LLVM_TARGET_VERSION}",
@@ -171,28 +171,27 @@ end
171
171
 
172
172
  desc 'Find LLVM bindings with a regular expression.'
173
173
  task :find_bind, :part do |t, args|
174
-
174
+
175
175
  # Get the task argument.
176
176
  part = Regexp.new(args[:part])
177
-
177
+
178
178
  # Require the Bindings module.
179
179
  require 'rltk/cg/bindings'
180
-
180
+
181
181
  syms =
182
182
  Symbol.all_symbols.select do |sym|
183
183
  sym = sym.to_s.downcase
184
-
184
+
185
185
  sym[0..3] == 'llvm' and sym[4..-1] =~ part
186
186
  end.sort
187
-
187
+
188
188
  puts
189
189
  if not syms.empty?
190
190
  puts "Matching bindings [#{syms.length}]:"
191
191
  syms.each { |sym| puts "\t#{sym}" }
192
-
192
+
193
193
  else
194
194
  puts 'No matching bindings.'
195
195
  end
196
196
  puts
197
197
  end
198
-
@@ -12,6 +12,7 @@ require 'filigree/abstract_class'
12
12
  require 'filigree/class'
13
13
  require 'filigree/match'
14
14
  require 'filigree/types'
15
+ require 'filigree/visitor'
15
16
 
16
17
  #######################
17
18
  # Classes and Modules #
@@ -20,22 +21,29 @@ require 'filigree/types'
20
21
  module RLTK
21
22
  # This class is a good start for all your abstract syntax tree node needs.
22
23
  class ASTNode
23
-
24
+
25
+ include Filigree::Visitable
26
+
24
27
  extend Filigree::AbstractClass
25
28
  extend Filigree::Destructurable
26
-
29
+
27
30
  # @return [ASTNode] Reference to the parent node.
28
31
  attr_accessor :parent
29
-
32
+
30
33
  # @return [Hash] The notes hash for this node.
31
34
  attr_reader :notes
32
-
35
+
33
36
  #################
34
37
  # Class Methods #
35
38
  #################
36
-
39
+
37
40
  class << self
38
-
41
+
42
+ # @return [Array<Symbol>] List of members (children and values) that have array types
43
+ def array_members
44
+ @array_members
45
+ end
46
+
39
47
  # Check to make sure a name isn't re-defining a value or child.
40
48
  #
41
49
  # @raise [ArgumentError] Raised if the name is already used for an existing value or child
@@ -43,30 +51,38 @@ module RLTK
43
51
  if @child_names.include? name
44
52
  raise ArgumentError, "Class #{self} or one of its superclasses already defines a child named #{name}"
45
53
  end
46
-
54
+
47
55
  if @value_names.include?(name)
48
56
  raise ArgumentError, "Class #{self} or one of its superclasses already defines a value named #{name}"
49
57
  end
50
58
  end
51
-
52
- # Installs instance class varialbes into a class.
59
+
60
+ # Installs instance class variables into a class.
53
61
  #
54
62
  # @return [void]
55
63
  def install_icvars
56
64
  if self.superclass == ASTNode
57
- @child_names = Array.new
58
- @child_types = Array.new
59
- @value_names = Array.new
60
- @value_types = Array.new
65
+ @child_names = Array.new
66
+ @value_names = Array.new
67
+ @array_members = Array.new
68
+
69
+ @member_order = :values
70
+ @def_order = Array.new
71
+ @inc_children = Array.new
72
+ @inc_values = Array.new
61
73
  else
62
- @child_names = self.superclass.child_names.clone
63
- @child_types = self.superclass.child_types.clone
64
- @value_names = self.superclass.value_names.clone
65
- @value_types = self.superclass.value_types.clone
74
+ @child_names = self.superclass.child_names.clone
75
+ @value_names = self.superclass.value_names.clone
76
+ @array_members = self.superclass.array_members.clone
77
+
78
+ @member_order = (v = self.superclass.member_order).is_a?(Symbol) ? v : v.clone
79
+ @def_order = self.superclass.def_order.clone
80
+ @inc_children = self.superclass.inc_children.clone
81
+ @inc_values = self.superclass.inc_values.clone
66
82
  end
67
83
  end
68
84
  protected :install_icvars
69
-
85
+
70
86
  # Called when the Lexer class is sub-classed, it installes
71
87
  # necessary instance class variables.
72
88
  #
@@ -76,50 +92,56 @@ module RLTK
76
92
  def inherited(klass)
77
93
  klass.install_icvars
78
94
  end
79
-
95
+
80
96
  # Defined a child for this AST class and its subclasses.
81
97
  # The name of the child will be used to define accessor
82
98
  # methods that include type checking. The type of this
83
99
  # child must be a subclass of the ASTNode class.
84
100
  #
85
- # @param [String, Symbol] name Name of child node.
101
+ # @param [String, Symbol] name Name of child node
86
102
  # @param [Class] type Type of child node. Must be a subclass of ASTNode.
103
+ # @param [Boolean] omit Include the child in the constructor or not
87
104
  #
88
105
  # @return [void]
89
- def child(name, type)
106
+ def child(name, type, omit = false)
90
107
  check_odr(name)
91
-
108
+
92
109
  if type.is_a?(Array) and type.length == 1
93
110
  t = type.first
94
-
111
+
95
112
  elsif type.is_a?(Class)
96
113
  t = type
97
-
114
+
98
115
  else
99
116
  raise 'Child and Value types must be a class name or an array with a single class name element.'
100
117
  end
101
-
102
- # Check to make sure that type is a subclass of
103
- # ASTNode.
118
+
119
+ # Check to make sure that type is a subclass of ASTNode.
104
120
  if not t.subclass_of?(ASTNode)
105
121
  raise "A child's type specification must be a subclass of ASTNode."
106
122
  end
107
-
108
- @child_names << name
109
- @child_types << type
123
+
124
+ @child_names << name
125
+ @array_members << name if type.is_a?(Array)
126
+
127
+ if not omit
128
+ @def_order << name
129
+ @inc_children << name
130
+ end
131
+
110
132
  define_accessor(name, type, true)
111
133
  end
112
-
134
+
113
135
  # @return [Array<Symbol>] Array of the names of this node class's children
114
136
  def child_names
115
137
  @child_names
116
138
  end
117
-
118
- # @return [Array] Array of types of this node class's children
119
- def child_types
120
- @child_types
139
+
140
+ # @return [Array<Symbol>] Array of names of values/children in the order they were defined
141
+ def def_order
142
+ @def_order
121
143
  end
122
-
144
+
123
145
  # This method defines a type checking accessor named *name*
124
146
  # with type *type*.
125
147
  #
@@ -130,31 +152,31 @@ module RLTK
130
152
  # @return [void]
131
153
  def define_accessor(name, type, set_parent = false)
132
154
  ivar_name = ('@' + name.to_s).to_sym
133
-
155
+
134
156
  define_method(name) do
135
157
  self.instance_variable_get(ivar_name)
136
158
  end
137
-
159
+
138
160
  if type.is_a?(Class)
139
161
  if set_parent
140
162
  define_method((name.to_s + '=').to_sym) do |value|
141
163
  self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
142
164
  value.parent = self if value
143
165
  end
144
-
166
+
145
167
  else
146
168
  define_method((name.to_s + '=').to_sym) do |value|
147
169
  self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
148
170
  end
149
171
  end
150
-
172
+
151
173
  else
152
174
  if set_parent
153
175
  define_method((name.to_s + '=').to_sym) do |value|
154
176
  self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
155
177
  value.each { |c| c.parent = self }
156
178
  end
157
-
179
+
158
180
  else
159
181
  define_method((name.to_s + '=').to_sym) do |value|
160
182
  self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
@@ -163,48 +185,87 @@ module RLTK
163
185
  end
164
186
  end
165
187
  private :define_accessor
166
-
188
+
189
+ # Define a custom ordering for the class to use when building the
190
+ # default constructor and destructurer.
191
+ #
192
+ # @param [Array<Symbol>] members List of member names
193
+ #
194
+ # @return [void]
195
+ def custom_order(*members)
196
+ @member_order = members
197
+ end
198
+
199
+ # @return [Array<Symbol>] Array of the names of children that should be included in the constructor
200
+ def inc_children
201
+ @inc_children
202
+ end
203
+
204
+ # @return [Array<Symbol>] Array of the names of values that should be included in the constructor
205
+ def inc_values
206
+ @inc_values
207
+ end
208
+
209
+ # A getter and setter for a class's initialization order. If the
210
+ # order value is `:values` the constructor will expect all of the
211
+ # values and then the children. If it is `:children` then the
212
+ # constructor expects children and then values. If it is `:def`
213
+ # the constructor expects to values and children in the order that
214
+ # they were defined. If val is nil the current value will be
215
+ # returned.
216
+ #
217
+ # The default ordering is `:values`, which matches the behavior of
218
+ # previous versions of RLTK.
219
+ #
220
+ # @param [:values, :children, :def] val The new initialization order
221
+ #
222
+ # @return [:values, :children, :def] The current initialization order
223
+ def member_order(val = nil)
224
+ if val
225
+ @member_order = val
226
+ else
227
+ @member_order
228
+ end
229
+ end
230
+ alias :order :member_order
231
+
167
232
  # Defined a value for this AST class and its subclasses.
168
233
  # The name of the value will be used to define accessor
169
234
  # methods that include type checking.
170
235
  #
171
236
  # @param [String, Symbol] name Name of value
172
237
  # @param [Class] type Type of value
238
+ # @param [Boolean] omit Include the value in the constructor or not
173
239
  #
174
240
  # @return [void]
175
- def value(name, type)
241
+ def value(name, type, omit = false)
176
242
  check_odr(name)
177
-
178
- if type.is_a?(Array) and type.length == 1
179
- t = type.first
180
-
181
- elsif type.is_a?(Class)
182
- t = type
183
-
184
- else
243
+
244
+ if not (type.is_a?(Class) or (type.is_a?(Array) and type.length == 1))
185
245
  raise 'Child and Value types must be a class name or an array with a single class name element.'
186
246
  end
187
-
188
- @value_names << name
189
- @value_types << type
247
+
248
+ @value_names << name
249
+ @array_members << name if type.is_a?(Array)
250
+
251
+ if not omit
252
+ @def_order << name
253
+ @inc_values << name
254
+ end
255
+
190
256
  define_accessor(name, type)
191
257
  end
192
-
258
+
193
259
  # @return [Array<Symbol>] Array of the names of this node class's values
194
260
  def value_names
195
261
  @value_names
196
262
  end
197
-
198
- # @return [Array<Symbol>] Array of the types of this node class's values
199
- def value_types
200
- @value_types
201
- end
202
263
  end
203
-
264
+
204
265
  ####################
205
266
  # Instance Methods #
206
267
  ####################
207
-
268
+
208
269
  # Used for AST comparison, this function will return true if the two
209
270
  # nodes are of the same class and all of their values and children
210
271
  # are equal.
@@ -215,41 +276,42 @@ module RLTK
215
276
  def ==(other)
216
277
  self.class == other.class and self.values == other.values and self.children == other.children
217
278
  end
218
-
279
+
219
280
  # @return [Object] Note with the name *key*
220
281
  def [](key)
221
282
  @notes[key]
222
283
  end
223
-
284
+
224
285
  # Sets the note named *key* to *value*.
225
286
  def []=(key, value)
226
287
  @notes[key] = value
227
288
  end
228
-
289
+
229
290
  # This method allows ASTNodes to be destructured for pattern matching.
230
- def call(arity)
231
- if arity == self.values.length
232
- self.values
233
- else
234
- [*self.values, *self.children]
235
- end
291
+ def destructure(arity)
292
+ case self.class.member_order
293
+ when :values then (self.class.inc_values + self.class.inc_children)
294
+ when :children then (self.class.inc_children + self.class.inc_values)
295
+ when :def then self.class.def_order
296
+ when Array then self.class.member_order
297
+ end.map { |m| self.send m }
236
298
  end
237
-
299
+
238
300
  # @param [Class] as The type that should be returned by the method. Must be either Array or hash.
239
301
  #
240
302
  # @return [Array<ASTNode>, Hash{Symbol => ASTNode}] Array or Hash of this node's children.
241
303
  def children(as = Array)
242
304
  if as == Array
243
305
  self.class.child_names.map { |name| self.send(name) }
244
-
306
+
245
307
  elsif as == Hash
246
308
  self.class.child_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
247
-
309
+
248
310
  else
249
311
  raise 'Children can only be returned as an Array or a Hash.'
250
312
  end
251
313
  end
252
-
314
+
253
315
  # Assigns an array or hash of AST nodes as the children of this node.
254
316
  # If a hash is provided as an argument the key is used as the name of
255
317
  # the child a object should be assigned to.
@@ -263,11 +325,11 @@ module RLTK
263
325
  if children.length != self.class.child_names.length
264
326
  raise 'Wrong number of children specified.'
265
327
  end
266
-
328
+
267
329
  self.class.child_names.each_with_index do |name, i|
268
330
  self.send((name.to_s + '=').to_sym, children[i])
269
331
  end
270
-
332
+
271
333
  when Hash
272
334
  children.each do |name, val|
273
335
  if self.class.child_names.include?(name)
@@ -278,14 +340,14 @@ module RLTK
278
340
  end
279
341
  end
280
342
  end
281
-
343
+
282
344
  # Produce an exact copy of this tree.
283
345
  #
284
346
  # @return [ASTNode] A copy of the tree.
285
347
  def copy
286
348
  self.map { |c| c }
287
349
  end
288
-
350
+
289
351
  # Removes the note *key* from this node. If the *recursive* argument
290
352
  # is true it will also remove the note from the node's children.
291
353
  #
@@ -295,7 +357,7 @@ module RLTK
295
357
  if recursive
296
358
  self.children.each do |child|
297
359
  next if not child
298
-
360
+
299
361
  if child.is_a?(Array)
300
362
  child.each { |c| c.delete_note(key, true) }
301
363
  else
@@ -303,10 +365,10 @@ module RLTK
303
365
  end
304
366
  end
305
367
  end
306
-
368
+
307
369
  @notes.delete(key)
308
370
  end
309
-
371
+
310
372
  # This method is a simple wrapper around Marshal.dump, and is used
311
373
  # to serialize an AST. You can use Marshal.load to reconstruct a
312
374
  # serialized AST.
@@ -324,7 +386,7 @@ module RLTK
324
386
  else raise TypeError, "AST#dump expects nil, a String, or an IO object for the dest parameter."
325
387
  end
326
388
  end
327
-
389
+
328
390
  # An iterator over the node's children. The AST may be traversed in
329
391
  # the following orders:
330
392
  #
@@ -339,31 +401,31 @@ module RLTK
339
401
  case order
340
402
  when :pre
341
403
  yield self
342
-
404
+
343
405
  self.children.flatten.compact.each { |c| c.each(:pre, &block) }
344
-
406
+
345
407
  when :post
346
408
  self.children.flatten.compact.each { |c| c.each(:post, &block) }
347
-
409
+
348
410
  yield self
349
-
411
+
350
412
  when :level
351
413
  level_queue = [self]
352
-
414
+
353
415
  while node = level_queue.shift
354
416
  yield node
355
-
417
+
356
418
  level_queue += node.children.flatten.compact
357
419
  end
358
420
  end
359
421
  end
360
-
422
+
361
423
  # Tests to see if a note named *key* is present at this node.
362
424
  def has_note?(key)
363
425
  @notes.has_key?(key)
364
426
  end
365
427
  alias :'note?' :'has_note?'
366
-
428
+
367
429
  # Instantiates a new ASTNode object. The arguments to this method are
368
430
  # split into two lists: the set of values for this node and a list of
369
431
  # its children. If the node has 2 values and 3 children you would
@@ -383,22 +445,27 @@ module RLTK
383
445
  def initialize(*objects, &block)
384
446
  @notes = Hash.new()
385
447
  @parent = nil
386
-
387
- # Pad out the objects array with nil values and empty
388
- # arrays.
389
- all_types = self.class.value_types + self.class.child_types
390
- remaining_types = all_types[objects.length..-1]
391
-
392
- objects += remaining_types.map { |type| type.is_a?(Array) ? [] : nil }
393
-
394
- pivot = self.class.value_names.length
395
-
396
- self.values = objects[0...pivot]
397
- self.children = objects[pivot..-1]
398
-
448
+
449
+ pairs =
450
+ case self.class.member_order
451
+ when :values then (self.class.inc_values + self.class.inc_children)
452
+ when :children then (self.class.inc_children + self.class.inc_values)
453
+ when :def then self.class.def_order
454
+ when Array then self.class.member_order
455
+ end.zip(objects).first(objects.length)
456
+
457
+ pairs.each do |name, value|
458
+ self.send("#{name}=", value)
459
+ end
460
+
461
+ self.class.array_members.each do |member|
462
+ ivar_name = '@' + member.to_s
463
+ self.instance_variable_set(ivar_name, []) if self.instance_variable_get(ivar_name).nil?
464
+ end
465
+
399
466
  self.instance_exec(&block) if not block.nil?
400
467
  end
401
-
468
+
402
469
  # Create a new tree by using the provided Proc object to map the
403
470
  # nodes of this tree to new nodes. This is always done in
404
471
  # post-order, meaning that all children of a node are visited before
@@ -409,7 +476,7 @@ module RLTK
409
476
  # @return [Object] Result of calling the given block on the root node
410
477
  def map(&block)
411
478
  new_values = self.values.map { |v| v.clone }
412
-
479
+
413
480
  new_children =
414
481
  self.children.map do |c0|
415
482
  case c0
@@ -418,13 +485,13 @@ module RLTK
418
485
  when NilClass then nil
419
486
  end
420
487
  end
421
-
488
+
422
489
  new_node = self.class.new(*new_values, *new_children)
423
490
  new_node.notes = self.notes
424
-
491
+
425
492
  block.call(new_node)
426
493
  end
427
-
494
+
428
495
  # Map the nodes in an AST to new nodes using the provided Proc
429
496
  # object. This is always done in post-order, meaning that all
430
497
  # children of a node are visited before the node itself.
@@ -443,10 +510,10 @@ module RLTK
443
510
  when NilClass then nil
444
511
  end
445
512
  end
446
-
513
+
447
514
  block.call(self)
448
515
  end
449
-
516
+
450
517
  # Set the notes for this node from a given hash.
451
518
  #
452
519
  # @param [Hash] new_notes The new notes for this node.
@@ -455,27 +522,27 @@ module RLTK
455
522
  def notes=(new_notes)
456
523
  @notes = new_notes.clone
457
524
  end
458
-
525
+
459
526
  # @return [ASTNode] Root of the abstract syntax tree.
460
527
  def root
461
528
  if @parent then @parent.root else self end
462
529
  end
463
-
530
+
464
531
  # @param [Class] as The type that should be returned by the method. Must be either Array or hash.
465
532
  #
466
533
  # @return [Array<Object>, Hash{Symbol => Object}] Array or Hash of this node's values.
467
534
  def values(as = Array)
468
535
  if as == Array
469
536
  self.class.value_names.map { |name| self.send(name) }
470
-
537
+
471
538
  elsif as == Hash
472
539
  self.class.value_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
473
-
540
+
474
541
  else
475
542
  raise 'Values can only be returned as an Array or a Hash.'
476
543
  end
477
544
  end
478
-
545
+
479
546
  # Assigns an array or hash of objects as the values of this node. If
480
547
  # a hash is provided as an argument the key is used as the name of
481
548
  # the value an object should be assigned to.
@@ -487,11 +554,11 @@ module RLTK
487
554
  if values.length != self.class.value_names.length
488
555
  raise 'Wrong number of values specified.'
489
556
  end
490
-
557
+
491
558
  self.class.value_names.each_with_index do |name, i|
492
559
  self.send((name.to_s + '=').to_sym, values[i])
493
560
  end
494
-
561
+
495
562
  when Hash
496
563
  values.each do |name, val|
497
564
  if self.class.value_names.include?(name)