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,150 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/15
4
+ # Description: This file defines the LLVM module.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/version'
12
+ require 'rltk/cg/bindings'
13
+
14
+ #######################
15
+ # Classes and Modules #
16
+ #######################
17
+
18
+ module RLTK::CG
19
+
20
+ # This module contains global operations on the LLVM compiler infrastructure.
21
+ module LLVM
22
+
23
+ # Enable LLVM's built-in stack trace code. This intercepts the OS's
24
+ # crash signals and prints which component of LLVM you were in at the
25
+ # time if the crash.
26
+ #
27
+ # @return [void]
28
+ def self.enable_pretty_stack_trace
29
+ Bindings.enable_pretty_stack_trace
30
+ end
31
+
32
+ # Initialize LLVM to generate code for a given architecture. You may
33
+ # also specify :all to initialize all targets or :native to
34
+ # initialize the host target.
35
+ #
36
+ # @see Bindings::ARCHS
37
+ #
38
+ # @param [Symbol] arch Architecture to initialize LLVM for.
39
+ #
40
+ # @raise [ArgumentError] An error is raised if an unsupported architecture is specified.
41
+ #
42
+ # @return [void]
43
+ def self.init(arch)
44
+ if arch == :all
45
+ Bindings.initialize_all_targets
46
+
47
+ elsif arch == :native
48
+ Bindings.initialize_native_target
49
+
50
+ elsif Bindings::ARCHS.include?(arch) or Bindings::ARCHS.map { |sym| sym.to_s.downcase.to_sym }.include?(arch)
51
+ arch = Bindings.get_bname(arch)
52
+
53
+ Bindings.send("initialize_#{arch}_target".to_sym)
54
+ Bindings.send("initialize_#{arch}_target_info".to_sym)
55
+ Bindings.send("initialize_#{arch}_target_mc".to_sym)
56
+
57
+ else
58
+ raise ArgumentError, "Unsupported architecture specified: #{arch}."
59
+ end
60
+ end
61
+
62
+ # Initialize access to all available target MC that LLVM is
63
+ # configured to support.
64
+ #
65
+ # @return [void]
66
+ def self.initialize_all_target_mcs
67
+ Bindings.initialize_all_target_mcs
68
+ end
69
+
70
+ # Initialize a given ASM parser inside LLVM. You may also specify
71
+ # :all to initialize all ASM parsers.
72
+ #
73
+ # @see Bindings::ASM_PARSERS
74
+ #
75
+ # @param [Symbol] asm Assembly language type to initialize parser for.
76
+ #
77
+ # @raise [ArgumentError] An error is raised if an unsupported assembler parser is specified.
78
+ #
79
+ # @return [void]
80
+ def self.init_asm_parser(asm)
81
+ if asm == :all
82
+ Bindings.initialize_all_asm_parsers
83
+
84
+ elsif Bindings::ASM_PARSERS.include?(asm) or Bindings::ASM_PARSERS.map { |sym| sym.to_s.downcase.to_sym }.include?(asm)
85
+ asm = Bindings.get_bname(asm)
86
+
87
+ Bindings.send("initialize_#{asm}_asm_parser".to_sym)
88
+
89
+ else
90
+ raise ArgumentError, "Unsupported assembler type specified: #{asm}"
91
+ end
92
+ end
93
+
94
+ # Initialize a given ASM printer inside LLVM. You may also specify
95
+ # :all to initialize all ASM printers or :native to initialize the
96
+ # printer for the host machine's assembly language.
97
+ #
98
+ # @see Bindings::ASM_PRINTERS
99
+ #
100
+ # @param [Symbol] asm Assembly language type to initialize printer for.
101
+ #
102
+ # @raise [ArgumentError] An error is raised if an unsupported assembler printer is specified.
103
+ #
104
+ # @return [void]
105
+ def self.init_asm_printer(asm)
106
+ if asm == :all
107
+ Bindings.initialize_all_asm_printers
108
+
109
+ elsif asm == :native
110
+ Bindings.initialize_native_asm_printer
111
+
112
+ elsif Bindings::ASM_PRINTERS.include?(asm) or Bindings::ASM_PRINTERS.map { |sym| sym.to_s.downcase.to_sym }.include?(asm)
113
+ asm = Bindings.get_bname(asm)
114
+
115
+ Bindings.send("initialize_#{asm}_asm_printer".to_sym)
116
+
117
+ else
118
+ raise ArgumentError, "Unsupported assembler type specified: #{asm}"
119
+ end
120
+ end
121
+
122
+ def self.multithreaded?
123
+ Bindings.is_multithreaded.to_bool
124
+ end
125
+
126
+ # Deallocate and destroy all ManagedStatic variables.
127
+ #
128
+ # @return [void]
129
+ def self.shutdown
130
+ Bindings.shutdown
131
+ end
132
+
133
+ # Initialize LLVM's multithreaded infrestructure.
134
+ #
135
+ # @return [void]
136
+ def self.start_multithreaded
137
+ Bindings.start_multithreaded
138
+ end
139
+
140
+ # Shutdown and cleanup LLVM's multithreaded infrastructure.
141
+ def self.stop_multithreaded
142
+ Bindings.stop_multithreaded
143
+ end
144
+
145
+ # @return [String] String representing the version of LLVM targeted by these bindings.
146
+ def self.version
147
+ RLTK::LLVM_TARGET_VERSION
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,75 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/04/16
4
+ # Description: This file defines the MemoryBuffer 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
+ # This class is used by the {Module} class to dump and load LLVM bitcode.
20
+ class MemoryBuffer
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.dispose_memory_buffer(ptr) if ptr = ObjectSpace._id2ref(id).ptr }
25
+
26
+ # Create a new memory buffer.
27
+ #
28
+ # @param [FFI::Pointer, String, nil] overloaded This parameter may be either a pointer to an existing memory
29
+ # buffer, the name of a file containing LLVM bitcode or IR, or nil. If it is nil the memory buffer will read
30
+ # from standard in.
31
+ def initialize(overloaded = nil)
32
+ @ptr =
33
+ case overloaded
34
+ when FFI::Pointer
35
+ overloaded
36
+ else
37
+ buf_ptr = FFI::MemoryPointer.new(:pointer)
38
+ msg_ptr = FFI::MemoryPointer.new(:pointer)
39
+
40
+ status =
41
+ case overloaded
42
+ when String
43
+ Bindings.create_memory_buffer_with_contents_of_file(overloaded, buf_ptr, msg_ptr)
44
+ else
45
+ Bindings.create_memory_buffer_with_stdin(buf_ptr, msg_ptr)
46
+ end
47
+
48
+ if status.zero?
49
+ buf_ptr.get_pointer(0)
50
+ else
51
+ raise msg_ptr.get_pointer(0).get_string(0)
52
+ end
53
+ end
54
+
55
+ # Define a finalizer to free the memory used by LLVM for this
56
+ # memory buffer.
57
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
58
+ end
59
+
60
+ # Get the size of the memory buffer.
61
+ #
62
+ # @return [Integer] Size of memory buffer
63
+ def size
64
+ Bindings.get_buffer_size(@ptr)
65
+ end
66
+
67
+ # Get a copy of the memory buffer, from the beginning, as a sequence
68
+ # of characters.
69
+ #
70
+ # @return [String]
71
+ def start
72
+ Bindings.get_buffer_start(@ptr)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,451 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/20
4
+ # Description: This file defines the Module class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+ require 'rltk/cg/context'
13
+
14
+ #######################
15
+ # Classes and Modules #
16
+ #######################
17
+
18
+ module RLTK::CG
19
+
20
+ # This class represents a collection of functions, constants, and global
21
+ # variables.
22
+ class Module
23
+ include BindingClass
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
+
28
+ # @!attribute [rw] engine
29
+ # @return [ExecutionEngine, nil] Execution engine associated with this module.
30
+ attr_accessor :engine
31
+
32
+ # Load a module from LLVM bitcode.
33
+ #
34
+ # @param [MemoryBuffer, String] overloaded Where to read the bitecode from
35
+ # @param [Context, nil] context Context in which to parse bitcode
36
+ #
37
+ # @return [Module]
38
+ def self.read_bitcode(overloaded, context = nil)
39
+ buffer = overloaded.is_a?(MemoryBuffer) ? overloaded : MemoryBuffer.new(overloaded)
40
+
41
+ mod_ptr = FFI::MemoryPointer.new(:pointer)
42
+ msg_ptr = FFI::MemoryPointer.new(:pointer)
43
+
44
+ status =
45
+ if context
46
+ Bindings.parse_bitcode_in_context(context, buffer, mod_ptr, msg_ptr)
47
+ else
48
+ Bindings.parse_bitcode(buffer, mod_ptr, msg_ptr)
49
+ end
50
+
51
+ if status.zero?
52
+ Module.new(mod_ptr.get_pointer(0))
53
+ else
54
+ raise msg_ptr.get_pointer(0).get_string(0)
55
+ end
56
+ end
57
+
58
+ # Load a Module form an LLVM IR.
59
+ #
60
+ # @param [MemoryBuffer, String] overloaded Where to read the IR from
61
+ # @param [Context] context Context in which to parse IR
62
+ #
63
+ # @return [Module]
64
+ def self.read_ir(overloaded, context = Context.global)
65
+ buffer = overloaded.is_a?(MemoryBuffer) ? overloaded : MemoryBuffer.new(overloaded)
66
+
67
+ mod_ptr = FFI::MemoryPointer.new(:pointer)
68
+ msg_ptr = FFI::MemoryPointer.new(:pointer)
69
+
70
+ status = Bindings.parse_ir_in_context(context, buffer, mod_ptr, msg_ptr)
71
+
72
+ if status.zero?
73
+ Module.new(mod_ptr.get_pointer(0))
74
+ else
75
+ raise msg_ptr.get_pointer(0).get_string(0)
76
+ end
77
+ end
78
+
79
+ # Create a new LLVM module.
80
+ #
81
+ # @param [FFI::Pointer, String] overloaded Pointer to existing module or name of new module.
82
+ # @param [Context, nil] context Optional context in which to create the module.
83
+ # @param [Proc] block Block to be executed inside the context of the module.
84
+ def initialize(overloaded, context = nil, &block)
85
+ @ptr =
86
+ case overloaded
87
+ when FFI::Pointer
88
+ overloaded
89
+
90
+ when String
91
+ if context
92
+ Bindings.module_create_with_name_in_context(overloaded, check_type(context, Context, 'context'))
93
+ else
94
+ Bindings.module_create_with_name(overloaded)
95
+ end
96
+
97
+ else
98
+ raise 'Argument `overloaded` must be a FFI::Pointer of String.'
99
+ end
100
+
101
+ # Define a finalizer to free the memory used by LLVM for this
102
+ # module.
103
+ ObjectSpace.define_finalizer(self, CLASS_FINALIZER)
104
+
105
+ self.instance_exec(&block) if block
106
+ end
107
+
108
+ # Compile this module to an assembly or object file.
109
+ #
110
+ # @param [String] file_name File to emit code to
111
+ # @param [:assembly, :object] emit_type Type of code to emit
112
+ # @param [TargetMachine] machine TargetMachine used to generate code
113
+ #
114
+ # @return [void]
115
+ #
116
+ # @raise LLVM error message if unable to emit code for module
117
+ def compile(file_name, emit_type = :object, machine = TargetMachine.host)
118
+ machine.emite_module(self, file_name, emit_type)
119
+ end
120
+
121
+ # @return [Context] Context in which this module exists.
122
+ def context
123
+ Context.new(Bindings.get_module_context(@ptr))
124
+ end
125
+
126
+ # Print the LLVM IR representation of this value to standard error.
127
+ # This function is the debugging version of the more general purpose
128
+ # {#print} method.
129
+ #
130
+ # @see #print
131
+ #
132
+ # @return [void]
133
+ def dump
134
+ Bindings.dump_module(@ptr)
135
+ end
136
+
137
+ # @return [FunctionPassManager] Function pass manager for this module.
138
+ def function_pass_manager
139
+ @function_pass_manager ||= FunctionPassManager.new(self)
140
+ end
141
+ alias :fpm :function_pass_manager
142
+
143
+ # Link another module into this one, taking ownership of it. You may
144
+ # not access the other module again once linking it.
145
+ #
146
+ # @param [Module] other Module to be linked
147
+ #
148
+ # @raise Errors encountered during linking
149
+ def link(other)
150
+ error = FFI::MemoryPointer.new(:pointer)
151
+ status = Bindings.link_modules(@ptr, other, :linker_destroy_source, error)
152
+
153
+ if not status.zero?
154
+ errorp = error.read_pointer
155
+ message = errorp.null? ? 'Unknown' : errorp.read_string
156
+
157
+ error.autorelease = false
158
+
159
+ Bindings.dispose_message(error)
160
+
161
+ raise "Error linking modules: #{message}"
162
+ end
163
+ end
164
+
165
+ # @return [PassManager] Pass manager for this module.
166
+ def pass_manager
167
+ @pass_manager ||= PassManager.new(self)
168
+ end
169
+ alias :pm :pass_manager
170
+
171
+ # Print the LLVM IR representation of this module to a file.
172
+ #
173
+ # @param [String] file_name Name of file to print to
174
+ #
175
+ # @return [void]
176
+ def print(file_name)
177
+ error = FFI::MemoryPointer.new(:pointer)
178
+ status = Bindings.print_module_to_file(@ptr, file_name, error)
179
+
180
+ if not status.zero?
181
+ errorp = error.read_pointer
182
+ message = errorp.null? ? 'Unknown' : errorp.read_string
183
+
184
+ error.autorelease = false
185
+
186
+ Bindings.dispose_message(error)
187
+
188
+ raise "Error printing module: #{message}"
189
+ end
190
+ end
191
+
192
+ # @return [FunctionCollection] Proxy object for inspecting this module's functions.
193
+ def functions
194
+ @functions ||= FunctionCollection.new(self)
195
+ end
196
+ alias :funs :functions
197
+
198
+ # @return [GlobalCollection] Proxy object for inspecting this module's global values and variables.
199
+ def globals
200
+ @globals ||= GlobalCollection.new(self)
201
+ end
202
+
203
+ # Set the module's target triple.
204
+ #
205
+ # @param [String] triple Triple value to set.
206
+ #
207
+ # @return [void]
208
+ def target=(triple)
209
+ Bindings.set_target(@ptr, triple)
210
+ end
211
+
212
+ # Get the module's target triple.
213
+ #
214
+ # @return [String]
215
+ def target
216
+ Bindings.get_target(@ptr)
217
+ end
218
+
219
+ # Return a LLVM IR representation of this file as a string.
220
+ #
221
+ # @return [String]
222
+ def to_s
223
+ Bindings.print_module_to_string(@ptr)
224
+ end
225
+
226
+ # Write the module as LLVM bitcode to a file.
227
+ #
228
+ # @param [#path, #fileno, Integer, String] overloaded Where to write the bitcode.
229
+ #
230
+ # @return [Boolean] If the write was successful.
231
+ def write_bitcode(overloaded)
232
+ 0 ==
233
+ if overloaded.respond_to?(:path)
234
+ Bindings.write_bitcode_to_file(@ptr, overloaded.path)
235
+
236
+ elsif overloaded.respond_to?(:fileno)
237
+ Bindings.write_bitcode_to_fd(@ptr, overloaded.fileno, 0, 1)
238
+
239
+ elsif overloaded.is_a?(Integer)
240
+ Bindings.write_bitcode_to_fd(@ptr, overloaded, 0, 1)
241
+
242
+ elsif overloaded.is_a?(String)
243
+ Bindings.write_bitcode_to_file(@ptr, overloaded)
244
+ end
245
+ end
246
+
247
+ # Verify that the module is valid LLVM IR.
248
+ #
249
+ # @return [nil, String] Human-readable description of any invalid constructs if invalid.
250
+ def verify
251
+ do_verification(:return_status)
252
+ end
253
+
254
+ # Verify that a module is valid LLVM IR and abort the process if it isn't.
255
+ #
256
+ # @return [nil]
257
+ def verify!
258
+ do_verification(:abort_process)
259
+ end
260
+
261
+ # Helper function for {#verify} and {#verify!}
262
+ def do_verification(action)
263
+ str_ptr = FFI::MemoryPointer.new(:pointer)
264
+ status = Bindings.verify_module(@ptr, action, str_ptr)
265
+
266
+ status == 1 ? str_ptr.read_string : nil
267
+ end
268
+ private :do_verification
269
+
270
+ # This class is used to access a module's {Function Functions}.
271
+ class FunctionCollection
272
+ include Enumerable
273
+
274
+ # @param [Module] mod Module for which this is a proxy.
275
+ def initialize(mod)
276
+ @module = mod
277
+ end
278
+
279
+ # Retreive a Function object.
280
+ #
281
+ # @param [String, Symbol, Integer] key Function identifier. Either the name of the function or its index.
282
+ #
283
+ # @return [Function]
284
+ def [](key)
285
+ case key
286
+ when String, Symbol
287
+ self.named(key)
288
+
289
+ when Integer
290
+ (1...key).inject(self.first) { |fun| if fun then self.next(fun) else break end }
291
+ end
292
+ end
293
+
294
+ # Add a Function to this module.
295
+ #
296
+ # @param [String] name Name of the module in LLVM IR.
297
+ # @param [FunctionType, Array(Type, Array<Type>)] type_info FunctionType or Values that will be passed to {FunctionType#initialize}.
298
+ # @param [Proc] block Block to be executed inside the context of the function.
299
+ #
300
+ # @return [Function]
301
+ def add(name, *type_info, &block)
302
+ Function.new(@module, name, *type_info, &block)
303
+ end
304
+
305
+ # Remove a function from the module.
306
+ #
307
+ # @param [Function] fun Function to remove.
308
+ #
309
+ # @return [void]
310
+ def delete(fun)
311
+ Bindings.delete_function(fun)
312
+ end
313
+
314
+ # An iterator for each function inside this collection.
315
+ #
316
+ # @yieldparam fun [Function]
317
+ #
318
+ # @return [Enumerator] Returns an Enumerator if no block is given.
319
+ def each
320
+ return to_enum(:each) unless block_given?
321
+
322
+ fun = self.first
323
+
324
+ while fun
325
+ yield fun
326
+ fun = self.next(fun)
327
+ end
328
+ end
329
+
330
+ # @return [Function, nil] The module's first function if one has been added.
331
+ def first
332
+ if (ptr = Bindings.get_first_function(@module)).null? then nil else Function.new(ptr) end
333
+ end
334
+
335
+ # @return [Function, nil] The module's last function if one has been added.
336
+ def last
337
+ if (ptr = Bindings.get_last_function(@module)).null? then nil else Function.new(ptr) end
338
+ end
339
+
340
+ # @param [String, Symbol] name Name of the desired function.
341
+ #
342
+ # @return [Function, nil] The function with the given name.
343
+ def named(name)
344
+ if (ptr = Bindings.get_named_function(@module, name)).null? then nil else Function.new(ptr) end
345
+ end
346
+
347
+ # @param [Function] fun Function you want the successor for.
348
+ #
349
+ # @return [Function, nil] Next function in the collection.
350
+ def next(fun)
351
+ if (ptr = Bindings.get_next_function(fun)).null? then nil else Function.new(ptr) end
352
+ end
353
+
354
+ # @param [Function] fun Function you want the predecessor for.
355
+ #
356
+ # @return [Function, nil] Previous function in the collection.
357
+ def previous(fun)
358
+ if (ptr = Bindings.get_previous_function(fun)).null? then nil else Function.new(ptr) end
359
+ end
360
+ end
361
+
362
+ # This class is used to access a module's global variables.
363
+ class GlobalCollection
364
+ include Enumerable
365
+
366
+ # @param [Module] mod Module for which this is a proxy.
367
+ def initialize(mod)
368
+ @module = mod
369
+ end
370
+
371
+ # Retreive a GlobalVariable object.
372
+ #
373
+ # @param [String, Symbol, Integer] key Global variable identifier. Either the name of the variable or its index.
374
+ #
375
+ # @return [GlobalVariable]
376
+ def [](key)
377
+ case key
378
+ when String, Symbol
379
+ self.named(key)
380
+
381
+ when Integer
382
+ (1...key).inject(self.first) { |global| if global then self.next(global) else break end }
383
+ end
384
+ end
385
+
386
+ # Add a global variable to a module.
387
+ #
388
+ # @param [Type] type Type of the global variable.
389
+ # @param [String] name Name of the global variable in LLVM IR.
390
+ def add(type, name)
391
+ GlobalVariable.new(Bindings.add_global(@module, type, name))
392
+ end
393
+
394
+ # Remove a global variable from the module.
395
+ #
396
+ # @param [GlobalVariable] global Global variable to remove.
397
+ #
398
+ # @return [void]
399
+ def delete(global)
400
+ Bindings.delete_global(global)
401
+ end
402
+
403
+ # An iterator for each global variable inside this collection.
404
+ #
405
+ # @yieldparam fun [GlobalVariable]
406
+ #
407
+ # @return [Enumerator] Returns an Enumerator if no block is given.
408
+ def each
409
+ return to_enum(:each) unless block_given?
410
+
411
+ global = self.first
412
+
413
+ while global
414
+ yield global
415
+ global = self.next(global)
416
+ end
417
+ end
418
+
419
+ # @return [GlobalVariable, nil] The module's first global variable if one has been added.
420
+ def first
421
+ if (ptr = Bindings.get_first_global(@module)).null? then nil else GlobalValue.new(ptr) end
422
+ end
423
+
424
+ # @return [GlobalVariable, nil] The module's last global variable if one has been added.
425
+ def last
426
+ if (ptr = Bindings.get_last_global(@module)).null? then nil else GlobalValue.new(ptr) end
427
+ end
428
+
429
+ # @param [String, Symbol] name Name of the desired global variable.
430
+ #
431
+ # @return [GlobalVariable, nil] The global variable with the given name.
432
+ def named(name)
433
+ if (ptr = Bindings.get_named_global(@module, name)).null? then nil else GlobalValue.new(ptr) end
434
+ end
435
+
436
+ # @param [GlobalVariable] global Global variable you want the successor for.
437
+ #
438
+ # @return [GlobalVariable, nil] global Next global variable in the collection.
439
+ def next(global)
440
+ if (ptr = Bindings.get_next_global(global)).null? then nil else GlobalValue.new(ptr) end
441
+ end
442
+
443
+ # @param [GlobalVariable] global Global variable you want the predecessor for.
444
+ #
445
+ # @return [GlobalVariable, nil] Previous global variable in the collection.
446
+ def previous(global)
447
+ if (ptr = Bindings.get_previous_global(global)).null? then nil else GlobalValue.new(ptr) end
448
+ end
449
+ end
450
+ end
451
+ end