rltk3 3.0.2

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