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
@@ -0,0 +1,48 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/20
4
+ # Description: This file defines the Context class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+
13
+ #######################
14
+ # Classes and Modules #
15
+ #######################
16
+
17
+ module RLTK::CG
18
+
19
+ # Bindings for LLVM contexts.
20
+ class Context
21
+ include BindingClass
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
+
26
+ #################
27
+ # Class Methods #
28
+ #################
29
+
30
+ # @return [Context] A global context.
31
+ def self.global
32
+ self.new(Bindings.get_global_context())
33
+ end
34
+
35
+ ####################
36
+ # Instance Methods #
37
+ ####################
38
+
39
+ # @param [FFI::Pointer, nil] ptr Pointer representing a context. If nil, a new context is created.
40
+ def initialize(ptr = nil)
41
+ @ptr = ptr || Bindings.context_create()
42
+
43
+ # Define a finalizer to free the memory used by LLVM for this
44
+ # context.
45
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,51 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/09/21
4
+ # Description: This file contains a combination of the Visitor and Builder
5
+ # classes called a Contractor.
6
+
7
+ ############
8
+ # Requires #
9
+ ############
10
+
11
+ # Gems
12
+ require 'filigree/visitor'
13
+
14
+ # Ruby Language Toolkit
15
+ require 'rltk/cg/builder'
16
+
17
+ #######################
18
+ # Classes and Modules #
19
+ #######################
20
+
21
+ module RLTK::CG
22
+
23
+ class Contractor < Builder
24
+
25
+ include Filigree::Visitor
26
+
27
+ ####################
28
+ # Instance Methods #
29
+ ####################
30
+
31
+ # Alias out the RLTK::Visitor.visit method.
32
+ alias :wrapped_visit :visit
33
+
34
+ # Visit an object in the context of this builder. See the
35
+ # Filigree::Visitor's visit method for more details about the basic
36
+ # behaviour of this method. The special options for this method are:
37
+ #
38
+ # @param [Object] object The object to visit.
39
+ # @param [BasicBlock] at Where to position the contractor before visiting the object.
40
+ # @param [Boolean] rcb If specified the method will also return the block where the contractor is currently positioned.
41
+ #
42
+ # @return [Object]
43
+ def visit(object, at: nil, rcb: false)
44
+ target at if at
45
+
46
+ result = wrapped_visit(object)
47
+
48
+ if rcb then [result, current_block] else result end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,194 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/15
4
+ # Description: This file defines the ExecutionEngine class, along with its
5
+ # subclasses.
6
+
7
+ ############
8
+ # Requires #
9
+ ############
10
+
11
+ # Gems
12
+ require 'filigree/abstract_class'
13
+
14
+ # Ruby Language Toolkit
15
+ require 'rltk/cg/bindings'
16
+ require 'rltk/cg/pass_manager'
17
+ require 'rltk/cg/target'
18
+
19
+ #######################
20
+ # Classes and Modules #
21
+ #######################
22
+
23
+ module RLTK::CG
24
+
25
+ # The ExecutionEngine class and its subclasses execute code from the
26
+ # provided module, as well as providing a {PassManager} and
27
+ # {FunctionPassManager} for optimizing modules.
28
+ #
29
+ # @abstract Implemented by {Interpreter} and {JITCompiler}.
30
+ class ExecutionEngine
31
+ include Filigree::AbstractClass
32
+ include BindingClass
33
+
34
+ # The Proc object called by the garbage collector to free resources used by LLVM.
35
+ CLASS_FINALIZER = Proc.new { |id| Bindings.dispose_execution_engine(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
36
+
37
+ # @return [Module]
38
+ attr_reader :module
39
+
40
+ # Create a new execution engine.
41
+ #
42
+ # @param [Module] mod Module to be executed.
43
+ # @param [Proc] block Block used by subclass constructors. Don't use this parameter.
44
+ #
45
+ # @raise [RuntimeError] An error is raised if something went horribly wrong inside LLVM during the creation of this engine.
46
+ def initialize(mod, &block)
47
+ check_type(mod, Module, 'mod')
48
+
49
+ block = Proc.new { |ptr, error| Bindings.create_execution_engine_for_module(ptr, mod, error) } if block == nil
50
+
51
+ ptr = FFI::MemoryPointer.new(:pointer)
52
+ error = FFI::MemoryPointer.new(:pointer)
53
+ status = block.call(ptr, error)
54
+
55
+ if status.zero?
56
+ @ptr = ptr.read_pointer
57
+ @module = mod
58
+
59
+ # Associate this engine with the provided module.
60
+ @module.engine = self
61
+
62
+ # Define a finalizer to free the memory used by LLVM for
63
+ # this execution engine.
64
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
65
+ else
66
+ errorp = error.read_pointer
67
+ message = errorp.null? ? 'Unknown' : errorp.read_string
68
+
69
+ error.autorelease = false
70
+
71
+ Bindings.dispose_message(error)
72
+
73
+ raise "Error creating execution engine: #{message}"
74
+ end
75
+ end
76
+
77
+ # Builds a pointer to a global value.
78
+ #
79
+ # @param [GlobalValue] global Value you want a pointer to.
80
+ #
81
+ # @return [FFI::Pointer]
82
+ def pointer_to_global(global)
83
+ Bindings.get_pointer_to_global(@ptr, global)
84
+ end
85
+
86
+ # Execute a function in the engine's module with the given arguments.
87
+ # The arguments may be either GnericValue objects or any object that
88
+ # can be turned into a GenericValue.
89
+ #
90
+ # @param [Function] fun Function object to be executed.
91
+ # @param [Array<GenericValue, Object>] args Arguments to be passed to the function.
92
+ #
93
+ # @return [GenericValue]
94
+ def run_function(fun, *args)
95
+ new_args =
96
+ fun.params.zip(args).map do |param, arg|
97
+ if arg.is_a?(GenericValue) then arg else GenericValue.new(arg) end
98
+ end
99
+
100
+ args_ptr = FFI::MemoryPointer.new(:pointer, args.length)
101
+ args_ptr.write_array_of_pointer(new_args)
102
+
103
+ GenericValue.new(Bindings.run_function(@ptr, fun, args.length, args_ptr))
104
+ end
105
+ alias :run :run_function
106
+
107
+ # Execute a function in the engine's module with the given arguments
108
+ # as the main function of a program.
109
+ #
110
+ # @param [Function] fun Function object to be executed.
111
+ # @param [Array<String>] args Arguments to be passed to the function.
112
+ #
113
+ # @return [GenericValue]
114
+ def run_function_as_main(fun, *args)
115
+ # Prepare the ARGV parameter.
116
+ argv = FFI::MemoryPointer.new(:pointer, argc)
117
+ argv.write_array_of_pointer(args.map { |str| FFI::MemoryPointer.from_string(str) })
118
+
119
+ # Prepare the ENV parameter.
120
+ env = FFI::MemoryPointer.new(:pointer, ENV.size)
121
+ env.write_array_of_pointer(ENV.to_a.map { |pair| FFI::MemoryPointer.from_string(pair[0] + '=' + pair[1]) })
122
+
123
+ GenericValue.new(Bindings.run_function_as_main(@ptr, fun, args.length, argv, env))
124
+ end
125
+ alias :run_main :run_function_as_main
126
+
127
+ # @return [TargetData] Information about the target architecture for this execution engine.
128
+ def target_data
129
+ TargetData.new(Bindings.get_execution_engine_target_data(@ptr))
130
+ end
131
+ end
132
+
133
+ # An execution engine that interprets the given code.
134
+ class Interpreter < ExecutionEngine
135
+
136
+ # Create a new interpreter.
137
+ #
138
+ # @param [Module] mod Module to be executed.
139
+ def initialize(mod)
140
+ super(mod) do |ptr, error|
141
+ Bindings.create_interpreter_for_module(ptr, mod, error)
142
+ end
143
+ end
144
+ end
145
+
146
+ # An execution engine that compiles the given code when needed.
147
+ class JITCompiler < ExecutionEngine
148
+
149
+ # Create a new just-in-time compiler.
150
+ #
151
+ # @param [Module] mod Module to be executed.
152
+ # @param [1, 2, 3] opt_level Optimization level; determines how much optimization is done during execution.
153
+ def initialize(mod, opt_level = 3)
154
+ super(mod) do |ptr, error|
155
+ Bindings.create_jit_compiler_for_module(ptr, mod, opt_level, error)
156
+ end
157
+ end
158
+ end
159
+
160
+ # Options for initializing a {MCJITCompiler}.
161
+ class MCJITCompilerOptions < RLTK::CG::Bindings::MCJITCompilerOptions
162
+
163
+ # Create an object representing MCJIT compiler options.
164
+ #
165
+ # @param [Integer] opt_level Optimization level
166
+ # @param [Symbol from _enum_code_model_] code_model JIT compilation code model
167
+ # @param [Boolean] no_frame_pointer_elim Disable frame pointer elimination
168
+ # @param [Boolean] enable_fast_i_sel Turn on fast instruction selection
169
+ def initialize(opt_level = 0, code_model = :jit_default, no_frame_pointer_elim = false,
170
+ enable_fast_i_sel = true)
171
+
172
+ Bindings.initialize_mcjit_compiler_options(self.to_ptr, self.class.size)
173
+
174
+ super(opt_level, code_model, no_frame_pointer_elim.to_i, enable_fast_i_sel.to_i, nil)
175
+ end
176
+ end
177
+
178
+ # The new LLVM JIT execution engine.
179
+ class MCJITCompiler < ExecutionEngine
180
+
181
+ # Create a new MC just-in-time-compiler.
182
+ #
183
+ # @see http://llvm.org/docs/MCJITDesignAndImplementation.html
184
+ # @see http://blog.llvm.org/2013/07/using-mcjit-with-kaleidoscope-tutorial.html
185
+ #
186
+ # @param [Module] mod Module to be executed
187
+ # @param [MCJITCompilerOptions] options Options used to create the MCJIT
188
+ def initialize(mod, options = MCJITCompilerOptions.new)
189
+ super(mod) do |ptr, error|
190
+ Bindings.create_mcjit_compiler_for_module(ptr, mod, options, MCJITCompilerOptions.size, error)
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,237 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/04/06
4
+ # Description: This file defines the Function class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+ require 'rltk/cg/basic_block'
13
+ require 'rltk/cg/value'
14
+
15
+ #######################
16
+ # Classes and Modules #
17
+ #######################
18
+
19
+ module RLTK::CG
20
+
21
+ # An LLVM IR function.
22
+ class Function < GlobalValue
23
+ # @return [FunctionType] FunctionType object describing this function's type.
24
+ attr_reader :type
25
+
26
+ # Define a new function in a given module. You can also use the
27
+ # {Module::FunctionCollection#add} method to add functions to
28
+ # modules.
29
+ #
30
+ # @param [FFI::Pointer, Module] overloaded Pointer to a function objet or a module.
31
+ # @param [String] name Name of the function in LLVM IR.
32
+ # @param [FunctionType, Array(Type, Array<Type>)] type_info FunctionType or Values that will be passed to {FunctionType#initialize}.
33
+ # @param [Proc] block Block to be executed inside the context of the function.
34
+ #
35
+ # @raise [RuntimeError] An error is raised if the overloaded parameter is of an incorrect type.
36
+ def initialize(overloaded, name = '', *type_info, &block)
37
+ @ptr =
38
+ case overloaded
39
+ when FFI::Pointer
40
+ overloaded
41
+
42
+ when RLTK::CG::Module
43
+ @type = if type_info.first.is_a?(FunctionType) then type_info.first else FunctionType.new(*type_info) end
44
+
45
+ Bindings.add_function(overloaded, name.to_s, @type)
46
+
47
+ else
48
+ raise 'The first argument to Function.new must be either a pointer or an instance of RLTK::CG::Module.'
49
+ end
50
+
51
+ self.instance_exec(self, &block) if block
52
+ end
53
+
54
+ # @return [FunctionAttrCollection] Proxy object for inspecting function attributes.
55
+ def attributes
56
+ @attributes ||= FunctionAttrCollection.new(self)
57
+ end
58
+ alias :attrs :attributes
59
+
60
+ # @return [BasicBlockCollection] Proxy object for inspecting a function's basic blocks.
61
+ def basic_blocks
62
+ @basic_blocks ||= BasicBlockCollection.new(self)
63
+ end
64
+ alias :blocks :basic_blocks
65
+
66
+ # Get a function's calling convention.
67
+ #
68
+ # @see Bindings._enum_call_conv_
69
+ #
70
+ # @return [Symbol]
71
+ def calling_convention
72
+ Bindings.enum_type(:call_conv)[Bindings.get_function_call_conv(@ptr)]
73
+ end
74
+
75
+ # Set a function's calling convention.
76
+ #
77
+ # @see Bindings._enum_call_conv_
78
+ #
79
+ # @param [Symbol] conv Calling convention to set.
80
+ def calling_convention=(conv)
81
+ Bindings.set_function_call_conv(@ptr, Bindings.enum_type(:call_conv)[conv])
82
+
83
+ conv
84
+ end
85
+
86
+ # @return [ParameterCollection] Proxy object for inspecting a function's parameters.
87
+ def parameters
88
+ @parameters ||= ParameterCollection.new(self)
89
+ end
90
+ alias :params :parameters
91
+
92
+ # Verify that the function is valid LLVM IR.
93
+ #
94
+ # @return [nil, String] Human-readable description of any invalid constructs if invalid.
95
+ def verify
96
+ do_verification(:return_status)
97
+ end
98
+
99
+ # Verify that the function is valid LLVM IR and abort the process if it isn't.
100
+ #
101
+ # @return [nil]
102
+ def verify!
103
+ do_verification(:abort_process)
104
+ end
105
+
106
+ # Helper function for {#verify} and {#verify!}
107
+ def do_verification(action)
108
+ Bindings.verify_function(@ptr, action).to_bool
109
+ end
110
+ private :do_verification
111
+
112
+ # This class is used to access a function's {BasicBlock BasicBlocks}
113
+ class BasicBlockCollection
114
+ include Enumerable
115
+
116
+ # @param [Function] fun Function for which this is a proxy.
117
+ def initialize(fun)
118
+ @fun = fun
119
+ end
120
+
121
+ # Add a {BasicBlock} to the end of this function.
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
+ #
126
+ # @param [String] name Name of the block in LLVM IR.
127
+ # @param [Builder, nil] builder Builder to be used in evaluating *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.
130
+ # @param [Proc] block Block to be evaluated using *builder* after positioning it at the end of the new block.
131
+ #
132
+ # @return [BasicBlock] New BasicBlock.
133
+ def append(name = '', builder = nil, context = nil, *block_args, &block)
134
+ BasicBlock.new(@fun, name, builder, context, *block_args, &block)
135
+ end
136
+
137
+ # An iterator for each block inside this collection.
138
+ #
139
+ # @yieldparam block [BasicBlock]
140
+ #
141
+ # @return [Enumerator] Returns an Enumerator if no block is given.
142
+ def each
143
+ return to_enum :each unless block_given?
144
+
145
+ ptr = Bindings.get_first_basic_block(@fun)
146
+
147
+ self.size.times do |i|
148
+ yield BasicBlock.new(ptr)
149
+ ptr = Bindings.get_next_basic_block(ptr)
150
+ end
151
+ end
152
+
153
+ # @return [BasicBlock, nil] The function's entry block if it has been added.
154
+ def entry
155
+ if (ptr = Bindings.get_entry_basic_block(@fun)) then BasicBlock.new(ptr) else nil end
156
+ end
157
+
158
+ # @return [BasicBlock, nil] The function's first block if one has been added.
159
+ def first
160
+ if (ptr = Bindings.get_first_basic_block(@fun)) then BasicBlock.new(ptr) else nil end
161
+ end
162
+
163
+ # @return [BasicBlock, nil] The function's last block if one has been added.
164
+ def last
165
+ if (ptr = Bindings.get_last_basic_block(@fun)) then BasicBlock.new(ptr) else nil end
166
+ end
167
+
168
+ # @return [Integer] Number of basic blocks that comprise this function.
169
+ def size
170
+ Bindings.count_basic_blocks(@fun)
171
+ end
172
+ end
173
+
174
+ # This class is used to access a function's attributes.
175
+ class FunctionAttrCollection < AttrCollection
176
+ @@add_method = :add_function_attr
177
+ @@del_method = :remove_function_attr
178
+
179
+ # Set a target-dependent function attribute.
180
+ #
181
+ # @param [String] attribute Attribute name
182
+ # @param [String] value Attribute value
183
+ #
184
+ # @return [void]
185
+ def add_td_attr(attribute, value)
186
+ Bindings.add_target_dependent_function_attr(@value, attribute, value)
187
+ end
188
+ end
189
+
190
+
191
+ # This class is used to access a function's parameters.
192
+ class ParameterCollection
193
+ include Enumerable
194
+
195
+ # @param [Function] fun Function for which this is a proxy.
196
+ def initialize(fun)
197
+ @fun = fun
198
+ end
199
+
200
+ # Access the parameter at the given index.
201
+ #
202
+ # @param [Integer] index Index of the desired parameter. May be negative.
203
+ #
204
+ # @return [Value] Value object representing the parameter.
205
+ def [](index)
206
+ index += self.size if index < 0
207
+
208
+ if 0 <= index and index < self.size
209
+ Value.new(Bindings.get_param(@fun, index))
210
+ end
211
+ end
212
+
213
+ # An iterator for each parameter inside this collection.
214
+ #
215
+ # @yieldparam val [Value]
216
+ #
217
+ # @return [Enumerator] Returns an Enumerator if no block is given.
218
+ def each
219
+ return to_enum :each unless block_given?
220
+
221
+ self.size.times { |index| yield self[index] }
222
+
223
+ self
224
+ end
225
+
226
+ # @return [Integer] Number of function parameters.
227
+ def size
228
+ Bindings.count_params(@fun)
229
+ end
230
+
231
+ # @return [Array<Value>] Array of Value objects representing the function parameters.
232
+ def to_a
233
+ self.size.times.to_a.inject([]) { |params, index| params << self[index] }
234
+ end
235
+ end
236
+ end
237
+ end