rltk 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -358,9 +358,9 @@ Here we can see the definition of several AST node classes that might be used to
358
358
  child :right, Expression
359
359
  end
360
360
 
361
- The assignment functions that are generated for the children and values perform type checking to make sure that the AST is well-formed. The type of a child must be a subclass of the {RLTK::ASTNode} class, whereas the type of a value must NOT be a subclass of the {RLTK::ASTNode} class. While child and value objects are stored as instance variables it is unsafe to assign to these variables directly, and it is strongly recommended to always use the accessor functions.
361
+ The assignment functions that are generated for the children and values perform type checking to make sure that the AST is well-formed. The type of a child must be a subclass of the {RLTK::ASTNode} class, whereas the type of a value must **NOT** be a subclass of the {RLTK::ASTNode} class. While child and value objects are stored as instance variables it is unsafe to assign to these variables directly, and it is strongly recommended to always use the accessor functions.
362
362
 
363
- When instantiating a subclass of {RLTK::ASTNode} the arguments to the constructor should be the node's values (in order of definition) followed by the node's children (in order of definition). Example:
363
+ When instantiating a subclass of {RLTK::ASTNode} the arguments to the constructor should be the node's values (in order of definition) followed by the node's children (in order of definition). If a constructor is given fewer arguments then the number of values and children the remaining arguments are assumed to be `nil`. Example:
364
364
 
365
365
  class Foo < RLTK::ASTNode
366
366
  value :a, Fixnum
@@ -369,9 +369,11 @@ When instantiating a subclass of {RLTK::ASTNode} the arguments to the constructo
369
369
  child :d, Bar
370
370
  end
371
371
 
372
- Foo.new(1, 'baz', nil, nil)
373
-
374
- You may notice that in the above example the children were set to **nil** instead of an instance of the Bar class. This allows you to specify optional children.
372
+ class Bar < RLTK::ASTNode
373
+ value :a, String
374
+ end
375
+
376
+ Foo.new(1, 'baz', Bar.new)
375
377
 
376
378
  Lastly, the type of a child or value can be defined as an array of objects of a specific type as follows:
377
379
 
@@ -379,11 +381,30 @@ Lastly, the type of a child or value can be defined as an array of objects of a
379
381
  value :strings, [String]
380
382
  end
381
383
 
384
+ ### Tree Iteration and Mapping
385
+
386
+ RLTK Abstract Syntax Trees may be [traversed](http://en.wikipedia.org/wiki/Tree_traversal) in three different ways:
387
+
388
+ * Pre-order
389
+ * Post-order
390
+ * Level-order
391
+
392
+ The order you wish to traverse the tree can be specified by passing the appropriate symbol to {RLTK::ASTNode#each}: `:pre`, `:post`, or `:level`.
393
+
394
+ You can also map one tree to another tree using the {RLTK::ASTNode#map} and {RLTK::ASTNode#map!} methods. In the former case a new tree is created and returned; in the latter case the current tree is transformed and the result of calling the provided block on the root node is returned. These methods will always visit nodes in *post-order*, so that all children of a node are visited before the node itself.
395
+
382
396
  ## Code Generation
383
397
 
384
398
  RLTK supports the generation of native code and LLVM IR, as well as JIT compilation and execution, through the {RLTK::CG} module. This module is built on top of bindings to [LLVM](http://llvm.org) and provides much, though not all, of the functionality of the LLVM libraries.
385
399
 
386
- A very small amount of the functionality of the RLTK::CG module (currently only the {RLTK::CG::Support.load_library} method) requires the [LLVM Extended C Bindings](https://github.com/chriswailes/llvm-ecb) library. If this library is missing the rest of the module should behave properly, but this functionality will be missing.
400
+ A small amount of the functionality of the RLTK::CG module requires the [LLVM Extended C Bindings](https://github.com/chriswailes/llvm-ecb) library. If this library is missing the rest of the module should behave properly, but this functionality will be missing. The features that require this library are:
401
+
402
+ * **Shared Library Loading** - Load shared libraries into the process so that their exported symbols are visible to LLVM via the {RLTK::CG::Support.load\_library} method.
403
+ * **ASM Printer and Parser Initialization** - Available through the {RLTK::CG::LLVM.init\_asm\_parser} and {RLTK::CG::LLVM.init\_asm\_printer} methods.
404
+ * **LLVM IR Loading** - LLVM IR files can be loaded into RLTK via the {RLTK::CG::Module.read\_ir\_file} method.
405
+ * **Value Printing** - Print any value's LLVM IR to a given file descriptor using {RLTK::CG::Value#print}.
406
+ * **Targets, Target Data, and Target Machines** - Manipulate LLVM structures that contain data about the target environment.
407
+ * **Object File Generation** - LLVM Modules can be compiled to object files via the {RLTK::CG::Module#compile} method.
387
408
 
388
409
  ### Acknowledgments and Discussion
389
410
 
@@ -392,9 +413,9 @@ Before we get started with the details, I would like to thank [Jeremy Voorhis](h
392
413
  Why did I fork ruby-llvm, and why might you want to use the RLTK bindings over ruby-llvm? There are a couple of reasons:
393
414
 
394
415
  * **Cleaner Codebase** - The RLTK bindings present a cleaner interface to the LLVM library by conforming to more standard Ruby programming practices, providing better abstractions and cleaner inheritance hierarchies, overloading constructors and other methods properly, and performing type checking on objects to better aid in debugging.
395
- * **Documentation** - RLTK's bindings provide slightly better documentation.
396
- * **Completeness** - The RLTK bindings provide several features that are missing from the ruby-llvm project. These include the ability to initialize LLVM for architectures besides x86 (RLTK supports all architectures supported by LLVM), the presence of all of LLVM's optimization passes, and the ability to print the LLVM IR representation of modules and values to files.
397
- * **Ease of Use** - Several features have been added to make generating code easier.
416
+ * **Documentation** - RLTK's bindings provide better documentation.
417
+ * **Completeness** - The RLTK bindings provide several features that are missing from the ruby-llvm project. These include the ability to initialize LLVM for architectures besides x86 (RLTK supports all architectures supported by LLVM), the presence of all of LLVM's optimization passes, the ability to print the LLVM IR representation of modules and values to files and load modules *from* files, easy initialization of native architectures, initialization for ASM printers and parsers, and compiling modules to object files.
418
+ * **Ease of Use** - Several features have been added to make generating code easier such as automatic management of memory resources used by LLVM.
398
419
  * **Speed** - The RLTK bindings are ever so slightly faster due to avoiding unnecessary FFI calls.
399
420
 
400
421
  Before you dive into generating code, here are some resources you might want to look over to build up some background knowledge on how LLVM works:
@@ -487,7 +508,7 @@ Now that you have a basic block you need to add instructions to it. This is acc
487
508
 
488
509
  To add instructions using a builder directly (this is most similar to how it is done using C/C++) you create the builder, position it where you want to add instructions, and then build them:
489
510
 
490
- fun = mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
511
+ fun = mod.functions.add('add', RLTK::CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
491
512
  bb = fun.blocks.append('entry')
492
513
 
493
514
  builder = RLTK::CG::Builder.new
@@ -502,35 +523,35 @@ To add instructions using a builder directly (this is most similar to how it is
502
523
 
503
524
  You can get rid of some of those references to the builder by using the {RLTK::CG::Builder#build} method:
504
525
 
505
- fun = mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
526
+ fun = mod.functions.add('add', RLTK::CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
506
527
  bb = fun.blocks.append('entry')
507
528
 
508
529
  builder = RLTK::CG::Builder.new
509
530
 
510
- builder.build(fun) do |fun|
531
+ builder.build(bb) do
511
532
  ret add(fun.params[0], fun.params[1])
512
533
  end
513
534
 
514
535
  To get rid of more code:
515
536
 
516
- fun = mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
537
+ fun = mod.functions.add('add', RLTK::CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
517
538
  bb = fun.blocks.append('entry')
518
539
 
519
- RLTK::CG::Builder.new do
540
+ RLTK::CG::Builder.new(bb) do
520
541
  ret add(fun.params[0], fun.params[1])
521
542
  end
522
543
 
523
544
  Or:
524
545
 
525
- fun = mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
526
- fun.blocks.append('entry') do |fun|
546
+ fun = mod.functions.add('add', RLTK::CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
547
+ fun.blocks.append('entry') do
527
548
  ret add(fun.params[0], fun.params[1])
528
549
  end
529
550
 
530
551
  Or even:
531
552
 
532
- mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType]) do
533
- blocks.append('entry', nil, nil, self) do |fun|
553
+ mod.functions.add('add', RLTK::CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType]) do
554
+ blocks.append('entry') do |fun|
534
555
  ret add(fun.params[0], fun.params[1])
535
556
  end
536
557
  end
@@ -539,9 +560,10 @@ In the last two examples a new builder object is created for the block. It is p
539
560
 
540
561
  builder = RLTK::CG::Builder.new
541
562
 
542
- fun = mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType])
543
- fun.blocks.append('entry', nil, builder) do
544
- ret add(fun.params[0], fun.params[1])
563
+ mod.functions.add('add', RLTK:CG::NativeIntType, [RLTK::CG::NativeIntType, RLTK::CG::NativeIntType]) do
564
+ blocks.append('entry', builder) do |fun|
565
+ ret add(fun.params[0], fun.params[1])
566
+ end
545
567
  end
546
568
 
547
569
  For an example of where this is useful, see the Kazoo tutorial.
@@ -333,6 +333,9 @@ module RLTK # :nodoc:
333
333
  # were declared) and then the children as the remaining arguments (in
334
334
  # the order they were declared).
335
335
  #
336
+ # If a node has 2 values and 2 children and is passed only a single
337
+ # value the remaining values and children are assumed to be nil.
338
+ #
336
339
  # @param [Array<Object>] objects The values and children of this node.
337
340
  def initialize(*objects)
338
341
  if self.class == RLTK::ASTNode
@@ -352,11 +355,34 @@ module RLTK # :nodoc:
352
355
  end
353
356
  end
354
357
 
355
- # Maps the children of the ASTNode from one value to another.
358
+ # Create a new tree by using the provided Proc object to map the
359
+ # nodes of this tree to new nodes. This is always done in
360
+ # post-order, meaning that all children of a node are visited before
361
+ # the node itself.
356
362
  #
357
- # @return [void]
358
- def map
359
- self.children = self.children.map { |c| yield c }
363
+ # @note This does not modify the current tree.
364
+ #
365
+ # @return [Object] The result of calling the given block on the root node.
366
+ def map(&block)
367
+ new_children = self.children.map { |c| if c.nil? then block.call(c) else c.map(&block) end }
368
+ new_node = self.class.new(*self.values, *new_children)
369
+
370
+ block.call(new_node)
371
+ end
372
+
373
+ # Map the nodes in an AST to new nodes using the provided Proc
374
+ # object. This is always done in post-order, meaning that all
375
+ # children of a node are visited before the node itself.
376
+ #
377
+ # @note The root node can not be replaced and as such the result of
378
+ # calling the provided block on the root node is used as the
379
+ # return value.
380
+ #
381
+ # @return [Object] The result of calling the given block on the root node.
382
+ def map!(&block)
383
+ self.children = self.children.map { |c| if c.nil? then block.call(c) else c.map!(&block) end }
384
+
385
+ block.call(self)
360
386
  end
361
387
 
362
388
  # @return [ASTNode] Root of the abstract syntax tree.
@@ -35,11 +35,11 @@ module RLTK::CG # :nodoc:
35
35
  # @param [FFI::Pointer, Function, BasicBlock] overloaded Overloaded paramater that determines creation behaviour.
36
36
  #
37
37
  # @param [String] name Name of this BasicBlock.
38
- # @param [Context, nil] context Context in which to create the block.
39
38
  # @param [Builder, nil] builder Builder to be used by {#build}.
39
+ # @param [Context, nil] context Context in which to create the block.
40
40
  # @param [Array<Object>] block_args Arguments to be passed when block is invoked.
41
41
  # @param [Proc] block Block to be invoked by {#build}.
42
- def initialize(overloaded, name = '', context = nil, builder = nil, *block_args, &block)
42
+ def initialize(overloaded, name = '', builder = nil, context = nil, *block_args, &block)
43
43
  check_type(context, Context, 'context') if context
44
44
 
45
45
  @ptr =
@@ -83,17 +83,7 @@ module RLTK::CG # :nodoc:
83
83
  #
84
84
  # @return [Object] Value the block evaluates to. Usually an {Instruction}
85
85
  def build(builder = nil, *block_args, &block)
86
- if builder
87
- builder.build(self, *block_args, &block)
88
-
89
- else
90
- builder = Builder.new
91
- last_inst = builder.build(self, *block_args, &block)
92
-
93
- builder.dispose
94
-
95
- last_inst
96
- end
86
+ if builder then builder else Builder.new end.build(self, *block_args, &block)
97
87
  end
98
88
 
99
89
  # Creates a new BasicBlock inserted immediately before this block.
@@ -21,29 +21,29 @@ module RLTK::CG # :nodoc:
21
21
  class Builder
22
22
  include BindingClass
23
23
 
24
+ # The Proc object called by the garbage collector to free resources used by LLVM.
25
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_builder(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
26
+
24
27
  # @return [Builder] A global Builder object.
25
28
  def self.global
26
29
  @@global_builder ||= Builder.new
27
30
  end
28
31
 
29
32
  # Creates a new Builder object, optionally positioning it at the end
30
- # of *block*.
33
+ # of *block*. If a block is given it will be executed as if it was
34
+ # passed to the #build method.
31
35
  #
32
- # @param [BasicBlock, nil] block BasicBlock used to position the Builder.
33
- def initialize(block = nil)
36
+ # @param [BasicBlock, nil] bb BasicBlock used to position the Builder.
37
+ # @param [Array<Object>] block_args Arguments to be passed to *block*.
38
+ # @param [Proc, nil] block Block to execute in the context of this Builder.
39
+ def initialize(bb = nil, *block_args, &block)
34
40
  @ptr = Bindings.create_builder
35
41
 
36
- position_at_end(block) if block
37
- end
38
-
39
- # Frees the resources used by LLVM for this Builder.
40
- #
41
- # @return [void]
42
- def dispose
43
- if @ptr
44
- Bindings.dispose_builder(@ptr)
45
- @ptr = nil
46
- end
42
+ # Define a finalizer to free the memory used by LLVM for this
43
+ # builder.
44
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
45
+
46
+ if block then self.build(bb, *block_args, &block) elsif bb then position_at_end(bb) end
47
47
  end
48
48
 
49
49
  # Executes a given block inside the context of this builder. If the
@@ -73,22 +73,22 @@ module RLTK::CG # :nodoc:
73
73
 
74
74
  # Position the Builder after the given instruction.
75
75
  #
76
- # @param [BasicBlock] block
76
+ # @param [BasicBlock] bb
77
77
  # @param [Instruction] instruction
78
78
  #
79
79
  # @return [Builder] self
80
- def position(block, instruction)
81
- Bindings.position_builder(@ptr, block, instruction)
80
+ def position(bb, instruction)
81
+ Bindings.position_builder(@ptr, bb, instruction) if check_type(bb, BasicBlock, 'bb')
82
82
  self
83
83
  end
84
84
 
85
85
  # Position the Builder at the end of the given BasicBlock.
86
86
  #
87
- # @param [BasicBlock] block
87
+ # @param [BasicBlock] bb
88
88
  #
89
89
  # @return [Bulder] self
90
- def position_at_end(block)
91
- Bindings.position_builder_at_end(@ptr, block)
90
+ def position_at_end(bb)
91
+ Bindings.position_builder_at_end(@ptr, bb) if check_type(bb, BasicBlock, 'bb')
92
92
  self
93
93
  end
94
94
 
@@ -20,6 +20,9 @@ module RLTK::CG # :nodoc:
20
20
  class Context
21
21
  include BindingClass
22
22
 
23
+ # The Proc object called by the garbage collector to free resources used by LLVM.
24
+ CLASS_FINALIZER = Proc.new { |id| Bindings.context_dispose(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
25
+
23
26
  #################
24
27
  # Class Methods #
25
28
  #################
@@ -36,16 +39,10 @@ module RLTK::CG # :nodoc:
36
39
  # @param [FFI::Pointer, nil] ptr Pointer representing a context. If nil, a new context is created.
37
40
  def initialize(ptr = nil)
38
41
  @ptr = ptr || Bindings.context_create()
39
- end
40
-
41
- # Frees the resources used by LLVM for this context.
42
- #
43
- # @return [void]
44
- def dispose
45
- if @ptr
46
- Bindings.context_dispose(@ptr)
47
- @ptr = nil
48
- end
42
+
43
+ # Define a finalizer to free the memory used by LLVM for this
44
+ # context.
45
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
49
46
  end
50
47
  end
51
48
  end
@@ -29,6 +29,9 @@ module RLTK::CG # :nodoc:
29
29
  include AbstractClass
30
30
  include BindingClass
31
31
 
32
+ # The Proc object called by the garbage collector to free resources used by LLVM.
33
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_execution_engine(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
34
+
32
35
  # @return [Module]
33
36
  attr_reader :module
34
37
 
@@ -53,7 +56,10 @@ module RLTK::CG # :nodoc:
53
56
 
54
57
  # Associate this engine with the provided module.
55
58
  @module.engine = self
56
-
59
+
60
+ # Define a finalizer to free the memory used by LLVM for
61
+ # this execution engine.
62
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
57
63
  else
58
64
  errorp = error.read_pointer
59
65
  message = errorp.null? ? 'Unknown' : errorp.read_string
@@ -66,17 +72,6 @@ module RLTK::CG # :nodoc:
66
72
  end
67
73
  end
68
74
 
69
- # Frees the resources used by LLVM for this execution engine..
70
- #
71
- # @return [void]
72
- def dispose
73
- if @ptr
74
- Bindings.dispose_execution_engine(@ptr)
75
-
76
- @ptr = nil
77
- end
78
- end
79
-
80
75
  # Builds a pointer to a global value.
81
76
  #
82
77
  # @param [GlobalValue] global Value you want a pointer to.
@@ -95,24 +90,15 @@ module RLTK::CG # :nodoc:
95
90
  #
96
91
  # @return [GenericValue]
97
92
  def run_function(fun, *args)
98
- new_values = Array.new
99
-
100
93
  new_args =
101
94
  fun.params.zip(args).map do |param, arg|
102
- if arg.is_a?(GenericValue)
103
- arg
104
-
105
- else
106
- returning(GenericValue.new(arg)) { |val| new_values << val }
107
- end
95
+ if arg.is_a?(GenericValue) then arg else GenericValue.new(arg) end
108
96
  end
109
97
 
110
98
  args_ptr = FFI::MemoryPointer.new(:pointer, args.length)
111
99
  args_ptr.write_array_of_pointer(new_args)
112
100
 
113
- returning(GenericValue.new(Bindings.run_function(@ptr, fun, args.length, args_ptr))) do
114
- new_values.each { |val| val.dispose }
115
- end
101
+ GenericValue.new(Bindings.run_function(@ptr, fun, args.length, args_ptr))
116
102
  end
117
103
  alias :run :run_function
118
104
 
@@ -120,15 +120,18 @@ module RLTK::CG # :nodoc:
120
120
 
121
121
  # Add a {BasicBlock} to the end of this function.
122
122
  #
123
+ # @note The first argument to any proc passed to this function
124
+ # will be the function the block is being appended to.
125
+ #
123
126
  # @param [String] name Name of the block in LLVM IR.
124
- # @param [Context, nil] context Context in which to create the block.
125
127
  # @param [Builder, nil] builder Builder to be used in evaluating *block*.
126
- # @param [Array<Object>] block_args Arguments to be passed to *block*.
128
+ # @param [Context, nil] context Context in which to create the block.
129
+ # @param [Array<Object>] block_args Arguments to be passed to *block*. The function the block is appended to is automatically added to the front of this list.
127
130
  # @param [Proc] block Block to be evaluated using *builder* after positioning it at the end of the new block.
128
131
  #
129
132
  # @return [BasicBlock] New BasicBlock.
130
- def append(name = '', context = nil, builder = nil, *block_args, &block)
131
- BasicBlock.new(@fun, name, context, builder, *block_args, &block)
133
+ def append(name = '', builder = nil, context = nil, *block_args, &block)
134
+ BasicBlock.new(@fun, name, builder, context, @fun, *block_args, &block)
132
135
  end
133
136
 
134
137
  # An iterator for each block inside this collection.
@@ -27,6 +27,9 @@ module RLTK::CG # :nodoc:
27
27
  class GenericValue
28
28
  include BindingClass
29
29
 
30
+ # The Proc object called by the garbage collector to free resources used by LLVM.
31
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_generic_value(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
32
+
30
33
  # @return [Type] LLVM type of this GenericValue.
31
34
  attr_reader :type
32
35
 
@@ -57,16 +60,10 @@ module RLTK::CG # :nodoc:
57
60
  when FalseClass
58
61
  [Bindings.create_generic_value_of_int(Int1Type, 0, 0), Int1Type]
59
62
  end
60
- end
61
-
62
- # Frees the resources used by LLVM for this value.
63
- #
64
- # @return [void]
65
- def dispose
66
- if @ptr
67
- Bindings.dispose_generic_value(@ptr)
68
- @ptr = nil
69
- end
63
+
64
+ # Define a finalizer to free the memory used by LLVM for this
65
+ # generic value.
66
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
70
67
  end
71
68
 
72
69
  # @param [Boolean] signed Treat the GenericValue as a signed integer.
@@ -20,6 +20,9 @@ module RLTK::CG # :nodoc:
20
20
  class MemoryBuffer
21
21
  include BindingClass
22
22
 
23
+ # The Proc object called by the garbage collector to free resources used by LLVM.
24
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_memory_buffer(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
25
+
23
26
  # Create a new memory buffer.
24
27
  #
25
28
  # @param [FFI::Pointer, String, nil] overloaded This parameter may be either a pointer to an existing memory
@@ -46,17 +49,10 @@ module RLTK::CG # :nodoc:
46
49
 
47
50
  buf_ptr.get_pointer(0)
48
51
  end
49
- end
50
-
51
- # Frees the resources used by LLVM for this memory buffer.
52
- #
53
- # @return [void]
54
- def dispose
55
- if @ptr
56
- Bindings.dispose_memory_buffer(@ptr)
57
-
58
- @ptr = nil
59
- end
52
+
53
+ # Define a finalizer to free the memory used by LLVM for this
54
+ # memory buffer.
55
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
60
56
  end
61
57
  end
62
58
  end
@@ -22,6 +22,9 @@ module RLTK::CG # :nodoc:
22
22
  class Module
23
23
  include BindingClass
24
24
 
25
+ # The Proc object called by the garbage collector to free resources used by LLVM.
26
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_module(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
27
+
25
28
  # @!attribute [rw] engine
26
29
  # @return [ExecutionEngine, nil] Execution engine associated with this module.
27
30
  attr_accessor :engine
@@ -76,6 +79,10 @@ module RLTK::CG # :nodoc:
76
79
  end
77
80
  end
78
81
 
82
+ # Define a finalizer to free the memory used by LLVM for this
83
+ # module.
84
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
85
+
79
86
  self.instance_exec(&block) if block
80
87
  end
81
88
 
@@ -97,17 +104,6 @@ module RLTK::CG # :nodoc:
97
104
  Context.new(Bindings.get_module_context(@ptr))
98
105
  end
99
106
 
100
- # Frees the resources used by LLVM for this module.
101
- #
102
- # @return [void]
103
- def dispose
104
- if @ptr
105
- Bindings.dispose_module(@ptr)
106
-
107
- @ptr = nil
108
- end
109
- end
110
-
111
107
  # Print the LLVM IR representation of this value to standard error.
112
108
  # This function is the debugging version of the more general purpose
113
109
  # {#print} method.
@@ -21,6 +21,9 @@ module RLTK::CG # :nodoc:
21
21
  class PassManager
22
22
  include BindingClass
23
23
 
24
+ # The Proc object called by the garbage collector to free resources used by LLVM.
25
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_pass_manager(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
26
+
24
27
  # A list of passes that are available to be added to the pass
25
28
  # manager via the {PassManager#add} method.
26
29
  PASSES = {
@@ -85,19 +88,10 @@ module RLTK::CG # :nodoc:
85
88
 
86
89
  # RLTK Initialization
87
90
  @enabled = Array.new
88
- end
89
-
90
- # Frees the resources used by LLVM for this pass manager.
91
- #
92
- # @return [void]
93
- def dispose
94
- if @ptr
95
- self.finalize
96
-
97
- Bindings.dispose_pass_manager(@ptr)
98
-
99
- @ptr = nil
100
- end
91
+
92
+ # Define a finalizer to free the memory used by LLVM for this
93
+ # pass manager.
94
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
101
95
  end
102
96
 
103
97
  # Add a pass or passes to this pass manager. Passes may either be
@@ -5,7 +5,7 @@
5
5
 
6
6
  module RLTK # :nodoc:
7
7
  # The version number of the RLTK library.
8
- VERSION = '2.1.1'
8
+ VERSION = '2.2.0'
9
9
  # The version of LLVM targeted by RLTK.
10
10
  LLVM_TARGET_VERSION = '3.0'
11
11
  end
@@ -42,8 +42,9 @@ class ASTNodeTester < Test::Unit::TestCase
42
42
 
43
43
  @tree1 = ANode.new(BNode.new(CNode.new), BNode.new)
44
44
  @tree2 = ANode.new(BNode.new, BNode.new(CNode.new))
45
+ @tree3 = ANode.new(CNode.new(BNode.new), CNode.new)
45
46
 
46
- @tree3 = SNode.new('F',
47
+ @tree4 = SNode.new('F',
47
48
  SNode.new('B',
48
49
  SNode.new('A'),
49
50
  SNode.new('D',
@@ -58,6 +59,14 @@ class ASTNodeTester < Test::Unit::TestCase
58
59
  )
59
60
  )
60
61
  )
62
+
63
+ @bc_proc = Proc.new do |n|
64
+ case n
65
+ when BNode then CNode.new(n.left, n.right)
66
+ when CNode then BNode.new(n.left, n.right)
67
+ else n
68
+ end
69
+ end
61
70
  end
62
71
 
63
72
  def test_children
@@ -68,16 +77,6 @@ class ASTNodeTester < Test::Unit::TestCase
68
77
  node.children = (expected_children = [BNode.new, CNode.new])
69
78
 
70
79
  assert_equal(node.children, expected_children)
71
-
72
- node.map do |child|
73
- if child.is_a?(BNode)
74
- CNode.new
75
- else
76
- BNode.new
77
- end
78
- end
79
-
80
- assert_equal(node.children, expected_children.reverse)
81
80
  end
82
81
 
83
82
  def test_dump
@@ -92,21 +91,21 @@ class ASTNodeTester < Test::Unit::TestCase
92
91
  # Test pre-order
93
92
  nodes = []
94
93
  expected = ['F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H']
95
- @tree3.each(:pre) { |n| nodes << n.string }
94
+ @tree4.each(:pre) { |n| nodes << n.string }
96
95
 
97
96
  assert_equal(expected, nodes)
98
97
 
99
98
  # Test post-order
100
99
  nodes = []
101
100
  expected = ['A', 'C', 'E', 'D', 'B', 'H', 'I', 'G', 'F']
102
- @tree3.each(:post) { |n| nodes << n.string }
101
+ @tree4.each(:post) { |n| nodes << n.string }
103
102
 
104
103
  assert_equal(expected, nodes)
105
104
 
106
105
  # Test level-order
107
106
  nodes = []
108
107
  expected = ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H']
109
- @tree3.each(:level) { |n| nodes << n.string }
108
+ @tree4.each(:level) { |n| nodes << n.string }
110
109
 
111
110
  assert_equal(expected, nodes)
112
111
  end
@@ -118,11 +117,31 @@ class ASTNodeTester < Test::Unit::TestCase
118
117
 
119
118
  def test_initialize
120
119
  assert_raise(RuntimeError) { RLTK::ASTNode.new }
121
- assert_nothing_raised(RuntimeError) { ANode.new(nil, nil) }
120
+ assert_nothing_raised(RuntimeError) { ANode.new }
121
+ end
122
+
123
+ def test_map
124
+ mapped_tree = @tree1.map(&@bc_proc)
125
+
126
+ assert_equal(@tree0, @tree1)
127
+ assert_equal(@tree3, mapped_tree)
128
+ end
129
+
130
+ def test_map!
131
+ tree1_clone = @tree1.clone
132
+ tree1_clone.map!(&@bc_proc)
133
+
134
+ assert_not_equal(@tree1, tree1_clone)
135
+ assert_equal(@tree3, tree1_clone)
136
+
137
+ replace_node = BNode.new
138
+ replace_node = replace_node.map!(&@bc_proc)
139
+
140
+ assert_equal(CNode.new, replace_node)
122
141
  end
123
142
 
124
143
  def test_notes
125
- node = ANode.new(nil, nil)
144
+ node = ANode.new
126
145
 
127
146
  assert_nil(node[:a])
128
147
  assert_equal(node[:a] = :b, :b)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rltk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-07 00:00:00.000000000 Z
12
+ date: 2012-08-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi