rltk 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +46 -2
- data/Rakefile +10 -1
- data/lib/rltk/ast.rb +48 -3
- data/lib/rltk/cfg.rb +90 -21
- data/lib/rltk/cg/bindings.rb +37 -5
- data/lib/rltk/cg/execution_engine.rb +11 -12
- data/lib/rltk/cg/generated_bindings.rb +2 -8
- data/lib/rltk/cg/generated_extended_bindings.rb +244 -0
- data/lib/rltk/cg/llvm.rb +64 -6
- data/lib/rltk/cg/module.rb +80 -2
- data/lib/rltk/cg/pass_manager.rb +28 -15
- data/lib/rltk/cg/support.rb +2 -0
- data/lib/rltk/cg/target.rb +100 -0
- data/lib/rltk/cg/triple.rb +58 -0
- data/lib/rltk/cg/type.rb +7 -7
- data/lib/rltk/cg/value.rb +25 -1
- data/lib/rltk/cg.rb +1 -1
- data/lib/rltk/parser.rb +91 -43
- data/lib/rltk/util/monkeys.rb +8 -4
- data/lib/rltk/version.rb +1 -1
- data/test/tc_ast.rb +62 -8
- data/test/tc_parser.rb +137 -0
- metadata +4 -2
@@ -0,0 +1,58 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2012/06/13
|
4
|
+
# Description: This file defines the Triple 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 # :nodoc:
|
18
|
+
|
19
|
+
# Class binding for the LLVM Triple class.
|
20
|
+
class Triple
|
21
|
+
include BindingClass
|
22
|
+
|
23
|
+
#################
|
24
|
+
# Class Methods #
|
25
|
+
#################
|
26
|
+
|
27
|
+
# @return [Triple] Object representing the host architecture, vendor, OS, and environment.
|
28
|
+
def self.host
|
29
|
+
@host ||= self.new(Bindings.get_host_triple)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] String representation of the host architecture, vendor, OS, and environment.
|
33
|
+
def self.host_string
|
34
|
+
@host_string ||= Bindings.get_host_triple_string
|
35
|
+
end
|
36
|
+
|
37
|
+
####################
|
38
|
+
# Instance Methods #
|
39
|
+
####################
|
40
|
+
|
41
|
+
# Create a new triple describing the host architecture, vendor, OS,
|
42
|
+
# and (optionally) environment.
|
43
|
+
#
|
44
|
+
# @param [FFI::Pointer, String] overloaded
|
45
|
+
def initialize(overloaded)
|
46
|
+
@ptr =
|
47
|
+
case overloaded
|
48
|
+
when FFI::Pointer then overloaded
|
49
|
+
when String then Bindings.triple_create(overloaded)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String] String representation of this triple.
|
54
|
+
def to_s
|
55
|
+
Bindings.get_triple_string(@ptr)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rltk/cg/type.rb
CHANGED
@@ -442,7 +442,7 @@ end
|
|
442
442
|
# @param [String] blame Variable name to blame for failed type checks.
|
443
443
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
444
444
|
#
|
445
|
-
# @raise [
|
445
|
+
# @raise [ArgumentError] An error is raise if a class is passed in parameter *o*
|
446
446
|
# that hasn't included the Singleton class, if the class passed in parameter
|
447
447
|
# *type* isn't a sub-class of {RLTK::CG::Type Type}, or if the type check
|
448
448
|
# fails.
|
@@ -456,10 +456,10 @@ def check_cg_type(o, type = RLTK::CG::Type, blame = 'type', strict = false)
|
|
456
456
|
if o.includes_module?(Singleton)
|
457
457
|
o.instance
|
458
458
|
else
|
459
|
-
raise "The #{o.name} class (passed as parameter #{blame}) must be instantiated directly."
|
459
|
+
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame}) must be instantiated directly."
|
460
460
|
end
|
461
461
|
else
|
462
|
-
raise "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
462
|
+
raise ArgumentError, "The #{o.name} class (passed as parameter #{blame} does not inherit from the #{type.name} class."
|
463
463
|
end
|
464
464
|
else
|
465
465
|
check_type(o, type, blame, strict)
|
@@ -476,7 +476,7 @@ end
|
|
476
476
|
# @param [String] blame Variable name to blame for failed type checks.
|
477
477
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
478
478
|
#
|
479
|
-
# @raise [
|
479
|
+
# @raise [ArgumentError] An error is raise if a class is passed in *array* that
|
480
480
|
# hasn't included the Singleton class, if the class passed in parameter
|
481
481
|
# *type* isn't a sub-class of {RLTK::CG::Type Type}, or if the type check
|
482
482
|
# fails.
|
@@ -491,10 +491,10 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
491
491
|
if o.includes_module?(Singleton)
|
492
492
|
o.instance
|
493
493
|
else
|
494
|
-
raise "The #{o.name} class (passed in parameter #{blame}) must be instantiated directly."
|
494
|
+
raise ArgumentError, "The #{o.name} class (passed in parameter #{blame}) must be instantiated directly."
|
495
495
|
end
|
496
496
|
else
|
497
|
-
raise "The #{o.name} class (passed in parameter #{blame}) does not inherit from the #{type.name} class."
|
497
|
+
raise ArgumentError, "The #{o.name} class (passed in parameter #{blame}) does not inherit from the #{type.name} class."
|
498
498
|
end
|
499
499
|
|
500
500
|
else
|
@@ -503,7 +503,7 @@ def check_cg_array_type(array, type = RLTK::CG::Type, blame = 'el_types', strict
|
|
503
503
|
if type_ok
|
504
504
|
o
|
505
505
|
else
|
506
|
-
raise "Parameter #{blame} must contain instances of the #{type.name} class."
|
506
|
+
raise ArgumentError, "Parameter #{blame} must contain instances of the #{type.name} class."
|
507
507
|
end
|
508
508
|
end
|
509
509
|
end
|
data/lib/rltk/cg/value.rb
CHANGED
@@ -60,7 +60,11 @@ module RLTK::CG # :nodoc:
|
|
60
60
|
Bindings.is_constant(@ptr).to_bool
|
61
61
|
end
|
62
62
|
|
63
|
-
# Print the LLVM IR representation of this value to standard
|
63
|
+
# Print the LLVM IR representation of this value to standard error.
|
64
|
+
# This function is the debugging version of the more general purpose
|
65
|
+
# {#print} method.
|
66
|
+
#
|
67
|
+
# @see #print
|
64
68
|
#
|
65
69
|
# @return [void]
|
66
70
|
def dump
|
@@ -91,6 +95,26 @@ module RLTK::CG # :nodoc:
|
|
91
95
|
Bindings.is_null(@ptr).to_bool
|
92
96
|
end
|
93
97
|
|
98
|
+
# Print the LLVM IR representation of this value to a file. The file
|
99
|
+
# may be specified via a file name (which will be created or
|
100
|
+
# truncated) or an object that responds to #fileno.
|
101
|
+
#
|
102
|
+
# @LLVMECB
|
103
|
+
#
|
104
|
+
# @param [String, #fileno] io File name or object with a file descriptor to print to.
|
105
|
+
#
|
106
|
+
# @return [void]
|
107
|
+
def print(io = $stdout)
|
108
|
+
case io
|
109
|
+
when String
|
110
|
+
File.open(io, 'w') do |f|
|
111
|
+
Bindings.print_value(@ptr, f.fileno)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
Bindings.print_value(@ptr, io.fileno)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
94
118
|
# Truncate a value to a given type.
|
95
119
|
#
|
96
120
|
# @param [Type] type Type to truncate to.
|
data/lib/rltk/cg.rb
CHANGED
@@ -14,7 +14,7 @@ module RLTK # :nodoc:
|
|
14
14
|
# generation functionality is provided by bindings to
|
15
15
|
# [LLVM](http://llvm.org).
|
16
16
|
module CG
|
17
|
-
autoload :
|
17
|
+
autoload :BasicBlock, 'rltk/cg/basic_block'
|
18
18
|
autoload :Bindings, 'rltk/cg/bindings'
|
19
19
|
autoload :Builder, 'rltk/cg/builder'
|
20
20
|
autoload :Context, 'rltk/cg/context'
|
data/lib/rltk/parser.rb
CHANGED
@@ -100,25 +100,41 @@ module RLTK # :nodoc:
|
|
100
100
|
|
101
101
|
@grammar.callback do |p, type, num|
|
102
102
|
@procs[p.id] =
|
103
|
-
[
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
Proc.new {
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
Proc.new { |o
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
Proc.new {
|
120
|
-
|
121
|
-
|
103
|
+
[
|
104
|
+
case type
|
105
|
+
when :*
|
106
|
+
case num
|
107
|
+
when :first then Proc.new { || [] }
|
108
|
+
else Proc.new { |os, o| os << o }
|
109
|
+
end
|
110
|
+
|
111
|
+
when :+
|
112
|
+
case num
|
113
|
+
when :first then Proc.new { |o| [o] }
|
114
|
+
else Proc.new { |os, o| os << o }
|
115
|
+
end
|
116
|
+
|
117
|
+
when :'?'
|
118
|
+
case num
|
119
|
+
when :first then Proc.new { || nil }
|
120
|
+
else Proc.new { |o| o }
|
121
|
+
end
|
122
|
+
|
123
|
+
when :elp
|
124
|
+
case num
|
125
|
+
when :first then Proc.new { || [] }
|
126
|
+
else Proc.new { |prime| prime }
|
127
|
+
end
|
128
|
+
|
129
|
+
when :nelp
|
130
|
+
case num
|
131
|
+
when :first then Proc.new { |el| [el] }
|
132
|
+
when :second then Proc.new { |els, _, el| els + [el] }
|
133
|
+
else Proc.new { |*el| if el.length == 1 then el.first else el end }
|
134
|
+
end
|
135
|
+
end,
|
136
|
+
p.rhs.length
|
137
|
+
]
|
122
138
|
|
123
139
|
@production_precs[p.id] = p.last_terminal
|
124
140
|
end
|
@@ -163,25 +179,41 @@ module RLTK # :nodoc:
|
|
163
179
|
|
164
180
|
@grammar.callback do |p, type, num|
|
165
181
|
@procs[p.id] =
|
166
|
-
[
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Proc.new { |v|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
Proc.new { |v|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
Proc.new { |v|
|
183
|
-
|
184
|
-
|
182
|
+
[
|
183
|
+
case type
|
184
|
+
when :*
|
185
|
+
case num
|
186
|
+
when :first then Proc.new { |v| [] }
|
187
|
+
else Proc.new { |v| v[0] << v[1] }
|
188
|
+
end
|
189
|
+
|
190
|
+
when :+
|
191
|
+
case num
|
192
|
+
when :first then Proc.new { |v| [v[0]] }
|
193
|
+
else Proc.new { |v| v[0] << v[1] }
|
194
|
+
end
|
195
|
+
|
196
|
+
when :'?'
|
197
|
+
case num
|
198
|
+
when :first then Proc.new { |v| nil }
|
199
|
+
else Proc.new { |v| v[0] }
|
200
|
+
end
|
201
|
+
|
202
|
+
when :elp
|
203
|
+
case num
|
204
|
+
when :first then Proc.new { |v| [] }
|
205
|
+
else Proc.new { |v| v[0] }
|
206
|
+
end
|
207
|
+
|
208
|
+
when :nelp
|
209
|
+
case num
|
210
|
+
when :first then Proc.new { |v| v }
|
211
|
+
when :second then Proc.new { |v| v[0] + [v[2]] }
|
212
|
+
else Proc.new { |v| if v.length == 1 then v.first else v end }
|
213
|
+
end
|
214
|
+
end,
|
215
|
+
p.rhs.length
|
216
|
+
]
|
185
217
|
|
186
218
|
@production_precs[p.id] = p.last_terminal
|
187
219
|
end
|
@@ -365,6 +397,14 @@ module RLTK # :nodoc:
|
|
365
397
|
@states.each { |state| state.clean }
|
366
398
|
end
|
367
399
|
|
400
|
+
# Adds productions and actions for parsing empty lists.
|
401
|
+
#
|
402
|
+
# @see CFG#empty_list_production
|
403
|
+
def empty_list_production(symbol, list_elements, separator)
|
404
|
+
@grammar.empty_list(symbol, list_elements, separator)
|
405
|
+
end
|
406
|
+
alias :empty_list :empty_list_production
|
407
|
+
|
368
408
|
# This function will print a description of the parser to the
|
369
409
|
# provided IO object.
|
370
410
|
#
|
@@ -507,7 +547,9 @@ module RLTK # :nodoc:
|
|
507
547
|
opts = build_finalize_opts(opts)
|
508
548
|
|
509
549
|
# Get the name of the file in which the parser is defined.
|
510
|
-
|
550
|
+
#
|
551
|
+
# FIXME: See why this is failing for the simple ListParser example.
|
552
|
+
def_file = caller()[2].split(':')[0] if opts[:use]
|
511
553
|
|
512
554
|
# Check to make sure we can load the necessary information
|
513
555
|
# from the specified object.
|
@@ -725,6 +767,14 @@ module RLTK # :nodoc:
|
|
725
767
|
end
|
726
768
|
end
|
727
769
|
|
770
|
+
# Adds productions and actions for parsing nonempty lists.
|
771
|
+
#
|
772
|
+
# @see CFG#nonempty_list_production
|
773
|
+
def nonempty_list_production(symbol, list_elements, separator)
|
774
|
+
@grammar.nonempty_list(symbol, list_elements, separator)
|
775
|
+
end
|
776
|
+
alias :nonempty_list :nonempty_list_production
|
777
|
+
|
728
778
|
# This function is where actual parsing takes place. The
|
729
779
|
# _tokens_ argument must be an array of Token objects, the last
|
730
780
|
# of which has type EOS. By default this method will return the
|
@@ -772,9 +822,7 @@ module RLTK # :nodoc:
|
|
772
822
|
tokens.each do |token|
|
773
823
|
# Check to make sure this token was seen in the
|
774
824
|
# grammar definition.
|
775
|
-
if not @symbols.include?(token.type)
|
776
|
-
raise BadToken
|
777
|
-
end
|
825
|
+
raise BadToken if not @symbols.include?(token.type)
|
778
826
|
|
779
827
|
v.puts("Current token: #{token.type}#{if token.value then "(#{token.value})" end}") if v
|
780
828
|
|
@@ -1265,7 +1313,7 @@ module RLTK # :nodoc:
|
|
1265
1313
|
@state_stack << state
|
1266
1314
|
@output_stack << o
|
1267
1315
|
@node_stack << @labels.length
|
1268
|
-
@labels << node0
|
1316
|
+
@labels << if CFG::is_terminal?(node0) and o then node0.to_s + "(#{o})" else node0 end
|
1269
1317
|
@positions << position
|
1270
1318
|
|
1271
1319
|
if CFG::is_nonterminal?(node0)
|
data/lib/rltk/util/monkeys.rb
CHANGED
@@ -18,6 +18,8 @@
|
|
18
18
|
# @param [String, nil] blame Variable name to blame for failed type checks.
|
19
19
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
20
20
|
#
|
21
|
+
# @raise [ArgumentError] An error is raise if the type checking fails.
|
22
|
+
#
|
21
23
|
# @return [Object] The object passed as parameter o.
|
22
24
|
def check_type(o, type, blame = nil, strict = false)
|
23
25
|
type_ok = if strict then o.instance_of?(type) else o.is_a?(type) end
|
@@ -26,9 +28,9 @@ def check_type(o, type, blame = nil, strict = false)
|
|
26
28
|
o
|
27
29
|
else
|
28
30
|
if blame
|
29
|
-
raise "Parameter #{blame} must be an instance of the #{type.name} class. Received an instance of #{o.class.name}."
|
31
|
+
raise ArgumentError, "Parameter #{blame} must be an instance of the #{type.name} class. Received an instance of #{o.class.name}."
|
30
32
|
else
|
31
|
-
raise "Expected an object of type #{type.name}. Received an instance of #{o.class.name}."
|
33
|
+
raise ArgumentError, "Expected an object of type #{type.name}. Received an instance of #{o.class.name}."
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -40,6 +42,8 @@ end
|
|
40
42
|
# @param [String, nil] blame Variable name to blame for failed type checks.
|
41
43
|
# @param [Boolean] strict Strict or non-strict checking. Uses `instance_of?` and `is_a?` respectively.
|
42
44
|
#
|
45
|
+
# @raise [ArgumentError] An error is raise if the type checking fails.
|
46
|
+
#
|
43
47
|
# @return [Object] The object passed in parameter o.
|
44
48
|
def check_array_type(array, type, blame = nil, strict = false)
|
45
49
|
array.each do |o|
|
@@ -47,9 +51,9 @@ def check_array_type(array, type, blame = nil, strict = false)
|
|
47
51
|
|
48
52
|
if not type_ok
|
49
53
|
if blame
|
50
|
-
raise "Parameter #{blame} must contain instances of the #{type.name} class."
|
54
|
+
raise ArgumentError, "Parameter #{blame} must contain instances of the #{type.name} class."
|
51
55
|
else
|
52
|
-
raise "Expected an object of type #{type.name}."
|
56
|
+
raise ArgumentError, "Expected an object of type #{type.name}."
|
53
57
|
end
|
54
58
|
end
|
55
59
|
end
|
data/lib/rltk/version.rb
CHANGED
data/test/tc_ast.rb
CHANGED
@@ -29,34 +29,88 @@ class ASTNodeTester < Test::Unit::TestCase
|
|
29
29
|
|
30
30
|
class DNode < RLTK::ASTNode; end
|
31
31
|
|
32
|
+
class SNode < RLTK::ASTNode
|
33
|
+
value :string, String
|
34
|
+
|
35
|
+
child :left, SNode
|
36
|
+
child :right, SNode
|
37
|
+
end
|
38
|
+
|
32
39
|
def setup
|
33
|
-
@leaf0 = CNode.new
|
34
|
-
@tree0 = ANode.new(BNode.new(@leaf0
|
40
|
+
@leaf0 = CNode.new
|
41
|
+
@tree0 = ANode.new(BNode.new(@leaf0), BNode.new)
|
42
|
+
|
43
|
+
@tree1 = ANode.new(BNode.new(CNode.new), BNode.new)
|
44
|
+
@tree2 = ANode.new(BNode.new, BNode.new(CNode.new))
|
35
45
|
|
36
|
-
@
|
37
|
-
|
46
|
+
@tree3 = SNode.new('F',
|
47
|
+
SNode.new('B',
|
48
|
+
SNode.new('A'),
|
49
|
+
SNode.new('D',
|
50
|
+
SNode.new('C'),
|
51
|
+
SNode.new('E')
|
52
|
+
),
|
53
|
+
),
|
54
|
+
SNode.new('G',
|
55
|
+
nil,
|
56
|
+
SNode.new('I',
|
57
|
+
SNode.new('H')
|
58
|
+
)
|
59
|
+
)
|
60
|
+
)
|
38
61
|
end
|
39
62
|
|
40
63
|
def test_children
|
41
|
-
node = ANode.new
|
64
|
+
node = ANode.new
|
42
65
|
|
43
66
|
assert_equal(node.children, [nil, nil])
|
44
67
|
|
45
|
-
node.children = (expected_children = [BNode.new
|
68
|
+
node.children = (expected_children = [BNode.new, CNode.new])
|
46
69
|
|
47
70
|
assert_equal(node.children, expected_children)
|
48
71
|
|
49
72
|
node.map do |child|
|
50
73
|
if child.is_a?(BNode)
|
51
|
-
CNode.new
|
74
|
+
CNode.new
|
52
75
|
else
|
53
|
-
BNode.new
|
76
|
+
BNode.new
|
54
77
|
end
|
55
78
|
end
|
56
79
|
|
57
80
|
assert_equal(node.children, expected_children.reverse)
|
58
81
|
end
|
59
82
|
|
83
|
+
def test_dump
|
84
|
+
tree0_string = @tree0.dump
|
85
|
+
|
86
|
+
reloaded_tree = Marshal.load(tree0_string)
|
87
|
+
|
88
|
+
assert_equal(@tree0, reloaded_tree)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_each
|
92
|
+
# Test pre-order
|
93
|
+
nodes = []
|
94
|
+
expected = ['F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H']
|
95
|
+
@tree3.each(:pre) { |n| nodes << n.string }
|
96
|
+
|
97
|
+
assert_equal(expected, nodes)
|
98
|
+
|
99
|
+
# Test post-order
|
100
|
+
nodes = []
|
101
|
+
expected = ['A', 'C', 'E', 'D', 'B', 'H', 'I', 'G', 'F']
|
102
|
+
@tree3.each(:post) { |n| nodes << n.string }
|
103
|
+
|
104
|
+
assert_equal(expected, nodes)
|
105
|
+
|
106
|
+
# Test level-order
|
107
|
+
nodes = []
|
108
|
+
expected = ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H']
|
109
|
+
@tree3.each(:level) { |n| nodes << n.string }
|
110
|
+
|
111
|
+
assert_equal(expected, nodes)
|
112
|
+
end
|
113
|
+
|
60
114
|
def test_equal
|
61
115
|
assert_equal(@tree0, @tree1)
|
62
116
|
assert_not_equal(@tree0, @tree2)
|
data/test/tc_parser.rb
CHANGED
@@ -31,6 +31,14 @@ class ParserTester < Test::Unit::TestCase
|
|
31
31
|
rule(/\s/)
|
32
32
|
end
|
33
33
|
|
34
|
+
class AlphaLexer < RLTK::Lexer
|
35
|
+
rule(/[A-Za-z]/) { |t| [t.upcase.to_sym, t] }
|
36
|
+
|
37
|
+
rule(/,/) { :COMMA }
|
38
|
+
|
39
|
+
rule(/\s/)
|
40
|
+
end
|
41
|
+
|
34
42
|
class APlusBParser < RLTK::Parser
|
35
43
|
production(:a, 'A+ B') { |a, _| a.length }
|
36
44
|
|
@@ -77,6 +85,44 @@ class ParserTester < Test::Unit::TestCase
|
|
77
85
|
finalize
|
78
86
|
end
|
79
87
|
|
88
|
+
class EmptyListParser0 < RLTK::Parser
|
89
|
+
empty_list('list', :A, :COMMA)
|
90
|
+
|
91
|
+
finalize
|
92
|
+
end
|
93
|
+
|
94
|
+
class EmptyListParser1 < RLTK::Parser
|
95
|
+
array_args
|
96
|
+
|
97
|
+
empty_list('list', ['A', 'B', 'C D'], :COMMA)
|
98
|
+
|
99
|
+
finalize
|
100
|
+
end
|
101
|
+
|
102
|
+
class NonEmptyListParser0 < RLTK::Parser
|
103
|
+
nonempty_list('list', :A, :COMMA)
|
104
|
+
|
105
|
+
finalize
|
106
|
+
end
|
107
|
+
|
108
|
+
class NonEmptyListParser1 < RLTK::Parser
|
109
|
+
nonempty_list('list', [:A, :B], :COMMA)
|
110
|
+
|
111
|
+
finalize
|
112
|
+
end
|
113
|
+
|
114
|
+
class NonEmptyListParser2 < RLTK::Parser
|
115
|
+
nonempty_list('list', ['A', 'B', 'C D'], :COMMA)
|
116
|
+
|
117
|
+
finalize
|
118
|
+
end
|
119
|
+
|
120
|
+
class NonEmptyListParser3 < RLTK::Parser
|
121
|
+
nonempty_list('list', 'A+', :COMMA)
|
122
|
+
|
123
|
+
finalize
|
124
|
+
end
|
125
|
+
|
80
126
|
class DummyError1 < StandardError; end
|
81
127
|
class DummyError2 < StandardError; end
|
82
128
|
|
@@ -193,6 +239,24 @@ class ParserTester < Test::Unit::TestCase
|
|
193
239
|
assert_equal(4, AStarBParser.parse(ABLexer.lex('aaaab')))
|
194
240
|
end
|
195
241
|
|
242
|
+
def test_empty_list
|
243
|
+
####################
|
244
|
+
# EmptyListParser0 #
|
245
|
+
####################
|
246
|
+
|
247
|
+
expected = []
|
248
|
+
actual = EmptyListParser0.parse(AlphaLexer.lex(''))
|
249
|
+
assert_equal(expected, actual)
|
250
|
+
|
251
|
+
####################
|
252
|
+
# EmptyListParser1 #
|
253
|
+
####################
|
254
|
+
|
255
|
+
expected = ['a', 'b', ['c', 'd']]
|
256
|
+
actual = EmptyListParser1.parse(AlphaLexer.lex('a, b, c d'))
|
257
|
+
assert_equal(expected, actual)
|
258
|
+
end
|
259
|
+
|
196
260
|
def test_environment
|
197
261
|
actual = RotatingCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
198
262
|
assert_equal(3, actual)
|
@@ -247,6 +311,79 @@ class ParserTester < Test::Unit::TestCase
|
|
247
311
|
assert_raise(RLTK::BadToken) { RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::EBNF.lex('A B C')) }
|
248
312
|
end
|
249
313
|
|
314
|
+
def test_nonempty_list
|
315
|
+
#######################
|
316
|
+
# NonEmptyListParser0 #
|
317
|
+
#######################
|
318
|
+
|
319
|
+
expected = ['a']
|
320
|
+
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a'))
|
321
|
+
assert_equal(expected, actual)
|
322
|
+
|
323
|
+
expected = ['a', 'a']
|
324
|
+
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a, a'))
|
325
|
+
assert_equal(expected, actual)
|
326
|
+
|
327
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('')) }
|
328
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',')) }
|
329
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('aa')) }
|
330
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('a,')) }
|
331
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',a')) }
|
332
|
+
|
333
|
+
#######################
|
334
|
+
# NonEmptyListParser1 #
|
335
|
+
#######################
|
336
|
+
|
337
|
+
expected = ['a']
|
338
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a'))
|
339
|
+
assert_equal(expected, actual)
|
340
|
+
|
341
|
+
expected = ['b']
|
342
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('b'))
|
343
|
+
assert_equal(expected, actual)
|
344
|
+
|
345
|
+
expected = ['a', 'b', 'a', 'b']
|
346
|
+
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a, b, a, b'))
|
347
|
+
assert_equal(expected, actual)
|
348
|
+
|
349
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser1.parse(AlphaLexer.lex('a b')) }
|
350
|
+
|
351
|
+
#######################
|
352
|
+
# NonEmptyListParser2 #
|
353
|
+
#######################
|
354
|
+
|
355
|
+
expected = ['a']
|
356
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a'))
|
357
|
+
assert_equal(expected, actual)
|
358
|
+
|
359
|
+
expected = ['b']
|
360
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('b'))
|
361
|
+
assert_equal(expected, actual)
|
362
|
+
|
363
|
+
expected = [['c', 'd']]
|
364
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d'))
|
365
|
+
assert_equal(expected, actual)
|
366
|
+
|
367
|
+
expected = [['c', 'd'], ['c', 'd']]
|
368
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d, c d'))
|
369
|
+
assert_equal(expected, actual)
|
370
|
+
|
371
|
+
expected = ['a', 'b', ['c', 'd']]
|
372
|
+
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a, b, c d'))
|
373
|
+
assert_equal(expected, actual)
|
374
|
+
|
375
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('c')) }
|
376
|
+
assert_raise(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('d')) }
|
377
|
+
|
378
|
+
#######################
|
379
|
+
# NonEmptyListParser3 #
|
380
|
+
#######################
|
381
|
+
|
382
|
+
expected = [['a'], ['a', 'a'], ['a', 'a', 'a']]
|
383
|
+
actual = NonEmptyListParser3.parse(AlphaLexer.lex('a, aa, aaa'))
|
384
|
+
assert_equal(expected, actual)
|
385
|
+
end
|
386
|
+
|
250
387
|
def test_postfix_calc
|
251
388
|
actual = RLTK::Parsers::PostfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 +'))
|
252
389
|
assert_equal(3, actual)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rltk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -192,6 +192,8 @@ files:
|
|
192
192
|
- lib/rltk/cg/value.rb
|
193
193
|
- lib/rltk/cg/bindings.rb
|
194
194
|
- lib/rltk/cg/llvm.rb
|
195
|
+
- lib/rltk/cg/target.rb
|
196
|
+
- lib/rltk/cg/triple.rb
|
195
197
|
- lib/rltk/cg/generated_bindings.rb
|
196
198
|
- lib/rltk/parsers/postfix_calc.rb
|
197
199
|
- lib/rltk/parsers/infix_calc.rb
|