rltk3 3.0.2

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 (56) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/LICENSE +27 -0
  4. data/README.md +852 -0
  5. data/Rakefile +197 -0
  6. data/lib/rltk/ast.rb +573 -0
  7. data/lib/rltk/cfg.rb +683 -0
  8. data/lib/rltk/cg/basic_block.rb +157 -0
  9. data/lib/rltk/cg/bindings.rb +151 -0
  10. data/lib/rltk/cg/builder.rb +1127 -0
  11. data/lib/rltk/cg/context.rb +48 -0
  12. data/lib/rltk/cg/contractor.rb +51 -0
  13. data/lib/rltk/cg/execution_engine.rb +194 -0
  14. data/lib/rltk/cg/function.rb +237 -0
  15. data/lib/rltk/cg/generated_bindings.rb +8118 -0
  16. data/lib/rltk/cg/generic_value.rb +95 -0
  17. data/lib/rltk/cg/instruction.rb +519 -0
  18. data/lib/rltk/cg/llvm.rb +150 -0
  19. data/lib/rltk/cg/memory_buffer.rb +75 -0
  20. data/lib/rltk/cg/module.rb +451 -0
  21. data/lib/rltk/cg/pass_manager.rb +252 -0
  22. data/lib/rltk/cg/support.rb +29 -0
  23. data/lib/rltk/cg/target.rb +230 -0
  24. data/lib/rltk/cg/triple.rb +58 -0
  25. data/lib/rltk/cg/type.rb +554 -0
  26. data/lib/rltk/cg/value.rb +1272 -0
  27. data/lib/rltk/cg.rb +32 -0
  28. data/lib/rltk/lexer.rb +372 -0
  29. data/lib/rltk/lexers/calculator.rb +44 -0
  30. data/lib/rltk/lexers/ebnf.rb +38 -0
  31. data/lib/rltk/parser.rb +1702 -0
  32. data/lib/rltk/parsers/infix_calc.rb +43 -0
  33. data/lib/rltk/parsers/postfix_calc.rb +34 -0
  34. data/lib/rltk/parsers/prefix_calc.rb +34 -0
  35. data/lib/rltk/token.rb +90 -0
  36. data/lib/rltk/version.rb +11 -0
  37. data/lib/rltk.rb +16 -0
  38. data/test/cg/tc_basic_block.rb +83 -0
  39. data/test/cg/tc_control_flow.rb +191 -0
  40. data/test/cg/tc_function.rb +54 -0
  41. data/test/cg/tc_generic_value.rb +33 -0
  42. data/test/cg/tc_instruction.rb +256 -0
  43. data/test/cg/tc_llvm.rb +25 -0
  44. data/test/cg/tc_math.rb +88 -0
  45. data/test/cg/tc_module.rb +89 -0
  46. data/test/cg/tc_transforms.rb +68 -0
  47. data/test/cg/tc_type.rb +69 -0
  48. data/test/cg/tc_value.rb +151 -0
  49. data/test/cg/ts_cg.rb +23 -0
  50. data/test/tc_ast.rb +332 -0
  51. data/test/tc_cfg.rb +164 -0
  52. data/test/tc_lexer.rb +216 -0
  53. data/test/tc_parser.rb +711 -0
  54. data/test/tc_token.rb +34 -0
  55. data/test/ts_rltk.rb +47 -0
  56. metadata +317 -0
data/lib/rltk/ast.rb ADDED
@@ -0,0 +1,573 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2011/01/19
4
+ # Description: This file provides a base Node class for ASTs.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'filigree/abstract_class'
12
+ require 'filigree/class'
13
+ require 'filigree/match'
14
+ require 'filigree/types'
15
+ require 'filigree/visitor'
16
+
17
+ #######################
18
+ # Classes and Modules #
19
+ #######################
20
+
21
+ module RLTK
22
+ # This class is a good start for all your abstract syntax tree node needs.
23
+ class ASTNode
24
+
25
+ include Filigree::Visitable
26
+
27
+ extend Filigree::AbstractClass
28
+ extend Filigree::Destructurable
29
+
30
+ # @return [ASTNode] Reference to the parent node.
31
+ attr_accessor :parent
32
+
33
+ # @return [Hash] The notes hash for this node.
34
+ attr_reader :notes
35
+
36
+ #################
37
+ # Class Methods #
38
+ #################
39
+
40
+ class << self
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
+
47
+ # Check to make sure a name isn't re-defining a value or child.
48
+ #
49
+ # @raise [ArgumentError] Raised if the name is already used for an existing value or child
50
+ def check_odr(name)
51
+ if @child_names.include? name
52
+ raise ArgumentError, "Class #{self} or one of its superclasses already defines a child named #{name}"
53
+ end
54
+
55
+ if @value_names.include?(name)
56
+ raise ArgumentError, "Class #{self} or one of its superclasses already defines a value named #{name}"
57
+ end
58
+ end
59
+
60
+ # Installs instance class variables into a class.
61
+ #
62
+ # @return [void]
63
+ def install_icvars
64
+ if self.superclass == ASTNode
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
73
+ else
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
82
+ end
83
+ end
84
+ protected :install_icvars
85
+
86
+ # Called when the Lexer class is sub-classed, it installes
87
+ # necessary instance class variables.
88
+ #
89
+ # @param [Class] klass The class is inheriting from this class.
90
+ #
91
+ # @return [void]
92
+ def inherited(klass)
93
+ klass.install_icvars
94
+ end
95
+
96
+ # Defined a child for this AST class and its subclasses.
97
+ # The name of the child will be used to define accessor
98
+ # methods that include type checking. The type of this
99
+ # child must be a subclass of the ASTNode class.
100
+ #
101
+ # @param [String, Symbol] name Name of child node
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
104
+ #
105
+ # @return [void]
106
+ def child(name, type, omit = false)
107
+ check_odr(name)
108
+
109
+ if type.is_a?(Array) and type.length == 1
110
+ t = type.first
111
+
112
+ elsif type.is_a?(Class)
113
+ t = type
114
+
115
+ else
116
+ raise 'Child and Value types must be a class name or an array with a single class name element.'
117
+ end
118
+
119
+ # Check to make sure that type is a subclass of ASTNode.
120
+ if not t < ASTNode
121
+ raise "A child's type specification must be a subclass of ASTNode."
122
+ end
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
+
132
+ define_accessor(name, type, true)
133
+ end
134
+
135
+ # @return [Array<Symbol>] Array of the names of this node class's children
136
+ def child_names
137
+ @child_names
138
+ end
139
+
140
+ # @return [Array<Symbol>] Array of names of values/children in the order they were defined
141
+ def def_order
142
+ @def_order
143
+ end
144
+
145
+ # This method defines a type checking accessor named *name*
146
+ # with type *type*.
147
+ #
148
+ # @param [String, Symbol] name Name of accessor
149
+ # @param [Class] type Class used for type checking
150
+ # @param [Boolean] set_parent Set the parent variable or not
151
+ #
152
+ # @return [void]
153
+ def define_accessor(name, type, set_parent = false)
154
+ ivar_name = ('@' + name.to_s).to_sym
155
+
156
+ define_method(name) do
157
+ self.instance_variable_defined?(ivar_name) ? self.instance_variable_get(ivar_name) : nil
158
+ end
159
+
160
+ if type.is_a?(Class)
161
+ if set_parent
162
+ define_method((name.to_s + '=').to_sym) do |value|
163
+ self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
164
+ value.parent = self if value
165
+ end
166
+
167
+ else
168
+ define_method((name.to_s + '=').to_sym) do |value|
169
+ self.instance_variable_set(ivar_name, check_type(value, type, nil, true))
170
+ end
171
+ end
172
+
173
+ else
174
+ if set_parent
175
+ define_method((name.to_s + '=').to_sym) do |value|
176
+ self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
177
+ value.each { |c| c.parent = self }
178
+ end
179
+
180
+ else
181
+ define_method((name.to_s + '=').to_sym) do |value|
182
+ self.instance_variable_set(ivar_name, check_array_type(value, type.first, nil, true))
183
+ end
184
+ end
185
+ end
186
+ end
187
+ private :define_accessor
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
+
232
+ # Defined a value for this AST class and its subclasses.
233
+ # The name of the value will be used to define accessor
234
+ # methods that include type checking.
235
+ #
236
+ # @param [String, Symbol] name Name of value
237
+ # @param [Class] type Type of value
238
+ # @param [Boolean] omit Include the value in the constructor or not
239
+ #
240
+ # @return [void]
241
+ def value(name, type, omit = false)
242
+ check_odr(name)
243
+
244
+ if not (type.is_a?(Class) or (type.is_a?(Array) and type.length == 1))
245
+ raise 'Child and Value types must be a class name or an array with a single class name element.'
246
+ end
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
+
256
+ define_accessor(name, type)
257
+ end
258
+
259
+ # @return [Array<Symbol>] Array of the names of this node class's values
260
+ def value_names
261
+ @value_names
262
+ end
263
+ end
264
+
265
+ ####################
266
+ # Instance Methods #
267
+ ####################
268
+
269
+ # Used for AST comparison, this function will return true if the two
270
+ # nodes are of the same class and all of their values and children
271
+ # are equal.
272
+ #
273
+ # @param [ASTNode] other The ASTNode to compare to
274
+ #
275
+ # @return [Boolean]
276
+ def ==(other)
277
+ self.class == other.class and self.values == other.values and self.children == other.children
278
+ end
279
+
280
+ # @return [Object] Note with the name *key*
281
+ def [](key)
282
+ @notes[key]
283
+ end
284
+
285
+ # Sets the note named *key* to *value*.
286
+ def []=(key, value)
287
+ @notes[key] = value
288
+ end
289
+
290
+ # This method allows ASTNodes to be destructured for pattern matching.
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 }
298
+ end
299
+
300
+ # @param [Class] as The type that should be returned by the method. Must be either Array or hash.
301
+ #
302
+ # @return [Array<ASTNode>, Hash{Symbol => ASTNode}] Array or Hash of this node's children.
303
+ def children(as = Array)
304
+ if as == Array
305
+ self.class.child_names.map { |name| self.send(name) }
306
+
307
+ elsif as == Hash
308
+ self.class.child_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
309
+
310
+ else
311
+ raise 'Children can only be returned as an Array or a Hash.'
312
+ end
313
+ end
314
+
315
+ # Assigns an array or hash of AST nodes as the children of this node.
316
+ # If a hash is provided as an argument the key is used as the name of
317
+ # the child a object should be assigned to.
318
+ #
319
+ # @param [Array<ASTNode>, Hash{Symbol => ASTNode}] children Children to be assigned to this node.
320
+ #
321
+ # @return [void]
322
+ def children=(children)
323
+ case children
324
+ when Array
325
+ if children.length != self.class.child_names.length
326
+ raise 'Wrong number of children specified.'
327
+ end
328
+
329
+ self.class.child_names.each_with_index do |name, i|
330
+ self.send((name.to_s + '=').to_sym, children[i])
331
+ end
332
+
333
+ when Hash
334
+ children.each do |name, val|
335
+ if self.class.child_names.include?(name)
336
+ self.send((name.to_s + '=').to_sym, val)
337
+ else
338
+ raise "ASTNode subclass #{self.class.name} does not have a child named #{name}."
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ # Produce an exact copy of this tree.
345
+ #
346
+ # @return [ASTNode] A copy of the tree.
347
+ def copy
348
+ self.map { |c| c }
349
+ end
350
+
351
+ # Removes the note *key* from this node. If the *recursive* argument
352
+ # is true it will also remove the note from the node's children.
353
+ #
354
+ # @param [Object] key The key of the note to remove
355
+ # @param [Boolean] recursive Do a recursive removal or not
356
+ def delete_note(key, recursive = true)
357
+ if recursive
358
+ self.children.each do |child|
359
+ next if not child
360
+
361
+ if child.is_a?(Array)
362
+ child.each { |c| c.delete_note(key, true) }
363
+ else
364
+ child.delete_note(key, true)
365
+ end
366
+ end
367
+ end
368
+
369
+ @notes.delete(key)
370
+ end
371
+
372
+ # This method is a simple wrapper around Marshal.dump, and is used
373
+ # to serialize an AST. You can use Marshal.load to reconstruct a
374
+ # serialized AST.
375
+ #
376
+ # @param [nil, IO, String] dest Where the serialized version of the AST will end up. If nil,
377
+ # this method will return the AST as a string.
378
+ # @param [Fixnum] limit Recursion depth. If -1 is specified there is no limit on the recursion depth.
379
+ #
380
+ # @return [void, String] String if *dest* is nil, void otherwise.
381
+ def dump(dest = nil, limit = -1)
382
+ case dest
383
+ when nil then Marshal.dump(self, limit)
384
+ when String then File.open(dest, 'w') { |f| Marshal.dump(self, f, limit) }
385
+ when IO then Marshal.dump(self, dest, limit)
386
+ else raise TypeError, "AST#dump expects nil, a String, or an IO object for the dest parameter."
387
+ end
388
+ end
389
+
390
+ # An iterator over the node's children. The AST may be traversed in
391
+ # the following orders:
392
+ #
393
+ # * Pre-order (:pre)
394
+ # * Post-order (:post)
395
+ # * Level-order (:level)
396
+ #
397
+ # @param [:pre, :post, :level] order The order in which to iterate over the tree
398
+ #
399
+ # @return [void]
400
+ def each(order = :pre, &block)
401
+ case order
402
+ when :pre
403
+ yield self
404
+
405
+ self.children.flatten.compact.each { |c| c.each(:pre, &block) }
406
+
407
+ when :post
408
+ self.children.flatten.compact.each { |c| c.each(:post, &block) }
409
+
410
+ yield self
411
+
412
+ when :level
413
+ level_queue = [self]
414
+
415
+ while node = level_queue.shift
416
+ yield node
417
+
418
+ level_queue += node.children.flatten.compact
419
+ end
420
+ end
421
+ end
422
+
423
+ # Tests to see if a note named *key* is present at this node.
424
+ def has_note?(key)
425
+ @notes.has_key?(key)
426
+ end
427
+ alias :'note?' :'has_note?'
428
+
429
+ # Instantiates a new ASTNode object. The arguments to this method are
430
+ # split into two lists: the set of values for this node and a list of
431
+ # its children. If the node has 2 values and 3 children you would
432
+ # pass the values in as the first two arguments (in the order they
433
+ # were declared) and then the children as the remaining arguments (in
434
+ # the order they were declared).
435
+ #
436
+ # If a node has 2 values and 2 children and is passed only a single
437
+ # value the remaining values and children are assumed to be nil or
438
+ # empty arrays, depending on the declared type of the value or
439
+ # child.
440
+ #
441
+ # If a block is passed to initialize the block will be executed in
442
+ # the conext of the new object.
443
+ #
444
+ # @param [Array<Object>] objects Values and children of this node
445
+ def initialize(*objects, &block)
446
+ @notes = Hash.new()
447
+ @parent = nil
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
+
466
+ self.instance_exec(&block) if not block.nil?
467
+ end
468
+
469
+ # Create a new tree by using the provided Proc object to map the
470
+ # nodes of this tree to new nodes. This is always done in
471
+ # post-order, meaning that all children of a node are visited before
472
+ # the node itself.
473
+ #
474
+ # @note This does not modify the current tree.
475
+ #
476
+ # @return [Object] Result of calling the given block on the root node
477
+ def map(&block)
478
+ new_values = self.values.map { |v| v.clone }
479
+
480
+ new_children =
481
+ self.children.map do |c0|
482
+ case c0
483
+ when Array then c0.map { |c1| c1.map(&block) }
484
+ when ASTNode then c0.map(&block)
485
+ when NilClass then nil
486
+ end
487
+ end
488
+
489
+ new_node = self.class.new(*new_values, *new_children)
490
+ new_node.notes = self.notes
491
+
492
+ block.call(new_node)
493
+ end
494
+
495
+ # Map the nodes in an AST to new nodes using the provided Proc
496
+ # object. This is always done in post-order, meaning that all
497
+ # children of a node are visited before the node itself.
498
+ #
499
+ # @note The root node can not be replaced and as such the result of
500
+ # calling the provided block on the root node is used as the
501
+ # return value.
502
+ #
503
+ # @return [Object] Result of calling the given block on the root node
504
+ def map!(&block)
505
+ self.children =
506
+ self.children.map do |c0|
507
+ case c0
508
+ when Array then c0.map { |c1| c1.map!(&block) }
509
+ when ASTNode then c0.map!(&block)
510
+ when NilClass then nil
511
+ end
512
+ end
513
+
514
+ block.call(self)
515
+ end
516
+
517
+ # Set the notes for this node from a given hash.
518
+ #
519
+ # @param [Hash] new_notes The new notes for this node.
520
+ #
521
+ # @return [void]
522
+ def notes=(new_notes)
523
+ @notes = new_notes.clone
524
+ end
525
+
526
+ # @return [ASTNode] Root of the abstract syntax tree.
527
+ def root
528
+ if @parent then @parent.root else self end
529
+ end
530
+
531
+ # @param [Class] as The type that should be returned by the method. Must be either Array or hash.
532
+ #
533
+ # @return [Array<Object>, Hash{Symbol => Object}] Array or Hash of this node's values.
534
+ def values(as = Array)
535
+ if as == Array
536
+ self.class.value_names.map { |name| self.send(name) }
537
+
538
+ elsif as == Hash
539
+ self.class.value_names.inject(Hash.new) { |h, name| h[name] = self.send(name); h }
540
+
541
+ else
542
+ raise 'Values can only be returned as an Array or a Hash.'
543
+ end
544
+ end
545
+
546
+ # Assigns an array or hash of objects as the values of this node. If
547
+ # a hash is provided as an argument the key is used as the name of
548
+ # the value an object should be assigned to.
549
+ #
550
+ # @param [Array<Object>, Hash{Symbol => Object}] values The values to be assigned to this node.
551
+ def values=(values)
552
+ case values
553
+ when Array
554
+ if values.length != self.class.value_names.length
555
+ raise 'Wrong number of values specified.'
556
+ end
557
+
558
+ self.class.value_names.each_with_index do |name, i|
559
+ self.send((name.to_s + '=').to_sym, values[i])
560
+ end
561
+
562
+ when Hash
563
+ values.each do |name, val|
564
+ if self.class.value_names.include?(name)
565
+ self.send((name.to_s + '=').to_sym, val)
566
+ else
567
+ raise "ASTNode subclass #{self.class.name} does not have a value named #{name}."
568
+ end
569
+ end
570
+ end
571
+ end
572
+ end
573
+ end