rltk3 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +1 -0
  3. data/LICENSE +27 -0
  4. data/README.md +852 -0
  5. data/Rakefile +197 -0
  6. data/lib/rltk/ast.rb +573 -0
  7. data/lib/rltk/cfg.rb +683 -0
  8. data/lib/rltk/cg/basic_block.rb +157 -0
  9. data/lib/rltk/cg/bindings.rb +151 -0
  10. data/lib/rltk/cg/builder.rb +1127 -0
  11. data/lib/rltk/cg/context.rb +48 -0
  12. data/lib/rltk/cg/contractor.rb +51 -0
  13. data/lib/rltk/cg/execution_engine.rb +194 -0
  14. data/lib/rltk/cg/function.rb +237 -0
  15. data/lib/rltk/cg/generated_bindings.rb +8118 -0
  16. data/lib/rltk/cg/generic_value.rb +95 -0
  17. data/lib/rltk/cg/instruction.rb +519 -0
  18. data/lib/rltk/cg/llvm.rb +150 -0
  19. data/lib/rltk/cg/memory_buffer.rb +75 -0
  20. data/lib/rltk/cg/module.rb +451 -0
  21. data/lib/rltk/cg/pass_manager.rb +252 -0
  22. data/lib/rltk/cg/support.rb +29 -0
  23. data/lib/rltk/cg/target.rb +230 -0
  24. data/lib/rltk/cg/triple.rb +58 -0
  25. data/lib/rltk/cg/type.rb +554 -0
  26. data/lib/rltk/cg/value.rb +1272 -0
  27. data/lib/rltk/cg.rb +32 -0
  28. data/lib/rltk/lexer.rb +372 -0
  29. data/lib/rltk/lexers/calculator.rb +44 -0
  30. data/lib/rltk/lexers/ebnf.rb +38 -0
  31. data/lib/rltk/parser.rb +1702 -0
  32. data/lib/rltk/parsers/infix_calc.rb +43 -0
  33. data/lib/rltk/parsers/postfix_calc.rb +34 -0
  34. data/lib/rltk/parsers/prefix_calc.rb +34 -0
  35. data/lib/rltk/token.rb +90 -0
  36. data/lib/rltk/version.rb +11 -0
  37. data/lib/rltk.rb +16 -0
  38. data/test/cg/tc_basic_block.rb +83 -0
  39. data/test/cg/tc_control_flow.rb +191 -0
  40. data/test/cg/tc_function.rb +54 -0
  41. data/test/cg/tc_generic_value.rb +33 -0
  42. data/test/cg/tc_instruction.rb +256 -0
  43. data/test/cg/tc_llvm.rb +25 -0
  44. data/test/cg/tc_math.rb +88 -0
  45. data/test/cg/tc_module.rb +89 -0
  46. data/test/cg/tc_transforms.rb +68 -0
  47. data/test/cg/tc_type.rb +69 -0
  48. data/test/cg/tc_value.rb +151 -0
  49. data/test/cg/ts_cg.rb +23 -0
  50. data/test/tc_ast.rb +332 -0
  51. data/test/tc_cfg.rb +164 -0
  52. data/test/tc_lexer.rb +216 -0
  53. data/test/tc_parser.rb +711 -0
  54. data/test/tc_token.rb +34 -0
  55. data/test/ts_rltk.rb +47 -0
  56. metadata +317 -0
@@ -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