rltk 1.2.0 → 2.0.0

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.
data/lib/rltk/cfg.rb CHANGED
@@ -21,18 +21,20 @@ module RLTK # :nodoc:
21
21
 
22
22
  # An exception class that represents a problem with a context-free
23
23
  # grammar's definition.
24
- class GrammarError < Exception; end
24
+ class GrammarError < StandardError; end
25
25
 
26
26
  # The CFG class is used to represent context-free grammars. It is used by
27
27
  # the RLTK::Parser class to represent the parser's grammar, but can also be
28
28
  # used to manipulate arbitrary CFGs.
29
29
  class CFG
30
30
 
31
- # The start symbol for the grammar.
31
+ # @return [Symbol] The grammar's starting symbol.
32
32
  attr_reader :start_symbol
33
33
 
34
- # The current left-hand side symbol. This is used by the
35
- # CFG.production method to wrap CFG.clause calls.
34
+ # This is used by the {CFG#production} method to wrap {CFG#clause}
35
+ # calls.
36
+ #
37
+ # @return [Symbol] The current left-hand side symbol.
36
38
  attr_accessor :curr_lhs
37
39
 
38
40
  #################
@@ -41,12 +43,20 @@ module RLTK # :nodoc:
41
43
 
42
44
  # Tests to see if a symbol is a terminal symbol, as used by the CFG
43
45
  # class.
46
+ #
47
+ # @param [Symbol] sym The symbol to test.
48
+ #
49
+ # @return [Boolean]
44
50
  def self.is_terminal?(sym)
45
51
  sym and (s = sym.to_s) == s.upcase
46
52
  end
47
53
 
48
54
  # Tests to see if a symbol is a non-terminal symbol, as used by the
49
55
  # CFG class.
56
+ #
57
+ # @param [Symbol] sym The symbol to test.
58
+ #
59
+ # @return [Boolean]
50
60
  def self.is_nonterminal?(sym)
51
61
  sym and (s = sym.to_s) == s.downcase
52
62
  end
@@ -55,9 +65,11 @@ module RLTK # :nodoc:
55
65
  # Instance Methods #
56
66
  ####################
57
67
 
58
- # Instantiates a new CFG object that uses _callback_ to inform the
68
+ # Instantiates a new CFG object that uses *callback* to inform the
59
69
  # programmer of the generation of new productions due to EBNF
60
70
  # operators.
71
+ #
72
+ # @param [Proc] callback A Proc object to be called when EBNF operators are expanded.
61
73
  def initialize(&callback)
62
74
  @curr_lhs = nil
63
75
  @callback = callback || Proc.new {}
@@ -77,12 +89,20 @@ module RLTK # :nodoc:
77
89
  @follows = Hash.new { |h,k| h[k] = Array.new }
78
90
  end
79
91
 
80
- # Adds _production_ to the appropriate internal data structures.
92
+ # Adds *production* to the appropriate internal data structures.
93
+ #
94
+ # @param [Production] production The production to add to the grammar.
95
+ #
96
+ # @return [void]
81
97
  def add_production(production)
82
98
  @productions_sym[production.lhs] << (@productions_id[production.id] = production)
83
99
  end
84
100
 
85
- # Sets the EBNF callback to _callback_.
101
+ # Sets the EBNF callback to *callback*.
102
+ #
103
+ # @param [Proc] callback A Proc object to be called when EBNF operators are expanded.
104
+ #
105
+ # @return [void]
86
106
  def callback(&callback)
87
107
  @callback = callback || Proc.new {}
88
108
  end
@@ -91,6 +111,10 @@ module RLTK # :nodoc:
91
111
  # make a new production with the left-hand side specified by the
92
112
  # CFG.production call's argument. This is the function that is
93
113
  # responsible for removing EBNF symbols from the grammar.
114
+ #
115
+ # @param [String] expression The right-hand side of a CFG production.
116
+ #
117
+ # @return [Production]
94
118
  def clause(expression)
95
119
  if not @curr_lhs
96
120
  raise GrammarError, 'CFG.clause called outside of CFG.production block.'
@@ -150,11 +174,12 @@ module RLTK # :nodoc:
150
174
  return production
151
175
  end
152
176
 
153
- # Returns the _first_ set for _sentence_. _Sentence_ may be either a
154
- # single symbol or an array of symbols.
177
+ # @param [Symbol, Array<Symbol>] sentence Sentence to find the *first set* for.
178
+ #
179
+ # @return [Array<Symbol>] The *first set* for the given sentence.
155
180
  def first_set(sentence)
156
181
  if sentence.is_a?(Symbol)
157
- self.first_set_prime(sentence)
182
+ first_set_prime(sentence)
158
183
 
159
184
  elsif sentence.inject(true) { |m, sym| m and self.symbols.include?(sym) }
160
185
  set0 = []
@@ -167,14 +192,18 @@ module RLTK # :nodoc:
167
192
  end
168
193
 
169
194
  if all_have_empty then set0 + [:'ɛ'] else set0 end
170
- else
171
- nil
172
195
  end
173
196
  end
174
197
 
175
- # This function is responsible for calculating the _first_ set of
176
- # individual symbols. CFG.first_set is a wrapper around this function
177
- # to provide support for calculating the _first_ set for sentences.
198
+ # This function is responsible for calculating the *first* set of
199
+ # individual symbols. {CFG#first_set} is a wrapper around this
200
+ # function to provide support for calculating the *first* set for
201
+ # sentences.
202
+ #
203
+ # @param [Symbol] sym0 The symbol to find the *first set* of.
204
+ # @param [Array<Symbol>] seen_lh_sides Previously seen LHS symbols.
205
+ #
206
+ # @return [Array<Symbol>]
178
207
  def first_set_prime(sym0, seen_lh_sides = [])
179
208
  if self.symbols.include?(sym0)
180
209
  # Memoize the result for later.
@@ -202,7 +231,7 @@ module RLTK # :nodoc:
202
231
  # Grab the First set for the current
203
232
  # symbol in this production.
204
233
  if not seen_lh_sides.include?(sym1)
205
- set0 |= (set1 = self.first_set_prime(sym1, seen_lh_sides << sym1)) - [:'ɛ']
234
+ set0 |= (set1 = first_set_prime(sym1, seen_lh_sides << sym1)) - [:'ɛ']
206
235
  end
207
236
 
208
237
  break if not (all_have_empty = set1.include?(:'ɛ'))
@@ -218,13 +247,19 @@ module RLTK # :nodoc:
218
247
  set0.uniq
219
248
  end
220
249
  else
221
- nil
250
+ []
222
251
  end
223
252
  end
253
+ private :first_set_prime
224
254
 
225
- # Returns the _follow_ set for a given symbol. The second argument is
255
+ # Returns the *follow* set for a given symbol. The second argument is
226
256
  # used to avoid infinite recursion when mutually recursive rules are
227
257
  # encountered.
258
+ #
259
+ # @param [Symbol] sym0 The symbol to find the *follow set* for.
260
+ # @param [Array<Symbol>] seen_lh_sides Previously seen LHS symbols.
261
+ #
262
+ # @return [Array<Symbol>]
228
263
  def follow_set(sym0, seen_lh_sides = [])
229
264
 
230
265
  # Use the memoized set if possible.
@@ -262,6 +297,10 @@ module RLTK # :nodoc:
262
297
  end
263
298
 
264
299
  # Builds productions used to eliminate the + EBNF operator.
300
+ #
301
+ # @param [Symbol] symbol Symbol to expand.
302
+ #
303
+ # @return [Symbol]
265
304
  def get_plus(symbol)
266
305
  new_symbol = (symbol.to_s.downcase + '_plus').to_sym
267
306
 
@@ -286,6 +325,10 @@ module RLTK # :nodoc:
286
325
  end
287
326
 
288
327
  # Builds productions used to eliminate the ? EBNF operator.
328
+ #
329
+ # @param [Symbol] symbol Symbol to expand.
330
+ #
331
+ # @return [Symbol]
289
332
  def get_question(symbol)
290
333
  new_symbol = (symbol.to_s.downcase + '_question').to_sym
291
334
 
@@ -310,6 +353,10 @@ module RLTK # :nodoc:
310
353
  end
311
354
 
312
355
  # Builds productions used to eliminate the * EBNF operator.
356
+ #
357
+ # @param [Symbol] symbol Symbol to expand.
358
+ #
359
+ # @return [Symbol]
313
360
  def get_star(symbol)
314
361
  new_symbol = (symbol.to_s.downcase + '_star').to_sym
315
362
 
@@ -333,21 +380,26 @@ module RLTK # :nodoc:
333
380
  return new_symbol
334
381
  end
335
382
 
336
- # Returns the ID for the next production to be defined.
383
+ # @return [Integer] ID for the next production to be defined.
337
384
  def next_id
338
385
  @production_counter += 1
339
386
  end
340
387
 
341
- # Returns all of the non-terminal symbols used in the gramar's
342
- # definition.
388
+ # @return [Array<Symbol>] All terminal symbols used in the grammar's definition.
343
389
  def nonterms
344
390
  @nonterms.keys
345
391
  end
346
392
 
347
- # Builds a new production with the left-hand side value of _symbol_.
348
- # If _expression_ is specified it is take as the right-hand side of
349
- # production. If _expression_ is nil then _block_ is evaluated, and
350
- # expected to make one or more calls to CFG.clause.
393
+ # Builds a new production with the left-hand side value of *symbol*.
394
+ # If *expression* is specified it is take as the right-hand side of
395
+ # production. If *expression* is nil then *block* is evaluated, and
396
+ # expected to make one or more calls to {CFG#clause}.
397
+ #
398
+ # @param [Symbol] symbol The right-hand side of a production.
399
+ # @param [String] expression The left-hand side of a production.
400
+ # @param [Proc] block Optional block for defining production clauses.
401
+ #
402
+ # @return [Array<Production>]
351
403
  def production(symbol, expression = nil, &block)
352
404
  @production_buffer = Array.new
353
405
  @curr_lhs = symbol
@@ -362,10 +414,14 @@ module RLTK # :nodoc:
362
414
  return @production_buffer.clone
363
415
  end
364
416
 
365
- # If _by_ is :sym, returns a hash of the grammar's productions, using
366
- # the productions' left-hand side symbol as the key. If _by_ is :id
417
+ # If *by* is :sym, returns a hash of the grammar's productions, using
418
+ # the productions' left-hand side symbol as the key. If *by* is :id
367
419
  # an array of productions is returned in the order of their
368
420
  # definition.
421
+ #
422
+ # @param [:sym, :id] by The way in which productions should be returned.
423
+ #
424
+ # @return [Array<Production>, Hash{Symbol => Production}]
369
425
  def productions(by = :sym)
370
426
  if by == :sym
371
427
  @productions_sym
@@ -377,6 +433,10 @@ module RLTK # :nodoc:
377
433
  end
378
434
 
379
435
  # Sets the start symbol for this grammar.
436
+ #
437
+ # @param [Symbol] symbol The new start symbol.
438
+ #
439
+ # @return [Symbol]
380
440
  def start(symbol)
381
441
  if not CFG::is_nonterminal?(symbol)
382
442
  raise GrammarError, 'Start symbol must be a non-terminal.'
@@ -385,13 +445,12 @@ module RLTK # :nodoc:
385
445
  @start_symbol = symbol
386
446
  end
387
447
 
388
- # Returns a list of symbols encountered in the grammar's definition.
448
+ # @return [Array<Symbol>] All symbols used in the grammar's definition.
389
449
  def symbols
390
450
  self.terms + self.nonterms
391
451
  end
392
452
 
393
- # Returns a list of all terminal symbols encountered in the grammar's
394
- # definition.
453
+ # @return [Array<Symbol>] All terminal symbols used in the grammar's definition.
395
454
  def terms
396
455
  @terms.keys
397
456
  end
@@ -399,12 +458,21 @@ module RLTK # :nodoc:
399
458
  # Oddly enough, the Production class represents a production in a
400
459
  # context-free grammar.
401
460
  class Production
461
+ # @return [Integer] ID of this production.
402
462
  attr_reader :id
463
+
464
+ # @return [Symbol] Left-hand side of this production.
403
465
  attr_reader :lhs
466
+
467
+ # @return [Array<Symbol>] Right-hand side of this production.
404
468
  attr_reader :rhs
405
469
 
406
470
  # Instantiates a new Production object with the specified ID,
407
471
  # and left- and right-hand sides.
472
+ #
473
+ # @param [Integer] id ID number of this production.
474
+ # @param [Symbol] lhs Left-hand side of the production.
475
+ # @param [Array<Symbol>] rhs Right-hand side of the production.
408
476
  def initialize(id, lhs, rhs)
409
477
  @id = id
410
478
  @lhs = lhs
@@ -413,27 +481,34 @@ module RLTK # :nodoc:
413
481
 
414
482
  # Comparese on production to another. Returns true only if the
415
483
  # left- and right- hand sides match.
484
+ #
485
+ # @param [Production] other Another production to compare to.
486
+ #
487
+ # @return [Boolean]
416
488
  def ==(other)
417
489
  self.lhs == other.lhs and self.rhs == other.rhs
418
490
  end
419
491
 
420
- # Makes a new copy of the production.
492
+ # @return [Production] A new copy of this production.
421
493
  def copy
422
494
  Production.new(@id, @lhs, @rhs.clone)
423
495
  end
424
496
 
425
- # Locates the last terminal in the right-hand side of a
426
- # production.
497
+ # @return [Symbol] The last terminal in the right-hand side of the production.
427
498
  def last_terminal
428
499
  @rhs.inject(nil) { |m, sym| if CFG::is_terminal?(sym) then sym else m end }
429
500
  end
430
501
 
431
- # Returns a new Item based on this production.
502
+ # @return [Item] An Item based on this production.
432
503
  def to_item
433
504
  Item.new(0, @id, @lhs, @rhs)
434
505
  end
435
506
 
436
507
  # Returns a string representation of this production.
508
+ #
509
+ # @param [Integer] padding The ammount of padding spaces to add to the beginning of the string.
510
+ #
511
+ # @return [String]
437
512
  def to_s(padding = 0)
438
513
  "#{format("%-#{padding}s", @lhs)} -> #{@rhs.map { |s| s.to_s }.join(' ')}"
439
514
  end
@@ -441,12 +516,16 @@ module RLTK # :nodoc:
441
516
 
442
517
  # The Item class represents a CFG production with dot in it.
443
518
  class Item < Production
519
+ # @return [Integer] Index of the next symbol in this item.
444
520
  attr_reader :dot
445
521
 
446
522
  # Instantiates a new Item object with a dot located before the
447
- # symbol at index _dot_ of the right-hand side. The remaining
448
- # arguments (_args_) should be as specified by
449
- # Production.initialize.
523
+ # symbol at index *dot* of the right-hand side. The remaining
524
+ # arguments (*args*) should be as specified by
525
+ # {Production#initialize}.
526
+ #
527
+ # @param [Integer] dot Location of the dot in this Item.
528
+ # @param [Array<Object>] args (see {Production#initialize})
450
529
  def initialize(dot, *args)
451
530
  super(*args)
452
531
 
@@ -455,12 +534,18 @@ module RLTK # :nodoc:
455
534
  end
456
535
 
457
536
  # Compares two items.
537
+ #
538
+ # @param [Item] other Another item to compare to.
539
+ #
540
+ # @return [Boolean]
458
541
  def ==(other)
459
542
  self.dot == other.dot and self.lhs == other.lhs and self.rhs == other.rhs
460
543
  end
461
544
 
462
545
  # Moves the items dot forward by one if the end of the right-hand
463
546
  # side hasn't already been reached.
547
+ #
548
+ # @return [Integer, nil]
464
549
  def advance
465
550
  if @dot < @rhs.length
466
551
  @dot += 1
@@ -468,21 +553,29 @@ module RLTK # :nodoc:
468
553
  end
469
554
 
470
555
  # Tests to see if the dot is at the end of the right-hand side.
556
+ #
557
+ # @return [Boolean]
471
558
  def at_end?
472
559
  @dot == @rhs.length
473
560
  end
474
561
 
475
- # Produces a new copy of this item.
562
+ # @return [Item] A new copy of this item.
476
563
  def copy
477
564
  Item.new(@dot, @id, @lhs, @rhs.clone)
478
565
  end
479
566
 
480
567
  # Returns the symbol located after the dot.
568
+ #
569
+ # @return [Symbol] Symbol located after the dot (at the index indicated by the {#dot} attribute).
481
570
  def next_symbol
482
571
  @rhs[@dot]
483
572
  end
484
573
 
485
574
  # Returns a string representation of this item.
575
+ #
576
+ # @param [Integer] padding The ammount of padding spaces to add to the beginning of the string.
577
+ #
578
+ # @return [String]
486
579
  def to_s(padding = 0)
487
580
  "#{format("%-#{padding}s", @lhs)} -> #{@rhs.map { |s| s.to_s }.insert(@dot, '·').join(' ') }"
488
581
  end
@@ -0,0 +1,167 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/04/07
4
+ # Description: This file defines the BasicBlock class.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Ruby Language Toolkit
11
+ require 'rltk/cg/bindings'
12
+ require 'rltk/cg/context'
13
+ require 'rltk/cg/value'
14
+
15
+ #######################
16
+ # Classes and Modules #
17
+ #######################
18
+
19
+ module RLTK::CG # :nodoc:
20
+
21
+ # A BasicBlock is what instructions are inserted into and what functions
22
+ # are made of. BasicBlock objects may be created either using
23
+ # BasicBlock.new or using the {Function::BasicBlockCollection#append}
24
+ # method.
25
+ class BasicBlock < Value
26
+
27
+ # Create a new BasicBlock object. The way the block is created is
28
+ # determined by the *overloaded* parameter. If it is a Function
29
+ # object then the new block is appended to the end of the function.
30
+ # If *overloaded* is another BasicBlock object the new block will
31
+ # be inserted before that block.
32
+ #
33
+ # A block may be given to this function to be invoked by {#build}.
34
+ #
35
+ # @param [FFI::Pointer, Function, BasicBlock] overloaded Overloaded paramater that determines creation behaviour.
36
+ #
37
+ # @param [String] name Name of this BasicBlock.
38
+ # @param [Context, nil] context Context in which to create the block.
39
+ # @param [Builder, nil] builder Builder to be used by {#build}.
40
+ # @param [Array<Object>] block_args Arguments to be passed when block is invoked.
41
+ # @param [Proc] block Block to be invoked by {#build}.
42
+ def initialize(overloaded, name = '', context = nil, builder = nil, *block_args, &block)
43
+ check_type(context, Context, 'context') if context
44
+
45
+ @ptr =
46
+ case overloaded
47
+ when FFI::Pointer
48
+ overloaded
49
+
50
+ when Function
51
+ if context
52
+ Bindings.append_basic_block_in_context(context, overloaded, name)
53
+ else
54
+ Bindings.append_basic_block(overloaded, name)
55
+ end
56
+
57
+ when BasicBlock
58
+ if context
59
+ Bindings.insert_basic_block_in_context(context, overloaded, name)
60
+ else
61
+ Bindings.insert_basic_block(overloaded, name)
62
+ end
63
+ end
64
+
65
+ self.build(builder, *block_args, &block) if block
66
+ end
67
+
68
+ # Used to add instructions to a BasicBlock. The block given to this
69
+ # method is executed inside the context of a {Builder} object, either
70
+ # the one passed in the *builder* parameter or one created for this
71
+ # call. Arguments may be passed into this block via the *block_args*
72
+ # parameter.
73
+ #
74
+ # @example
75
+ # fun = Function.new(...)
76
+ # block.build do
77
+ # ret add(fun.params[0], fun.params[1])
78
+ # end
79
+ #
80
+ # @param [Builder, nil] builder Builder in which to execute this block.
81
+ # @param [Array<Object>] block_args Arguments to pass into block.
82
+ # @param [Proc] block Block to execute inside builder.
83
+ #
84
+ # @return [Object] Value the block evaluates to. Usually an {Instruction}
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
97
+ end
98
+
99
+ # Creates a new BasicBlock inserted immediately before this block.
100
+ #
101
+ # @param [String] name Name of this BasicBlock.
102
+ # @param [Context] context Context in which to create this BasicBlock.
103
+ #
104
+ # @return [BasicBlock]
105
+ def insert_before(name = '', context = nil)
106
+ BasicBlock.new(self, name, context)
107
+ end
108
+
109
+ # @return [InstructionCollect] Collection of all instructions inside this BasicBlock.
110
+ def instructions
111
+ @instructions ||= InstructionCollection.new(self)
112
+ end
113
+
114
+ # @return [BasicBlock, nil] BasicBlock that occures immediately after this block or nil.
115
+ def next
116
+ if (ptr = Bindings.get_next_basic_block(@ptr)).null? then nil else BasicBlock.new(ptr) end
117
+ end
118
+
119
+ # @return [Function] Function object that this BasicBlock belongs to.
120
+ def parent
121
+ if (ptr = Bindings.get_basic_block_parent(@ptr)).null? then nil else Function.new(ptr) end
122
+ end
123
+
124
+ # @return [BasicBlock, nil] BasicBlock that occures immediately before this block or nil.
125
+ def previous
126
+ if (ptr = Bindings.get_previous_basic_block(@ptr)).null? then nil else BasicBlock.new(ptr) end
127
+ end
128
+
129
+ # This class is used to access all of the {Instruction Instructions} that have been added to a {BasicBlock}.
130
+ class InstructionCollection
131
+ include Enumerable
132
+
133
+ # @param [BasicBlock] bb BasicBlock this collection belongs to.
134
+ def initialize(bb)
135
+ @bb = bb
136
+ end
137
+
138
+ # Iterate over each {Instruction} in this collection.
139
+ #
140
+ # @yieldparam inst [Instruction]
141
+ #
142
+ # @return [Enumerator] An Enumerator is returned if no block is given.
143
+ def each
144
+ return to_enum(:each) unless block_given?
145
+
146
+ inst = self.first
147
+
148
+ while inst
149
+ yield inst
150
+ inst = inst.next
151
+ end
152
+
153
+ self
154
+ end
155
+
156
+ # @return [Instruction] First instruction in this collection.
157
+ def first
158
+ if (ptr = Bindings.get_first_instruction(@bb)).null? then nil else Instruction.from_ptr(ptr) end
159
+ end
160
+
161
+ # @return [Instruction] Last instruction in this collection.
162
+ def last
163
+ if (ptr = Bindings.get_last_instruction(@bb)).null? then nil else Instruction.from_ptr(ptr) end
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,136 @@
1
+ # Author: Chris Wailes <chris.wailes@gmail.com>
2
+ # Project: Ruby Language Toolkit
3
+ # Date: 2012/03/08
4
+ # Description: This file holds bindings to LLVM.
5
+
6
+ ############
7
+ # Requires #
8
+ ############
9
+
10
+ # Gems
11
+ require 'rubygems'
12
+ require 'ffi'
13
+
14
+ # Ruby Language Toolkit
15
+ require 'rltk/util/monkeys'
16
+ require 'rltk/version'
17
+ require 'rltk/cg'
18
+
19
+ #######################
20
+ # Classes and Modules #
21
+ #######################
22
+
23
+ module RLTK::CG # :nodoc:
24
+
25
+ # This module provides access to stored FFI::Pointer objects and allows a
26
+ # class to be passed directly into FFI methods. It also provides a
27
+ # pointer comparison method.
28
+ module BindingClass
29
+ # @return [FFI::Pointer]
30
+ attr_accessor :ptr
31
+ alias :to_ptr :ptr
32
+
33
+ # Compares one BindingClass object to another.
34
+ #
35
+ # @param [BindingClass] other Another BindingClass object to compare to.
36
+ #
37
+ # @return [Boolean]
38
+ def ==(other)
39
+ self.class == other.class and @ptr == other.ptr
40
+ end
41
+ end
42
+
43
+ # This module contains FFI bindings to LLVM.
44
+ module Bindings
45
+ extend FFI::Library
46
+ ffi_lib("LLVM-#{RLTK::LLVM_TARGET_VERSION}")
47
+
48
+ # Exception that is thrown when the LLVM target version does not
49
+ # match the version of LLVM present on the system.
50
+ class LibraryMismatch < Exception; end
51
+
52
+ # Require the generated bindings files while handling errors.
53
+ require 'rltk/cg/generated_bindings'
54
+
55
+ begin
56
+ require 'rltk/cg/generated_extended_bindings'
57
+
58
+ # Check to make sure that we have the same target version as the ECB.
59
+ if target_version() != RLTK::LLVM_TARGET_VERSION
60
+ raise LibraryMismatch,
61
+ "Extended bindings expected LLVM version #{target_version()}, " +
62
+ "RLTK expects LLVM version #{RLTK::LLVM_TARGET_VERSION}"
63
+ end
64
+
65
+ @ecb = true
66
+
67
+ rescue LoadError
68
+ @ecb = false
69
+ end
70
+
71
+ #############
72
+ # Constants #
73
+ #############
74
+
75
+ # List of architectures supported by LLVM.
76
+ ARCHS = [
77
+ :ARM,
78
+ :Alpha,
79
+ :Blackfin,
80
+ :CBackend,
81
+ :CellSPU,
82
+ :CppBackend,
83
+ :MBlaze,
84
+ :MSP430,
85
+ :Mips,
86
+ :PTX,
87
+ :PowerPC,
88
+ :Sparc,
89
+ :SystemZ,
90
+ :XCore,
91
+ :X86
92
+ ]
93
+
94
+ ###########
95
+ # Methods #
96
+ ###########
97
+
98
+ # @return [Boolean] If the Extended C Bindings for LLVM are present.
99
+ def self.ecb?
100
+ @ecb
101
+ end
102
+
103
+ # Converts a CamelCase string into an underscored string.
104
+ #
105
+ # @param [#to_s] name CamelCase string.
106
+ #
107
+ # @return [Symbol] Underscored string.
108
+ def self.get_bname(name)
109
+ name.to_s.
110
+ gsub(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2').
111
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
112
+ downcase.to_sym
113
+ end
114
+
115
+ # A wrapper class for FFI::Library.attach_function
116
+ #
117
+ # @param [Symbol] func Function name.
118
+ # @param [Array<Object>] args Argument types for FFI::Library.attach_function.
119
+ # @param [Object] returns Return type for FFI::Library.attach_function.
120
+ def self.add_binding(func, args, returns)
121
+ attach_function(get_bname(func.to_s[4..-1]), func, args, returns)
122
+ end
123
+
124
+ ####################
125
+ # Missing Bindings #
126
+ ####################
127
+
128
+ ARCHS.each do |arch|
129
+ add_binding("LLVMInitialize#{arch}Target", [], :void)
130
+ add_binding("LLVMInitialize#{arch}TargetInfo", [], :void)
131
+ add_binding("LLVMInitialize#{arch}TargetMC", [], :void)
132
+ end
133
+
134
+ add_binding(:LLVMDisposeMessage, [:pointer], :void)
135
+ end
136
+ end