rltk3 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
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