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 +43 -21
- data/lib/rltk/ast.rb +30 -4
- data/lib/rltk/cg/basic_block.rb +3 -13
- data/lib/rltk/cg/builder.rb +20 -20
- data/lib/rltk/cg/context.rb +7 -10
- data/lib/rltk/cg/execution_engine.rb +9 -23
- data/lib/rltk/cg/function.rb +7 -4
- data/lib/rltk/cg/generic_value.rb +7 -10
- data/lib/rltk/cg/memory_buffer.rb +7 -11
- data/lib/rltk/cg/module.rb +7 -11
- data/lib/rltk/cg/pass_manager.rb +7 -13
- data/lib/rltk/version.rb +1 -1
- data/test/tc_ast.rb +35 -16
- metadata +2 -2
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
|
-
|
373
|
-
|
374
|
-
|
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
|
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
|
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,
|
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
|
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
|
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(
|
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
|
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
|
526
|
-
fun.blocks.append('entry') do
|
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
|
533
|
-
blocks.append('entry'
|
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
|
-
|
543
|
-
|
544
|
-
|
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.
|
data/lib/rltk/ast.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
# @
|
358
|
-
|
359
|
-
|
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.
|
data/lib/rltk/cg/basic_block.rb
CHANGED
@@ -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 = '',
|
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.
|
data/lib/rltk/cg/builder.rb
CHANGED
@@ -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]
|
33
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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]
|
76
|
+
# @param [BasicBlock] bb
|
77
77
|
# @param [Instruction] instruction
|
78
78
|
#
|
79
79
|
# @return [Builder] self
|
80
|
-
def position(
|
81
|
-
Bindings.position_builder(@ptr,
|
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]
|
87
|
+
# @param [BasicBlock] bb
|
88
88
|
#
|
89
89
|
# @return [Bulder] self
|
90
|
-
def position_at_end(
|
91
|
-
Bindings.position_builder_at_end(@ptr,
|
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
|
|
data/lib/rltk/cg/context.rb
CHANGED
@@ -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
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
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
|
|
data/lib/rltk/cg/function.rb
CHANGED
@@ -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 [
|
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 = '',
|
131
|
-
BasicBlock.new(@fun, name, context,
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
data/lib/rltk/cg/module.rb
CHANGED
@@ -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.
|
data/lib/rltk/cg/pass_manager.rb
CHANGED
@@ -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
|
-
|
89
|
-
|
90
|
-
|
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
|
data/lib/rltk/version.rb
CHANGED
data/test/tc_ast.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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
|
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
|
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.
|
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-
|
12
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|