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/README.md +610 -0
- data/Rakefile +156 -21
- data/lib/rltk/ast.rb +179 -127
- data/lib/rltk/cfg.rb +131 -38
- data/lib/rltk/cg/basic_block.rb +167 -0
- data/lib/rltk/cg/bindings.rb +136 -0
- data/lib/rltk/cg/builder.rb +1095 -0
- data/lib/rltk/cg/context.rb +51 -0
- data/lib/rltk/cg/execution_engine.rb +172 -0
- data/lib/rltk/cg/function.rb +224 -0
- data/lib/rltk/cg/generated_bindings.rb +6158 -0
- data/lib/rltk/cg/generated_extended_bindings.rb +43 -0
- data/lib/rltk/cg/generic_value.rb +98 -0
- data/lib/rltk/cg/instruction.rb +498 -0
- data/lib/rltk/cg/llvm.rb +51 -0
- data/lib/rltk/cg/memory_buffer.rb +62 -0
- data/lib/rltk/cg/module.rb +328 -0
- data/lib/rltk/cg/pass_manager.rb +201 -0
- data/lib/rltk/cg/support.rb +29 -0
- data/lib/rltk/cg/type.rb +510 -0
- data/lib/rltk/cg/value.rb +1207 -0
- data/lib/rltk/cg.rb +33 -0
- data/lib/rltk/lexer.rb +135 -85
- data/lib/rltk/lexers/calculator.rb +4 -1
- data/lib/rltk/lexers/ebnf.rb +1 -4
- data/lib/rltk/parser.rb +360 -196
- data/lib/rltk/token.rb +29 -4
- data/lib/rltk/util/abstract_class.rb +25 -0
- data/lib/rltk/util/monkeys.rb +125 -0
- data/lib/rltk/version.rb +5 -2
- data/test/tc_ast.rb +11 -11
- data/test/tc_lexer.rb +41 -41
- data/test/tc_parser.rb +123 -97
- data/test/ts_rltk.rb +50 -0
- metadata +181 -87
- data/README +0 -390
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 <
|
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
|
-
#
|
31
|
+
# @return [Symbol] The grammar's starting symbol.
|
32
32
|
attr_reader :start_symbol
|
33
33
|
|
34
|
-
#
|
35
|
-
#
|
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
|
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
|
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
|
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
|
-
#
|
154
|
-
#
|
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
|
-
|
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
|
176
|
-
# individual symbols. CFG
|
177
|
-
# to provide support for calculating the
|
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 =
|
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
|
-
|
250
|
+
[]
|
222
251
|
end
|
223
252
|
end
|
253
|
+
private :first_set_prime
|
224
254
|
|
225
|
-
# Returns the
|
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
|
-
#
|
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
|
-
#
|
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
|
348
|
-
# If
|
349
|
-
# production. If
|
350
|
-
# expected to make one or more calls to CFG
|
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
|
366
|
-
# the productions' left-hand side symbol as the key. If
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
448
|
-
# arguments (
|
449
|
-
# Production
|
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
|
-
#
|
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
|