rltk 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)