rltk3 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AUTHORS +1 -0
- data/LICENSE +27 -0
- data/README.md +852 -0
- data/Rakefile +197 -0
- data/lib/rltk/ast.rb +573 -0
- data/lib/rltk/cfg.rb +683 -0
- data/lib/rltk/cg/basic_block.rb +157 -0
- data/lib/rltk/cg/bindings.rb +151 -0
- data/lib/rltk/cg/builder.rb +1127 -0
- data/lib/rltk/cg/context.rb +48 -0
- data/lib/rltk/cg/contractor.rb +51 -0
- data/lib/rltk/cg/execution_engine.rb +194 -0
- data/lib/rltk/cg/function.rb +237 -0
- data/lib/rltk/cg/generated_bindings.rb +8118 -0
- data/lib/rltk/cg/generic_value.rb +95 -0
- data/lib/rltk/cg/instruction.rb +519 -0
- data/lib/rltk/cg/llvm.rb +150 -0
- data/lib/rltk/cg/memory_buffer.rb +75 -0
- data/lib/rltk/cg/module.rb +451 -0
- data/lib/rltk/cg/pass_manager.rb +252 -0
- data/lib/rltk/cg/support.rb +29 -0
- data/lib/rltk/cg/target.rb +230 -0
- data/lib/rltk/cg/triple.rb +58 -0
- data/lib/rltk/cg/type.rb +554 -0
- data/lib/rltk/cg/value.rb +1272 -0
- data/lib/rltk/cg.rb +32 -0
- data/lib/rltk/lexer.rb +372 -0
- data/lib/rltk/lexers/calculator.rb +44 -0
- data/lib/rltk/lexers/ebnf.rb +38 -0
- data/lib/rltk/parser.rb +1702 -0
- data/lib/rltk/parsers/infix_calc.rb +43 -0
- data/lib/rltk/parsers/postfix_calc.rb +34 -0
- data/lib/rltk/parsers/prefix_calc.rb +34 -0
- data/lib/rltk/token.rb +90 -0
- data/lib/rltk/version.rb +11 -0
- data/lib/rltk.rb +16 -0
- data/test/cg/tc_basic_block.rb +83 -0
- data/test/cg/tc_control_flow.rb +191 -0
- data/test/cg/tc_function.rb +54 -0
- data/test/cg/tc_generic_value.rb +33 -0
- data/test/cg/tc_instruction.rb +256 -0
- data/test/cg/tc_llvm.rb +25 -0
- data/test/cg/tc_math.rb +88 -0
- data/test/cg/tc_module.rb +89 -0
- data/test/cg/tc_transforms.rb +68 -0
- data/test/cg/tc_type.rb +69 -0
- data/test/cg/tc_value.rb +151 -0
- data/test/cg/ts_cg.rb +23 -0
- data/test/tc_ast.rb +332 -0
- data/test/tc_cfg.rb +164 -0
- data/test/tc_lexer.rb +216 -0
- data/test/tc_parser.rb +711 -0
- data/test/tc_token.rb +34 -0
- data/test/ts_rltk.rb +47 -0
- metadata +317 -0
data/test/cg/tc_value.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2012/05/09
|
4
|
+
# Description: This file contains unit tests for the RLTK::CG::Value class and
|
5
|
+
# its subclasses.
|
6
|
+
|
7
|
+
############
|
8
|
+
# Requires #
|
9
|
+
############
|
10
|
+
|
11
|
+
# Gems
|
12
|
+
require 'minitest/autorun'
|
13
|
+
|
14
|
+
# Ruby Language Toolkit
|
15
|
+
require 'rltk/cg/llvm'
|
16
|
+
require 'rltk/cg/module'
|
17
|
+
require 'rltk/cg/execution_engine'
|
18
|
+
require 'rltk/cg/type'
|
19
|
+
require 'rltk/cg/value'
|
20
|
+
|
21
|
+
class ValueTester < Minitest::Test
|
22
|
+
def setup
|
23
|
+
RLTK::CG::LLVM.init(:X86)
|
24
|
+
|
25
|
+
@mod = RLTK::CG::Module.new('Testing Module')
|
26
|
+
@jit = RLTK::CG::JITCompiler.new(@mod)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_array_values
|
30
|
+
fun = @mod.functions.add('array_function_tester', RLTK::CG::NativeIntType,
|
31
|
+
[RLTK::CG::NativeIntType, RLTK::CG::NativeIntType]) do |fun|
|
32
|
+
|
33
|
+
blocks.append do
|
34
|
+
ptr = alloca(RLTK::CG::ArrayType.new(RLTK::CG::NativeIntType, 2))
|
35
|
+
|
36
|
+
array = load(ptr)
|
37
|
+
array = insert_value(array, fun.params[0], 0)
|
38
|
+
array = insert_value(array, fun.params[1], 1)
|
39
|
+
|
40
|
+
ret(add(extract_value(array, 0), extract_value(array, 1)))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_equal(5, @jit.run_function(fun, 2, 3).to_i)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_constant_array_from_array
|
48
|
+
array = RLTK::CG::ConstantArray.new(RLTK::CG::NativeIntType, [RLTK::CG::NativeInt.new(0), RLTK::CG::NativeInt.new(1)])
|
49
|
+
|
50
|
+
assert_instance_of(RLTK::CG::ConstantArray, array)
|
51
|
+
assert_equal(2, array.length)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_constant_array_from_size
|
55
|
+
array = RLTK::CG::ConstantArray.new(RLTK::CG::NativeIntType, 2) { |i| RLTK::CG::NativeInt.new(i) }
|
56
|
+
|
57
|
+
assert_instance_of(RLTK::CG::ConstantArray, array)
|
58
|
+
assert_equal(2, array.length)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_constant_vector_elements
|
62
|
+
fun = @mod.functions.add('constant_vector_elements_tester', RLTK::CG::NativeIntType,
|
63
|
+
[RLTK::CG::NativeIntType, RLTK::CG::NativeIntType]) do |fun|
|
64
|
+
|
65
|
+
blocks.append do
|
66
|
+
ptr = alloca(RLTK::CG::VectorType.new(RLTK::CG::NativeIntType, 2))
|
67
|
+
|
68
|
+
vector = load(ptr)
|
69
|
+
vector = insert_element(vector, fun.params[0], RLTK::CG::NativeInt.new(0))
|
70
|
+
vector = insert_element(vector, fun.params[1], RLTK::CG::NativeInt.new(1))
|
71
|
+
|
72
|
+
ret(add(extract_element(vector, RLTK::CG::NativeInt.new(0)), extract_element(vector, RLTK::CG::NativeInt.new(1))))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_equal(5, @jit.run_function(fun, 2, 3).to_i)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_constant_vector_from_array
|
80
|
+
vector = RLTK::CG::ConstantVector.new([RLTK::CG::NativeInt.new(0), RLTK::CG::NativeInt.new(1)])
|
81
|
+
|
82
|
+
assert_instance_of(RLTK::CG::ConstantVector, vector)
|
83
|
+
assert_equal(2, vector.size)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_constant_vector_from_size
|
87
|
+
vector = RLTK::CG::ConstantVector.new(2) { |i| RLTK::CG::NativeInt.new(i) }
|
88
|
+
|
89
|
+
assert_instance_of(RLTK::CG::ConstantVector, vector)
|
90
|
+
assert_equal(2, vector.size)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_constant_vector_shuffle
|
94
|
+
fun = @mod.functions.add('constant_vector_shuffle_tester', RLTK::CG::NativeIntType, Array.new(4, RLTK::CG::NativeIntType)) do |fun|
|
95
|
+
blocks.append do
|
96
|
+
vec_type = RLTK::CG::VectorType.new(RLTK::CG::NativeIntType, 2)
|
97
|
+
|
98
|
+
v0 = load(alloca(vec_type))
|
99
|
+
v0 = insert_element(v0, fun.params[0], RLTK::CG::NativeInt.new(0))
|
100
|
+
v0 = insert_element(v0, fun.params[1], RLTK::CG::NativeInt.new(1))
|
101
|
+
|
102
|
+
v1 = load(alloca(vec_type))
|
103
|
+
v1 = insert_element(v1, fun.params[2], RLTK::CG::NativeInt.new(0))
|
104
|
+
v1 = insert_element(v1, fun.params[3], RLTK::CG::NativeInt.new(1))
|
105
|
+
|
106
|
+
v2 = shuffle_vector(v0, v1, RLTK::CG::ConstantVector.new([RLTK::CG::NativeInt.new(0), RLTK::CG::NativeInt.new(3)]))
|
107
|
+
|
108
|
+
ret(add(extract_element(v2, RLTK::CG::NativeInt.new(0)), extract_element(v2, RLTK::CG::NativeInt.new(1))))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
assert_equal(5, @jit.run_function(fun, 1, 2, 3, 4).to_i)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_constant_struct_from_size_packed
|
116
|
+
struct = RLTK::CG::ConstantStruct.new(2, true) { |i| RLTK::CG::NativeInt.new(i) }
|
117
|
+
|
118
|
+
assert_instance_of(RLTK::CG::ConstantStruct, struct)
|
119
|
+
assert_equal(2, struct.operands.size)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_constant_struct_from_size_unpacked
|
123
|
+
struct = RLTK::CG::ConstantStruct.new(2, false) { |i| RLTK::CG::NativeInt.new(i) }
|
124
|
+
|
125
|
+
assert_instance_of(RLTK::CG::ConstantStruct, struct)
|
126
|
+
assert_equal(2, struct.operands.size)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_constant_struct_from_values_packed
|
130
|
+
struct = RLTK::CG::ConstantStruct.new([RLTK::CG::NativeInt.new(0), RLTK::CG::NativeInt.new(1)], true)
|
131
|
+
|
132
|
+
assert_instance_of(RLTK::CG::ConstantStruct, struct)
|
133
|
+
assert_equal(2, struct.operands.size)
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_constant_struct_from_values_unpacked
|
137
|
+
struct = RLTK::CG::ConstantStruct.new([RLTK::CG::NativeInt.new(0), RLTK::CG::NativeInt.new(1)], false)
|
138
|
+
|
139
|
+
assert_instance_of(RLTK::CG::ConstantStruct, struct)
|
140
|
+
assert_equal(2, struct.operands.size)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_equality
|
144
|
+
v0 = RLTK::CG::NativeInt.new(0)
|
145
|
+
v1 = RLTK::CG::NativeInt.new(1)
|
146
|
+
v2 = RLTK::CG::NativeInt.new(v0.ptr)
|
147
|
+
|
148
|
+
assert_equal(v0, v2)
|
149
|
+
refute_equal(v0, v1)
|
150
|
+
end
|
151
|
+
end
|
data/test/cg/ts_cg.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2012/05/04
|
4
|
+
# Description: This file contains test suit for the RLTK LLVM bindigns. It
|
5
|
+
# requires the individual tests from their respective files.
|
6
|
+
|
7
|
+
############
|
8
|
+
# Requires #
|
9
|
+
############
|
10
|
+
|
11
|
+
# Ruby Language Toolkit
|
12
|
+
require 'cg/tc_llvm'
|
13
|
+
require 'cg/tc_module'
|
14
|
+
|
15
|
+
require 'cg/tc_basic_block'
|
16
|
+
require 'cg/tc_control_flow'
|
17
|
+
require 'cg/tc_function'
|
18
|
+
require 'cg/tc_generic_value'
|
19
|
+
require 'cg/tc_instruction'
|
20
|
+
require 'cg/tc_math'
|
21
|
+
require 'cg/tc_transforms'
|
22
|
+
require 'cg/tc_type'
|
23
|
+
require 'cg/tc_value'
|
data/test/tc_ast.rb
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains unit tests for the RLTK::ASTNode class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Gems
|
11
|
+
require 'minitest/autorun'
|
12
|
+
|
13
|
+
# Ruby Language Toolkit
|
14
|
+
require 'rltk/ast'
|
15
|
+
|
16
|
+
#######################
|
17
|
+
# Classes and Modules #
|
18
|
+
#######################
|
19
|
+
|
20
|
+
class ASTNodeTester < Minitest::Test
|
21
|
+
class ANode < RLTK::ASTNode
|
22
|
+
child :left, ANode
|
23
|
+
child :right, ANode
|
24
|
+
end
|
25
|
+
|
26
|
+
class BNode < ANode; end
|
27
|
+
class CNode < ANode; end
|
28
|
+
|
29
|
+
class DNode < RLTK::ASTNode; end
|
30
|
+
|
31
|
+
class ENode < RLTK::ASTNode
|
32
|
+
value :str, String
|
33
|
+
end
|
34
|
+
|
35
|
+
class FNode < ENode
|
36
|
+
child :c, [ENode]
|
37
|
+
end
|
38
|
+
|
39
|
+
class SNode < RLTK::ASTNode
|
40
|
+
value :string, String
|
41
|
+
|
42
|
+
child :left, SNode
|
43
|
+
child :right, SNode
|
44
|
+
end
|
45
|
+
|
46
|
+
class VNode < RLTK::ASTNode
|
47
|
+
value :a, Integer
|
48
|
+
value :b, Integer
|
49
|
+
end
|
50
|
+
|
51
|
+
class ONode < RLTK::ASTNode
|
52
|
+
value :a, Integer
|
53
|
+
value :b, Integer, true
|
54
|
+
value :c, Integer
|
55
|
+
end
|
56
|
+
|
57
|
+
class ValuesFirstNode < RLTK::ASTNode
|
58
|
+
child :b, ValuesFirstNode
|
59
|
+
value :a, Integer
|
60
|
+
end
|
61
|
+
|
62
|
+
class ChildrenFirstNode < RLTK::ASTNode
|
63
|
+
order :children
|
64
|
+
|
65
|
+
value :b, Integer
|
66
|
+
child :a, ChildrenFirstNode
|
67
|
+
end
|
68
|
+
|
69
|
+
class DefOrderNode < RLTK::ASTNode
|
70
|
+
order :def
|
71
|
+
|
72
|
+
value :a, Integer
|
73
|
+
child :b, DefOrderNode
|
74
|
+
value :c, Float
|
75
|
+
end
|
76
|
+
|
77
|
+
class CustomOrderNode < RLTK::ASTNode
|
78
|
+
custom_order :a, :b, :c, :d
|
79
|
+
|
80
|
+
child :b, CustomOrderNode
|
81
|
+
child :d, CustomOrderNode
|
82
|
+
|
83
|
+
value :a, Integer
|
84
|
+
value :c, String
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup
|
88
|
+
@leaf0 = CNode.new
|
89
|
+
@tree0 = ANode.new(BNode.new(@leaf0), BNode.new)
|
90
|
+
|
91
|
+
@tree1 = ANode.new(BNode.new(CNode.new), BNode.new)
|
92
|
+
@tree2 = ANode.new(BNode.new, BNode.new(CNode.new))
|
93
|
+
@tree3 = ANode.new(CNode.new(BNode.new), CNode.new)
|
94
|
+
|
95
|
+
@tree4 = SNode.new('F',
|
96
|
+
SNode.new('B',
|
97
|
+
SNode.new('A'),
|
98
|
+
SNode.new('D',
|
99
|
+
SNode.new('C'),
|
100
|
+
SNode.new('E')
|
101
|
+
),
|
102
|
+
),
|
103
|
+
SNode.new('G',
|
104
|
+
nil,
|
105
|
+
SNode.new('I',
|
106
|
+
SNode.new('H')
|
107
|
+
)
|
108
|
+
)
|
109
|
+
)
|
110
|
+
|
111
|
+
@tree5 = FNode.new('one',
|
112
|
+
[FNode.new('two',
|
113
|
+
[ENode.new('three')]),
|
114
|
+
ENode.new('four')])
|
115
|
+
|
116
|
+
@tree6 = FNode.new('one',
|
117
|
+
[FNode.new('two',
|
118
|
+
[ENode.new('three')]),
|
119
|
+
ENode.new('four')])
|
120
|
+
|
121
|
+
@tree7 = FNode.new('one!',
|
122
|
+
[FNode.new('two!',
|
123
|
+
[ENode.new('three!')]),
|
124
|
+
ENode.new('four!')])
|
125
|
+
|
126
|
+
@bc_proc = Proc.new do |n|
|
127
|
+
case n
|
128
|
+
when BNode then CNode.new(n.left, n.right)
|
129
|
+
when CNode then BNode.new(n.left, n.right)
|
130
|
+
else n
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_children
|
136
|
+
node = ANode.new
|
137
|
+
|
138
|
+
assert_equal(node.children, [nil, nil])
|
139
|
+
|
140
|
+
node.children = (expected_children = [BNode.new, CNode.new])
|
141
|
+
|
142
|
+
assert_equal(node.children, expected_children)
|
143
|
+
|
144
|
+
node.children = (expected_children = {:left => CNode.new, :right => BNode.new})
|
145
|
+
|
146
|
+
assert_equal(node.children(Hash), expected_children)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_copy
|
150
|
+
new_tree = @tree5.copy
|
151
|
+
|
152
|
+
assert_equal(@tree5, new_tree)
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_dump
|
156
|
+
tree0_string = @tree0.dump
|
157
|
+
|
158
|
+
reloaded_tree = Marshal.load(tree0_string)
|
159
|
+
|
160
|
+
assert_equal(@tree0, reloaded_tree)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_each
|
164
|
+
# Test pre-order
|
165
|
+
nodes = []
|
166
|
+
expected = ['F', 'B', 'A', 'D', 'C', 'E', 'G', 'I', 'H']
|
167
|
+
@tree4.each(:pre) { |n| nodes << n.string }
|
168
|
+
|
169
|
+
assert_equal(expected, nodes)
|
170
|
+
|
171
|
+
# Test post-order
|
172
|
+
nodes = []
|
173
|
+
expected = ['A', 'C', 'E', 'D', 'B', 'H', 'I', 'G', 'F']
|
174
|
+
@tree4.each(:post) { |n| nodes << n.string }
|
175
|
+
|
176
|
+
assert_equal(expected, nodes)
|
177
|
+
|
178
|
+
# Test level-order
|
179
|
+
nodes = []
|
180
|
+
expected = ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H']
|
181
|
+
@tree4.each(:level) { |n| nodes << n.string }
|
182
|
+
|
183
|
+
assert_equal(expected, nodes)
|
184
|
+
|
185
|
+
# Test iteration with array children.
|
186
|
+
|
187
|
+
res = ''
|
188
|
+
@tree5.each(:pre) { |node| res += ' ' + node.str }
|
189
|
+
assert_equal(res, ' one two three four')
|
190
|
+
|
191
|
+
res = ''
|
192
|
+
@tree5.each(:post) { |node| res += ' ' + node.str }
|
193
|
+
assert_equal(res, ' three two four one')
|
194
|
+
|
195
|
+
res = ''
|
196
|
+
@tree5.each(:level) { |node| res += ' ' + node.str }
|
197
|
+
assert_equal(res, ' one two four three')
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_equal
|
201
|
+
assert_equal(@tree0, @tree1)
|
202
|
+
refute_equal(@tree0, @tree2)
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_initialize
|
206
|
+
assert_raises(AbstractClassError) { RLTK::ASTNode.new }
|
207
|
+
|
208
|
+
node = ENode.new { self.str = 'hello world' }
|
209
|
+
assert_equal('hello world', node.str)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_map
|
213
|
+
mapped_tree = @tree1.map(&@bc_proc)
|
214
|
+
|
215
|
+
assert_equal(@tree0, @tree1)
|
216
|
+
assert_equal(@tree3, mapped_tree)
|
217
|
+
|
218
|
+
mapped_tree = @tree5.map do |c|
|
219
|
+
c.str += '!'
|
220
|
+
|
221
|
+
c
|
222
|
+
end
|
223
|
+
|
224
|
+
assert_equal(@tree6, @tree5)
|
225
|
+
assert_equal(@tree7, mapped_tree)
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_map!
|
229
|
+
tree1_clone = @tree1.clone
|
230
|
+
tree1_clone.map!(&@bc_proc)
|
231
|
+
|
232
|
+
refute_equal(@tree1, tree1_clone)
|
233
|
+
assert_equal(@tree3, tree1_clone)
|
234
|
+
|
235
|
+
replace_node = BNode.new
|
236
|
+
replace_node = replace_node.map!(&@bc_proc)
|
237
|
+
|
238
|
+
assert_equal(CNode.new, replace_node)
|
239
|
+
|
240
|
+
@tree5.map! do |c|
|
241
|
+
c.str += '!'
|
242
|
+
|
243
|
+
c
|
244
|
+
end
|
245
|
+
|
246
|
+
refute_equal(@tree6, @tree5)
|
247
|
+
assert_equal(@tree7, @tree5)
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_notes
|
251
|
+
node = ANode.new
|
252
|
+
|
253
|
+
assert_nil(node[:a])
|
254
|
+
assert_equal(node[:a] = :b, :b)
|
255
|
+
assert_equal(node.note?(:a), true)
|
256
|
+
assert_equal(node.note?(:b), false)
|
257
|
+
assert_equal(node.delete_note(:a), :b)
|
258
|
+
assert_nil(node[:a])
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_omit
|
262
|
+
onode = ONode.new(1, 3)
|
263
|
+
|
264
|
+
assert_equal(1, onode.a)
|
265
|
+
assert_nil(onode.b)
|
266
|
+
assert_equal(3, onode.c)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_one_definition_rule
|
270
|
+
asserter = self
|
271
|
+
|
272
|
+
Class.new(ANode) do
|
273
|
+
asserter.assert_raises(ArgumentError) { child :left, ANode }
|
274
|
+
end
|
275
|
+
|
276
|
+
Class.new(ENode) do
|
277
|
+
asserter.assert_raises(ArgumentError) { value :str, String }
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_ordering
|
282
|
+
vfn = ValuesFirstNode.new(42, ValuesFirstNode.new)
|
283
|
+
|
284
|
+
a, b = vfn.destructure(2)
|
285
|
+
|
286
|
+
assert_equal(42, a)
|
287
|
+
assert_instance_of(ValuesFirstNode, b)
|
288
|
+
|
289
|
+
cfn = ChildrenFirstNode.new(ChildrenFirstNode.new, 42)
|
290
|
+
|
291
|
+
a, b = cfn.destructure(2)
|
292
|
+
|
293
|
+
assert_instance_of(ChildrenFirstNode, a)
|
294
|
+
assert_equal(42, b)
|
295
|
+
|
296
|
+
dfn = DefOrderNode.new(4, DefOrderNode.new, 2.0)
|
297
|
+
|
298
|
+
a, b, c = dfn.destructure(3)
|
299
|
+
|
300
|
+
assert_equal(4, a)
|
301
|
+
assert_instance_of(DefOrderNode, b)
|
302
|
+
assert_equal(2.0, c)
|
303
|
+
|
304
|
+
con = CustomOrderNode.new(42, CustomOrderNode.new, 'foo')
|
305
|
+
|
306
|
+
a, b, c, d = con.destructure(4)
|
307
|
+
|
308
|
+
assert_equal(42, a)
|
309
|
+
assert_instance_of(CustomOrderNode, b)
|
310
|
+
assert_equal('foo', c)
|
311
|
+
assert_nil(d)
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_root
|
315
|
+
assert_same(@tree0, @tree0.root)
|
316
|
+
assert_same(@tree0, @leaf0.root)
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_value
|
320
|
+
node = VNode.new
|
321
|
+
|
322
|
+
assert_equal(node.values, [nil, nil])
|
323
|
+
|
324
|
+
node.values = (expected_values = [42, 1984])
|
325
|
+
|
326
|
+
assert_equal(node.values, expected_values)
|
327
|
+
|
328
|
+
node.values = (expected_values = {:a => 1984, :b => 42})
|
329
|
+
|
330
|
+
assert_equal(node.values(Hash), expected_values)
|
331
|
+
end
|
332
|
+
end
|
data/test/tc_cfg.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# Author: Chris Wailes <chris.wailes@gmail.com>
|
2
|
+
# Project: Ruby Language Toolkit
|
3
|
+
# Date: 2011/04/06
|
4
|
+
# Description: This file contains unit tests for the RLTK::CFG class.
|
5
|
+
|
6
|
+
############
|
7
|
+
# Requires #
|
8
|
+
############
|
9
|
+
|
10
|
+
# Gems
|
11
|
+
require 'minitest/autorun'
|
12
|
+
|
13
|
+
# Ruby Language Toolkit
|
14
|
+
require 'rltk/cfg'
|
15
|
+
|
16
|
+
#######################
|
17
|
+
# Classes and Modules #
|
18
|
+
#######################
|
19
|
+
|
20
|
+
class CFGTester < Minitest::Test
|
21
|
+
def setup
|
22
|
+
@grammar = RLTK::CFG.new
|
23
|
+
|
24
|
+
@grammar.production(:s) do
|
25
|
+
clause('A G D')
|
26
|
+
clause('A a C')
|
27
|
+
clause('B a D')
|
28
|
+
clause('B G C')
|
29
|
+
end
|
30
|
+
|
31
|
+
@grammar.production(:a, 'b')
|
32
|
+
@grammar.production(:b, 'G')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_callback
|
36
|
+
grammar = RLTK::CFG.new
|
37
|
+
|
38
|
+
call_count = 0
|
39
|
+
grammar.callback do |type, which, p|
|
40
|
+
refute_nil(p)
|
41
|
+
assert_equal(type, :optional)
|
42
|
+
|
43
|
+
case call_count
|
44
|
+
when 0 then assert_equal(:empty, which)
|
45
|
+
when 1 then assert_equal(:nonempty, which)
|
46
|
+
end
|
47
|
+
|
48
|
+
call_count += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
grammar.production(:a, 'A?') { |a| a }
|
52
|
+
assert_equal(2, call_count)
|
53
|
+
|
54
|
+
call_count = 0
|
55
|
+
grammar.callback do |type, which, p|
|
56
|
+
refute_nil(p)
|
57
|
+
|
58
|
+
case call_count
|
59
|
+
when 0
|
60
|
+
assert_equal(:elp, type)
|
61
|
+
assert_equal(:empty, which)
|
62
|
+
|
63
|
+
when 1
|
64
|
+
assert_equal(:elp, type)
|
65
|
+
assert_equal(:nonempty, which)
|
66
|
+
|
67
|
+
when 2
|
68
|
+
assert_equal(:nelp, type)
|
69
|
+
assert_equal(:single, which)
|
70
|
+
|
71
|
+
when 3
|
72
|
+
assert_equal(:nelp, type)
|
73
|
+
assert_equal(:multiple, which)
|
74
|
+
end
|
75
|
+
|
76
|
+
call_count += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
grammar.production(:a, 'A*') { |a| a }
|
80
|
+
assert_equal(4, call_count)
|
81
|
+
|
82
|
+
call_count = 0
|
83
|
+
grammar.callback do |type, which, p|
|
84
|
+
refute_nil(p)
|
85
|
+
assert_equal(type, :nelp)
|
86
|
+
|
87
|
+
case call_count
|
88
|
+
when 0 then assert_equal(:single, which)
|
89
|
+
when 1 then assert_equal(:multiple, which)
|
90
|
+
end
|
91
|
+
|
92
|
+
call_count += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
grammar.production(:a, 'A+') { |a| a }
|
96
|
+
assert_equal(2, call_count)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_first_set
|
100
|
+
@grammar.first_set(:s).each do |sym|
|
101
|
+
assert_includes([:A, :B], sym)
|
102
|
+
end
|
103
|
+
|
104
|
+
assert_equal([:G], @grammar.first_set(:b))
|
105
|
+
assert_equal([:G], @grammar.first_set(:a))
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_follow_set
|
109
|
+
assert_equal(@grammar.follow_set(:s), [:EOS])
|
110
|
+
|
111
|
+
@grammar.follow_set(:a).each do |sym|
|
112
|
+
assert([:C, :D].include?(sym))
|
113
|
+
end
|
114
|
+
|
115
|
+
@grammar.follow_set(:b).each do |sym|
|
116
|
+
assert([:C, :D].include?(sym))
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_is_nonterminal
|
121
|
+
assert(RLTK::CFG::is_nonterminal?(:lowercase))
|
122
|
+
assert(!RLTK::CFG::is_nonterminal?(:UPERCASE))
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_is_terminal
|
126
|
+
assert(!RLTK::CFG::is_terminal?(:lowercase))
|
127
|
+
assert(RLTK::CFG::is_terminal?(:UPERCASE))
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_item
|
131
|
+
i0 = RLTK::CFG::Item.new(0, 0, :a, [:b, :C, :D, :e])
|
132
|
+
i1 = i0.copy
|
133
|
+
|
134
|
+
assert_equal(i0, i1)
|
135
|
+
assert(!i0.at_end?)
|
136
|
+
assert_equal(:b, i0.next_symbol)
|
137
|
+
|
138
|
+
i0.advance
|
139
|
+
|
140
|
+
refute_equal(i0, i1)
|
141
|
+
assert(!i0.at_end?)
|
142
|
+
assert_equal(:C, i0.next_symbol)
|
143
|
+
|
144
|
+
i0.advance
|
145
|
+
assert(!i0.at_end?)
|
146
|
+
assert_equal(:D, i0.next_symbol)
|
147
|
+
|
148
|
+
i0.advance
|
149
|
+
assert(!i0.at_end?)
|
150
|
+
assert_equal(:e, i0.next_symbol)
|
151
|
+
|
152
|
+
i0.advance
|
153
|
+
assert(i0.at_end?)
|
154
|
+
assert_nil(i0.next_symbol)
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_production
|
158
|
+
p0 = RLTK::CFG::Production.new(0, :a, [:b, :C, :D, :e])
|
159
|
+
p1 = p0.copy
|
160
|
+
|
161
|
+
assert_equal(p0, p1)
|
162
|
+
assert_equal(:D, p0.last_terminal)
|
163
|
+
end
|
164
|
+
end
|