rltk 3.0.0 → 3.0.1
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.
- checksums.yaml +4 -4
- data/Rakefile +21 -22
- data/lib/rltk/ast.rb +185 -118
- data/lib/rltk/cfg.rb +157 -103
- data/lib/rltk/cg/basic_block.rb +19 -19
- data/lib/rltk/cg/bindings.rb +16 -16
- data/lib/rltk/cg/builder.rb +129 -129
- data/lib/rltk/cg/context.rb +7 -7
- data/lib/rltk/cg/contractor.rb +7 -7
- data/lib/rltk/cg/execution_engine.rb +30 -30
- data/lib/rltk/cg/function.rb +37 -37
- data/lib/rltk/cg/generated_bindings.rb +3932 -3932
- data/lib/rltk/cg/generic_value.rb +17 -17
- data/lib/rltk/cg/instruction.rb +116 -116
- data/lib/rltk/cg/llvm.rb +22 -22
- data/lib/rltk/cg/memory_buffer.rb +7 -7
- data/lib/rltk/cg/module.rb +73 -73
- data/lib/rltk/cg/pass_manager.rb +35 -35
- data/lib/rltk/cg/target.rb +41 -41
- data/lib/rltk/cg/triple.rb +7 -7
- data/lib/rltk/cg/type.rb +75 -75
- data/lib/rltk/cg/value.rb +161 -161
- data/lib/rltk/lexer.rb +57 -57
- data/lib/rltk/lexers/calculator.rb +7 -7
- data/lib/rltk/lexers/ebnf.rb +5 -5
- data/lib/rltk/parser.rb +338 -295
- data/lib/rltk/parsers/infix_calc.rb +7 -7
- data/lib/rltk/parsers/postfix_calc.rb +3 -3
- data/lib/rltk/parsers/prefix_calc.rb +3 -3
- data/lib/rltk/token.rb +13 -13
- data/lib/rltk/version.rb +6 -6
- data/test/cg/tc_basic_block.rb +17 -17
- data/test/cg/tc_control_flow.rb +41 -41
- data/test/cg/tc_function.rb +4 -4
- data/test/cg/tc_generic_value.rb +3 -3
- data/test/cg/tc_instruction.rb +53 -53
- data/test/cg/tc_math.rb +12 -12
- data/test/cg/tc_module.rb +14 -14
- data/test/cg/tc_transforms.rb +11 -11
- data/test/cg/tc_type.rb +12 -12
- data/test/cg/tc_value.rb +35 -35
- data/test/cg/ts_cg.rb +5 -5
- data/test/tc_ast.rb +137 -60
- data/test/tc_cfg.rb +34 -34
- data/test/tc_lexer.rb +42 -42
- data/test/tc_parser.rb +250 -173
- data/test/tc_token.rb +2 -2
- data/test/ts_rltk.rb +8 -8
- metadata +84 -85
- data/lib/rltk/cg/old_generated_bindings.rb +0 -6152
data/test/tc_cfg.rb
CHANGED
@@ -20,144 +20,144 @@ require 'rltk/cfg'
|
|
20
20
|
class CFGTester < Minitest::Test
|
21
21
|
def setup
|
22
22
|
@grammar = RLTK::CFG.new
|
23
|
-
|
23
|
+
|
24
24
|
@grammar.production(:s) do
|
25
25
|
clause('A G D')
|
26
26
|
clause('A a C')
|
27
27
|
clause('B a D')
|
28
28
|
clause('B G C')
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
@grammar.production(:a, 'b')
|
32
32
|
@grammar.production(:b, 'G')
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def test_callback
|
36
36
|
grammar = RLTK::CFG.new
|
37
|
-
|
37
|
+
|
38
38
|
call_count = 0
|
39
39
|
grammar.callback do |type, which, p|
|
40
40
|
refute_nil(p)
|
41
41
|
assert_equal(type, :optional)
|
42
|
-
|
42
|
+
|
43
43
|
case call_count
|
44
44
|
when 0 then assert_equal(:empty, which)
|
45
45
|
when 1 then assert_equal(:nonempty, which)
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
call_count += 1
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
grammar.production(:a, 'A?') { |a| a }
|
52
52
|
assert_equal(2, call_count)
|
53
|
-
|
53
|
+
|
54
54
|
call_count = 0
|
55
55
|
grammar.callback do |type, which, p|
|
56
56
|
refute_nil(p)
|
57
|
-
|
57
|
+
|
58
58
|
case call_count
|
59
59
|
when 0
|
60
60
|
assert_equal(:elp, type)
|
61
61
|
assert_equal(:empty, which)
|
62
|
-
|
62
|
+
|
63
63
|
when 1
|
64
64
|
assert_equal(:elp, type)
|
65
65
|
assert_equal(:nonempty, which)
|
66
|
-
|
66
|
+
|
67
67
|
when 2
|
68
68
|
assert_equal(:nelp, type)
|
69
69
|
assert_equal(:single, which)
|
70
|
-
|
70
|
+
|
71
71
|
when 3
|
72
72
|
assert_equal(:nelp, type)
|
73
73
|
assert_equal(:multiple, which)
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
call_count += 1
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
grammar.production(:a, 'A*') { |a| a }
|
80
80
|
assert_equal(4, call_count)
|
81
|
-
|
81
|
+
|
82
82
|
call_count = 0
|
83
83
|
grammar.callback do |type, which, p|
|
84
84
|
refute_nil(p)
|
85
85
|
assert_equal(type, :nelp)
|
86
|
-
|
86
|
+
|
87
87
|
case call_count
|
88
88
|
when 0 then assert_equal(:single, which)
|
89
89
|
when 1 then assert_equal(:multiple, which)
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
call_count += 1
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
grammar.production(:a, 'A+') { |a| a }
|
96
96
|
assert_equal(2, call_count)
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
def test_first_set
|
100
100
|
@grammar.first_set(:s).each do |sym|
|
101
101
|
assert_includes([:A, :B], sym)
|
102
102
|
end
|
103
|
-
|
103
|
+
|
104
104
|
assert_equal([:G], @grammar.first_set(:b))
|
105
105
|
assert_equal([:G], @grammar.first_set(:a))
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
def test_follow_set
|
109
109
|
assert_equal(@grammar.follow_set(:s), [:EOS])
|
110
|
-
|
110
|
+
|
111
111
|
@grammar.follow_set(:a).each do |sym|
|
112
112
|
assert([:C, :D].include?(sym))
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
@grammar.follow_set(:b).each do |sym|
|
116
116
|
assert([:C, :D].include?(sym))
|
117
117
|
end
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
def test_is_nonterminal
|
121
121
|
assert(RLTK::CFG::is_nonterminal?(:lowercase))
|
122
122
|
assert(!RLTK::CFG::is_nonterminal?(:UPERCASE))
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
def test_is_terminal
|
126
126
|
assert(!RLTK::CFG::is_terminal?(:lowercase))
|
127
127
|
assert(RLTK::CFG::is_terminal?(:UPERCASE))
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
def test_item
|
131
131
|
i0 = RLTK::CFG::Item.new(0, 0, :a, [:b, :C, :D, :e])
|
132
132
|
i1 = i0.copy
|
133
|
-
|
133
|
+
|
134
134
|
assert_equal(i0, i1)
|
135
135
|
assert(!i0.at_end?)
|
136
136
|
assert_equal(:b, i0.next_symbol)
|
137
|
-
|
137
|
+
|
138
138
|
i0.advance
|
139
|
-
|
139
|
+
|
140
140
|
refute_equal(i0, i1)
|
141
141
|
assert(!i0.at_end?)
|
142
142
|
assert_equal(:C, i0.next_symbol)
|
143
|
-
|
143
|
+
|
144
144
|
i0.advance
|
145
145
|
assert(!i0.at_end?)
|
146
146
|
assert_equal(:D, i0.next_symbol)
|
147
|
-
|
147
|
+
|
148
148
|
i0.advance
|
149
149
|
assert(!i0.at_end?)
|
150
150
|
assert_equal(:e, i0.next_symbol)
|
151
|
-
|
151
|
+
|
152
152
|
i0.advance
|
153
153
|
assert(i0.at_end?)
|
154
154
|
assert_nil(i0.next_symbol)
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
def test_production
|
158
158
|
p0 = RLTK::CFG::Production.new(0, :a, [:b, :C, :D, :e])
|
159
159
|
p1 = p0.copy
|
160
|
-
|
160
|
+
|
161
161
|
assert_equal(p0, p1)
|
162
162
|
assert_equal(:D, p0.last_terminal)
|
163
163
|
end
|
data/test/tc_lexer.rb
CHANGED
@@ -24,28 +24,28 @@ class LexerTester < Minitest::Test
|
|
24
24
|
class ABLongest < RLTK::Lexer
|
25
25
|
rule(/a+/) { :APLUS }
|
26
26
|
rule(/b+/) { :BPLUS }
|
27
|
-
|
27
|
+
|
28
28
|
rule(/a+b+/) { :APLUSBPLUS }
|
29
29
|
end
|
30
30
|
|
31
31
|
class ABFirst < RLTK::Lexer
|
32
32
|
match_first
|
33
|
-
|
33
|
+
|
34
34
|
rule(/a+/) { :APLUS }
|
35
35
|
rule(/b+/) { :BPLUS }
|
36
|
-
|
36
|
+
|
37
37
|
rule(/a+b+/) { :APLUSBPLUS }
|
38
38
|
end
|
39
39
|
|
40
40
|
class ENVLexer < RLTK::Lexer
|
41
41
|
rule(/a/) { [:A, next_value] }
|
42
|
-
|
42
|
+
|
43
43
|
class Environment < Environment
|
44
44
|
def initialize(*args)
|
45
45
|
super(*args)
|
46
46
|
@value = -1
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def next_value
|
50
50
|
@value += 1
|
51
51
|
end
|
@@ -55,7 +55,7 @@ class LexerTester < Minitest::Test
|
|
55
55
|
class FlagLexer < RLTK::Lexer
|
56
56
|
rule(/a/) { set_flag(:a); :A }
|
57
57
|
rule(/\s/)
|
58
|
-
|
58
|
+
|
59
59
|
rule(/b/, :default, [:a]) { set_flag(:b); :B }
|
60
60
|
rule(/c/, :default, [:a, :b]) { :C }
|
61
61
|
end
|
@@ -63,9 +63,9 @@ class LexerTester < Minitest::Test
|
|
63
63
|
class StateLexer < RLTK::Lexer
|
64
64
|
rule(/a/) { :A }
|
65
65
|
rule(/\s/)
|
66
|
-
|
66
|
+
|
67
67
|
rule(/\(\*/) { push_state(:comment) }
|
68
|
-
|
68
|
+
|
69
69
|
rule(/\(\*/, :comment) { push_state(:comment) }
|
70
70
|
rule(/\*\)/, :comment) { pop_state }
|
71
71
|
rule(/./, :comment)
|
@@ -74,42 +74,42 @@ class LexerTester < Minitest::Test
|
|
74
74
|
class MatchDataLexer < RLTK::Lexer
|
75
75
|
rule(/a(b*)(c+)/) { [:FOO, match[1,2]] }
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
def test_calc
|
79
79
|
expected = [
|
80
80
|
RLTK::Token.new(:NUM, 1),
|
81
|
-
|
81
|
+
|
82
82
|
RLTK::Token.new(:PLS),
|
83
83
|
RLTK::Token.new(:SUB),
|
84
84
|
RLTK::Token.new(:MUL),
|
85
85
|
RLTK::Token.new(:DIV),
|
86
|
-
|
86
|
+
|
87
87
|
RLTK::Token.new(:LPAREN),
|
88
88
|
RLTK::Token.new(:RPAREN),
|
89
89
|
RLTK::Token.new(:EOS)
|
90
90
|
]
|
91
|
-
|
91
|
+
|
92
92
|
actual = RLTK::Lexers::Calculator.lex('1 + - * / ( )')
|
93
|
-
|
93
|
+
|
94
94
|
assert_equal(expected, actual)
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
def test_ebnf
|
98
98
|
expected = [
|
99
99
|
RLTK::Token.new(:NONTERM, :aaa),
|
100
100
|
RLTK::Token.new(:TERM, :BBB),
|
101
|
-
|
101
|
+
|
102
102
|
RLTK::Token.new(:STAR),
|
103
103
|
RLTK::Token.new(:PLUS),
|
104
104
|
RLTK::Token.new(:QUESTION),
|
105
105
|
RLTK::Token.new(:EOS)
|
106
106
|
]
|
107
|
-
|
107
|
+
|
108
108
|
actual = RLTK::Lexers::EBNF.lex('aaa BBB * + ?')
|
109
|
-
|
109
|
+
|
110
110
|
assert_equal(expected, actual)
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
def test_environment
|
114
114
|
expected = [
|
115
115
|
RLTK::Token.new(:A, 0),
|
@@ -117,52 +117,52 @@ class LexerTester < Minitest::Test
|
|
117
117
|
RLTK::Token.new(:A, 2),
|
118
118
|
RLTK::Token.new(:EOS)
|
119
119
|
]
|
120
|
-
|
120
|
+
|
121
121
|
actual = ENVLexer.lex('aaa')
|
122
|
-
|
122
|
+
|
123
123
|
assert_equal(expected, actual)
|
124
|
-
|
124
|
+
|
125
125
|
lexer = ENVLexer.new
|
126
|
-
|
126
|
+
|
127
127
|
assert_equal(expected, lexer.lex('aaa'))
|
128
|
-
|
128
|
+
|
129
129
|
expected = [
|
130
130
|
RLTK::Token.new(:A, 3),
|
131
131
|
RLTK::Token.new(:A, 4),
|
132
132
|
RLTK::Token.new(:A, 5),
|
133
133
|
RLTK::Token.new(:EOS)
|
134
134
|
]
|
135
|
-
|
135
|
+
|
136
136
|
assert_equal(expected, lexer.lex('aaa'))
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
def test_first_match
|
140
140
|
expected = [
|
141
141
|
RLTK::Token.new(:APLUS),
|
142
142
|
RLTK::Token.new(:BPLUS),
|
143
143
|
RLTK::Token.new(:EOS)
|
144
144
|
]
|
145
|
-
|
145
|
+
|
146
146
|
actual = ABFirst.lex('aaabbb')
|
147
|
-
|
147
|
+
|
148
148
|
assert_equal(expected, actual)
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
def test_flags
|
152
|
-
|
152
|
+
|
153
153
|
assert_raises(RLTK::LexingError) { FlagLexer.lex('b') }
|
154
154
|
assert_raises(RLTK::LexingError) { FlagLexer.lex('ac') }
|
155
|
-
|
155
|
+
|
156
156
|
expected = [
|
157
157
|
RLTK::Token.new(:A),
|
158
158
|
RLTK::Token.new(:B),
|
159
159
|
RLTK::Token.new(:C),
|
160
160
|
RLTK::Token.new(:EOS)
|
161
161
|
]
|
162
|
-
|
162
|
+
|
163
163
|
actual = FlagLexer.lex('abc')
|
164
164
|
assert_equal(expected, actual)
|
165
|
-
|
165
|
+
|
166
166
|
expected = [
|
167
167
|
RLTK::Token.new(:A),
|
168
168
|
RLTK::Token.new(:B),
|
@@ -172,44 +172,44 @@ class LexerTester < Minitest::Test
|
|
172
172
|
RLTK::Token.new(:C),
|
173
173
|
RLTK::Token.new(:EOS)
|
174
174
|
]
|
175
|
-
|
175
|
+
|
176
176
|
actual = FlagLexer.lex('abcabc')
|
177
177
|
assert_equal(expected, actual)
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
def test_lex
|
181
181
|
assert_raises(RLTK::LexingError) { ABFirst.lex('aaabbbCCC') }
|
182
182
|
assert_raises(RLTK::LexingError) { ABLongest.lex('aaabbbCCC') }
|
183
183
|
end
|
184
|
-
|
184
|
+
|
185
185
|
def test_longest_match
|
186
186
|
expected = [
|
187
187
|
RLTK::Token.new(:APLUSBPLUS),
|
188
188
|
RLTK::Token.new(:EOS)
|
189
189
|
]
|
190
|
-
|
190
|
+
|
191
191
|
actual = ABLongest.lex('aaabbb')
|
192
|
-
|
192
|
+
|
193
193
|
assert_equal(expected, actual)
|
194
194
|
end
|
195
|
-
|
195
|
+
|
196
196
|
def test_match_data
|
197
197
|
expected = [RLTK::Token.new(:FOO, ['', 'ccc']), RLTK::Token.new(:EOS)]
|
198
198
|
actual = MatchDataLexer.lex('accc')
|
199
|
-
|
199
|
+
|
200
200
|
assert_equal(expected, actual)
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
def test_state
|
204
204
|
expected = [
|
205
205
|
RLTK::Token.new(:A),
|
206
206
|
RLTK::Token.new(:A),
|
207
207
|
RLTK::Token.new(:EOS)
|
208
208
|
]
|
209
|
-
|
209
|
+
|
210
210
|
actual = StateLexer.lex('a (* bbb *) a')
|
211
211
|
assert_equal(expected, actual)
|
212
|
-
|
212
|
+
|
213
213
|
actual = StateLexer.lex('a (* b (* ccc *) b *) a')
|
214
214
|
assert_equal(expected, actual)
|
215
215
|
end
|
data/test/tc_parser.rb
CHANGED
@@ -29,606 +29,683 @@ class ParserTester < Minitest::Test
|
|
29
29
|
class ABLexer < RLTK::Lexer
|
30
30
|
rule(/a/) { [:A, 1] }
|
31
31
|
rule(/b/) { [:B, 2] }
|
32
|
-
|
32
|
+
|
33
33
|
rule(/\s/)
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
class AlphaLexer < RLTK::Lexer
|
37
37
|
rule(/[A-Za-z]/) { |t| [t.upcase.to_sym, t] }
|
38
|
-
|
38
|
+
|
39
39
|
rule(/,/) { :COMMA }
|
40
|
-
|
40
|
+
|
41
41
|
rule(/\s/)
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
class UnderscoreLexer < RLTK::Lexer
|
45
45
|
rule(/\w/) { |t| [:A_TOKEN, t] }
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
class APlusBParser < RLTK::Parser
|
49
49
|
production(:a, 'A+ B') { |a, _| a.length }
|
50
|
-
|
50
|
+
|
51
51
|
finalize
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
class AQuestionBParser < RLTK::Parser
|
55
55
|
production(:a, 'A? B') { |a, _| a }
|
56
|
-
|
56
|
+
|
57
57
|
finalize
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
class AStarBParser < RLTK::Parser
|
61
61
|
production(:a, 'A* B') { |a, _| a.length }
|
62
|
-
|
62
|
+
|
63
63
|
finalize
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
class AmbiguousParser < RLTK::Parser
|
67
67
|
production(:e) do
|
68
68
|
clause('NUM') {|n| n}
|
69
|
-
|
69
|
+
|
70
70
|
clause('e PLS e') { |e0, _, e1| e0 + e1 }
|
71
71
|
clause('e SUB e') { |e0, _, e1| e0 - e1 }
|
72
72
|
clause('e MUL e') { |e0, _, e1| e0 * e1 }
|
73
73
|
clause('e DIV e') { |e0, _, e1| e0 / e1 }
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
finalize
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
class ArrayCalc < RLTK::Parser
|
80
80
|
dat :array
|
81
|
-
|
81
|
+
|
82
82
|
production(:e) do
|
83
83
|
clause('NUM') { |v| v[0] }
|
84
|
-
|
84
|
+
|
85
85
|
clause('PLS e e') { |v| v[1] + v[2] }
|
86
86
|
clause('SUB e e') { |v| v[1] - v[2] }
|
87
87
|
clause('MUL e e') { |v| v[1] * v[2] }
|
88
88
|
clause('DIV e e') { |v| v[1] / v[2] }
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
finalize
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# This grammar is purposefully ambiguous. This should not be equivalent
|
95
95
|
# to the grammar produced with `e -> A B? B?`, due to greedy Kleene
|
96
96
|
# operators.
|
97
97
|
class AmbiguousParseStackParser < RLTK::Parser
|
98
98
|
production(:s, 'e*') { |e| e }
|
99
|
-
|
99
|
+
|
100
100
|
production(:e, 'A b_question b_question') { |a, b0, b1| [a, b0, b1] }
|
101
|
-
|
101
|
+
|
102
102
|
production(:b_question) do
|
103
103
|
clause('') { | | nil }
|
104
104
|
clause('B') { |b| b }
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
finalize
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
|
+
class EBNFSelectorParser < RLTK::Parser
|
111
|
+
dat :array
|
112
|
+
|
113
|
+
production(:s) do
|
114
|
+
clause('.A .B* .A') { |a| a }
|
115
|
+
clause('.B C* .B') { |a| a }
|
116
|
+
end
|
117
|
+
|
118
|
+
finalize
|
119
|
+
end
|
120
|
+
|
110
121
|
class EmptyListParser0 < RLTK::Parser
|
111
122
|
list('list', :A, :COMMA)
|
112
|
-
|
123
|
+
|
113
124
|
finalize
|
114
125
|
end
|
115
|
-
|
126
|
+
|
116
127
|
class EmptyListParser1 < RLTK::Parser
|
117
128
|
dat :array
|
118
|
-
|
129
|
+
|
119
130
|
list('list', ['A', 'B', 'C D'], :COMMA)
|
120
|
-
|
131
|
+
|
121
132
|
finalize
|
122
133
|
end
|
123
|
-
|
134
|
+
|
124
135
|
class GreedTestParser0 < RLTK::Parser
|
125
136
|
production(:e, 'A? A') { |a0, a1| [a0, a1] }
|
126
|
-
|
137
|
+
|
127
138
|
finalize
|
128
139
|
end
|
129
|
-
|
140
|
+
|
130
141
|
class GreedTestParser1 < RLTK::Parser
|
131
142
|
production(:e, 'A? A?') { |a0, a1| [a0, a1] }
|
132
|
-
|
143
|
+
|
133
144
|
finalize
|
134
145
|
end
|
135
|
-
|
146
|
+
|
136
147
|
class GreedTestParser2 < RLTK::Parser
|
137
148
|
production(:e, 'A* A') { |a0, a1| [a0, a1] }
|
138
|
-
|
149
|
+
|
139
150
|
finalize
|
140
151
|
end
|
141
|
-
|
152
|
+
|
142
153
|
class GreedTestParser3 < RLTK::Parser
|
143
154
|
production(:e, 'A+ A') { |a0, a1| [a0, a1] }
|
144
|
-
|
155
|
+
|
145
156
|
finalize
|
146
157
|
end
|
147
|
-
|
158
|
+
|
148
159
|
class NonEmptyListParser0 < RLTK::Parser
|
149
160
|
nonempty_list('list', :A, :COMMA)
|
150
|
-
|
161
|
+
|
151
162
|
finalize
|
152
163
|
end
|
153
|
-
|
164
|
+
|
154
165
|
class NonEmptyListParser1 < RLTK::Parser
|
155
166
|
nonempty_list('list', [:A, :B], :COMMA)
|
156
|
-
|
167
|
+
|
157
168
|
finalize explain: 'nelp1.tbl'
|
158
169
|
end
|
159
|
-
|
170
|
+
|
160
171
|
class NonEmptyListParser2 < RLTK::Parser
|
161
172
|
nonempty_list('list', ['A', 'B', 'C D'], :COMMA)
|
162
|
-
|
173
|
+
|
163
174
|
finalize
|
164
175
|
end
|
165
|
-
|
176
|
+
|
166
177
|
class NonEmptyListParser3 < RLTK::Parser
|
167
178
|
nonempty_list('list', 'A+', :COMMA)
|
168
|
-
|
179
|
+
|
169
180
|
finalize
|
170
181
|
end
|
171
|
-
|
182
|
+
|
172
183
|
class NonEmptyListParser4 < RLTK::Parser
|
173
184
|
nonempty_list('list', :A)
|
174
|
-
|
185
|
+
|
175
186
|
finalize
|
176
187
|
end
|
177
|
-
|
188
|
+
|
178
189
|
class NonEmptyListParser5 < RLTK::Parser
|
179
190
|
nonempty_list('list', :A, 'B C?')
|
180
|
-
|
191
|
+
|
181
192
|
finalize
|
182
193
|
end
|
183
|
-
|
194
|
+
|
184
195
|
class DummyError1 < StandardError; end
|
185
196
|
class DummyError2 < StandardError; end
|
186
|
-
|
197
|
+
|
187
198
|
class ErrorCalc < RLTK::Parser
|
188
199
|
left :ERROR
|
189
200
|
right :PLS, :SUB, :MUL, :DIV, :NUM
|
190
|
-
|
201
|
+
|
191
202
|
production(:e) do
|
192
203
|
clause('NUM') {|n| n}
|
193
|
-
|
204
|
+
|
194
205
|
clause('e PLS e') { |e0, _, e1| e0 + e1 }
|
195
206
|
clause('e SUB e') { |e0, _, e1| e0 - e1 }
|
196
207
|
clause('e MUL e') { |e0, _, e1| e0 * e1 }
|
197
208
|
clause('e DIV e') { |e0, _, e1| e0 / e1 }
|
198
|
-
|
209
|
+
|
199
210
|
clause('e PLS ERROR e') { |e0, _, ts, e1| error(ts); e0 + e1 }
|
200
211
|
end
|
201
|
-
|
212
|
+
|
202
213
|
finalize
|
203
214
|
end
|
204
215
|
|
205
216
|
class ELLexer < RLTK::Lexer
|
206
|
-
rule(/\n/)
|
207
|
-
rule(/;/)
|
208
|
-
|
217
|
+
rule(/\n/) { :NEWLINE }
|
218
|
+
rule(/;/) { :SEMI }
|
219
|
+
|
209
220
|
rule(/\s/)
|
210
|
-
|
211
|
-
rule(/[A-Za-z]+/)
|
221
|
+
|
222
|
+
rule(/[A-Za-z]+/) { |t| [:WORD, t] }
|
212
223
|
end
|
213
224
|
|
214
225
|
class ErrorLine < RLTK::Parser
|
215
|
-
|
226
|
+
|
216
227
|
production(:s, 'line*') { |l| l }
|
217
|
-
|
228
|
+
|
218
229
|
production(:line) do
|
219
230
|
clause('NEWLINE') { |_| nil }
|
220
|
-
|
231
|
+
|
221
232
|
clause('WORD+ SEMI NEWLINE') { |w, _, _| w }
|
222
233
|
clause('WORD+ ERROR') { |w, e| error(pos(1).line_number); w }
|
223
234
|
end
|
224
|
-
|
235
|
+
|
225
236
|
finalize
|
226
237
|
end
|
227
|
-
|
238
|
+
|
228
239
|
class UnderscoreParser < RLTK::Parser
|
229
240
|
production(:s, 'A_TOKEN+') { |o| o }
|
230
|
-
|
241
|
+
|
231
242
|
finalize
|
232
243
|
end
|
233
|
-
|
244
|
+
|
234
245
|
class RotatingCalc < RLTK::Parser
|
235
246
|
production(:e) do
|
236
247
|
clause('NUM') {|n| n}
|
237
|
-
|
248
|
+
|
238
249
|
clause('PLS e e') { |_, e0, e1| e0.send(get_op(:+), e1) }
|
239
250
|
clause('SUB e e') { |_, e0, e1| e0.send(get_op(:-), e1) }
|
240
251
|
clause('MUL e e') { |_, e0, e1| e0.send(get_op(:*), e1) }
|
241
252
|
clause('DIV e e') { |_, e0, e1| e0.send(get_op(:/), e1) }
|
242
253
|
end
|
243
|
-
|
254
|
+
|
244
255
|
class Environment < Environment
|
245
256
|
def initialize
|
246
257
|
@map = { :+ => 0, :- => 1, :* => 2, :/ => 3 }
|
247
258
|
@ops = [ :+, :-, :*, :/ ]
|
248
259
|
end
|
249
|
-
|
260
|
+
|
250
261
|
def get_op(orig_op)
|
251
262
|
new_op = @ops[@map[orig_op]]
|
252
|
-
|
263
|
+
|
253
264
|
@ops = @ops[1..-1] << @ops[0]
|
254
|
-
|
265
|
+
|
255
266
|
new_op
|
256
267
|
end
|
257
268
|
end
|
258
|
-
|
269
|
+
|
259
270
|
finalize
|
260
271
|
end
|
261
|
-
|
272
|
+
|
262
273
|
class SelectionParser < RLTK::Parser
|
263
274
|
production(:s, 'A+ .B+') { |bs| bs.inject &:+ }
|
264
|
-
|
275
|
+
|
265
276
|
finalize
|
266
277
|
end
|
267
|
-
|
278
|
+
|
279
|
+
class UselessParser < RLTK::Parser
|
280
|
+
production(:s, 'A+') { |a| a }
|
281
|
+
end
|
282
|
+
|
283
|
+
class TokenHookParser < RLTK::Parser
|
284
|
+
dat :array
|
285
|
+
|
286
|
+
production(:s) do
|
287
|
+
clause('A A A A') { |_| nil }
|
288
|
+
clause('B B B B') { |_| nil }
|
289
|
+
end
|
290
|
+
|
291
|
+
token_hook(:A) { @counter += 1 }
|
292
|
+
token_hook(:B) { @counter += 2 }
|
293
|
+
|
294
|
+
class Environment < Environment
|
295
|
+
attr_reader :counter
|
296
|
+
|
297
|
+
def initialize
|
298
|
+
@counter = 0
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
finalize
|
303
|
+
end
|
304
|
+
|
268
305
|
def test_ambiguous_grammar
|
269
306
|
actual = AmbiguousParser.parse(RLTK::Lexers::Calculator.lex('1 + 2 * 3'), {:accept => :all})
|
270
307
|
assert_equal([7, 9], actual.sort)
|
271
308
|
end
|
272
|
-
|
309
|
+
|
273
310
|
# This test is to ensure that objects placed on the output stack are
|
274
311
|
# cloned when we split the parse stack. This was posted as Issue #17 on
|
275
312
|
# Github.
|
276
313
|
def test_ambiguous_parse_stack
|
277
314
|
assert_equal(1, AmbiguousParseStackParser.parse(ABLexer.lex('ab')).length)
|
278
315
|
end
|
279
|
-
|
316
|
+
|
280
317
|
def test_array_args
|
281
318
|
actual = ArrayCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
282
319
|
assert_equal(3, actual)
|
283
|
-
|
320
|
+
|
284
321
|
actual = ArrayCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 * 2 3'))
|
285
322
|
assert_equal(7, actual)
|
286
|
-
|
323
|
+
|
287
324
|
actual = ArrayCalc.parse(RLTK::Lexers::Calculator.lex('* + 1 2 3'))
|
288
325
|
assert_equal(9, actual)
|
289
326
|
end
|
290
|
-
|
327
|
+
|
328
|
+
def test_construction_error
|
329
|
+
assert_raises(RLTK::ParserConstructionException) do
|
330
|
+
Class.new(RLTK::Parser) do
|
331
|
+
finalize
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
291
336
|
def test_ebnf_parsing
|
292
337
|
################
|
293
338
|
# APlusBParser #
|
294
339
|
################
|
295
|
-
|
340
|
+
|
296
341
|
assert_raises(RLTK::NotInLanguage) { APlusBParser.parse(ABLexer.lex('b')) }
|
297
|
-
|
342
|
+
|
298
343
|
assert_equal(1, APlusBParser.parse(ABLexer.lex('ab')))
|
299
344
|
assert_equal(2, APlusBParser.parse(ABLexer.lex('aab')))
|
300
345
|
assert_equal(3, APlusBParser.parse(ABLexer.lex('aaab')))
|
301
346
|
assert_equal(4, APlusBParser.parse(ABLexer.lex('aaaab')))
|
302
|
-
|
347
|
+
|
303
348
|
####################
|
304
349
|
# AQuestionBParser #
|
305
350
|
####################
|
306
|
-
|
351
|
+
|
307
352
|
assert_raises(RLTK::NotInLanguage) { AQuestionBParser.parse(ABLexer.lex('aab')) }
|
308
353
|
assert_nil(AQuestionBParser.parse(ABLexer.lex('b')))
|
309
354
|
refute_nil(AQuestionBParser.parse(ABLexer.lex('ab')))
|
310
|
-
|
355
|
+
|
311
356
|
################
|
312
357
|
# AStarBParser #
|
313
358
|
################
|
314
|
-
|
359
|
+
|
315
360
|
assert_equal(0, AStarBParser.parse(ABLexer.lex('b')))
|
316
361
|
assert_equal(1, AStarBParser.parse(ABLexer.lex('ab')))
|
317
362
|
assert_equal(2, AStarBParser.parse(ABLexer.lex('aab')))
|
318
363
|
assert_equal(3, AStarBParser.parse(ABLexer.lex('aaab')))
|
319
364
|
assert_equal(4, AStarBParser.parse(ABLexer.lex('aaaab')))
|
320
365
|
end
|
321
|
-
|
366
|
+
|
322
367
|
def test_empty_list
|
323
368
|
####################
|
324
369
|
# EmptyListParser0 #
|
325
370
|
####################
|
326
|
-
|
371
|
+
|
327
372
|
expected = []
|
328
373
|
actual = EmptyListParser0.parse(AlphaLexer.lex(''))
|
329
374
|
assert_equal(expected, actual)
|
330
|
-
|
375
|
+
|
331
376
|
####################
|
332
377
|
# EmptyListParser1 #
|
333
378
|
####################
|
334
|
-
|
379
|
+
|
335
380
|
expected = ['a', 'b', ['c', 'd']]
|
336
381
|
actual = EmptyListParser1.parse(AlphaLexer.lex('a, b, c d'))
|
337
382
|
assert_equal(expected, actual)
|
338
383
|
end
|
339
|
-
|
384
|
+
|
340
385
|
def test_greed
|
341
|
-
|
386
|
+
|
342
387
|
####################
|
343
388
|
# GreedTestParser0 #
|
344
389
|
####################
|
345
|
-
|
390
|
+
|
346
391
|
expected = [nil, 'a']
|
347
392
|
actual = GreedTestParser0.parse(AlphaLexer.lex('a'))
|
348
393
|
assert_equal(expected, actual)
|
349
|
-
|
394
|
+
|
350
395
|
expected = ['a', 'a']
|
351
396
|
actual = GreedTestParser0.parse(AlphaLexer.lex('a a'))
|
352
397
|
assert_equal(expected, actual)
|
353
|
-
|
398
|
+
|
354
399
|
####################
|
355
400
|
# GreedTestParser1 #
|
356
401
|
####################
|
357
|
-
|
402
|
+
|
358
403
|
expected = [nil, nil]
|
359
404
|
actual = GreedTestParser1.parse(AlphaLexer.lex(''))
|
360
405
|
assert_equal(expected, actual)
|
361
|
-
|
406
|
+
|
362
407
|
# expected = ['a', nil]
|
363
408
|
# actual = GreedTestParser1.parse(AlphaLexer.lex('a'))
|
364
409
|
# assert_equal(expected, actual)
|
365
|
-
|
410
|
+
|
366
411
|
expected = ['a', 'a']
|
367
412
|
actual = GreedTestParser1.parse(AlphaLexer.lex('a a'))
|
368
413
|
assert_equal(expected, actual)
|
369
|
-
|
414
|
+
|
370
415
|
####################
|
371
416
|
# GreedTestParser2 #
|
372
417
|
####################
|
373
|
-
|
418
|
+
|
374
419
|
expected = [[], 'a']
|
375
420
|
actual = GreedTestParser2.parse(AlphaLexer.lex('a'))
|
376
421
|
assert_equal(expected, actual)
|
377
|
-
|
422
|
+
|
378
423
|
expected = [['a'], 'a']
|
379
424
|
actual = GreedTestParser2.parse(AlphaLexer.lex('a a'))
|
380
425
|
assert_equal(expected, actual)
|
381
|
-
|
426
|
+
|
382
427
|
expected = [['a', 'a'], 'a']
|
383
428
|
actual = GreedTestParser2.parse(AlphaLexer.lex('a a a'))
|
384
429
|
assert_equal(expected, actual)
|
385
|
-
|
430
|
+
|
386
431
|
####################
|
387
432
|
# GreedTestParser3 #
|
388
433
|
####################
|
389
|
-
|
434
|
+
|
390
435
|
expected = [['a'], 'a']
|
391
436
|
actual = GreedTestParser3.parse(AlphaLexer.lex('a a'))
|
392
437
|
assert_equal(expected, actual)
|
393
|
-
|
438
|
+
|
394
439
|
expected = [['a', 'a'], 'a']
|
395
440
|
actual = GreedTestParser3.parse(AlphaLexer.lex('a a a'))
|
396
441
|
assert_equal(expected, actual)
|
397
442
|
end
|
398
|
-
|
443
|
+
|
444
|
+
def test_ebnf_selector_interplay
|
445
|
+
expected = ['a', ['b', 'b', 'b'], 'a']
|
446
|
+
actual = EBNFSelectorParser.parse(AlphaLexer.lex('abbba'))
|
447
|
+
assert_equal(expected, actual)
|
448
|
+
|
449
|
+
expected = ['a', [], 'a']
|
450
|
+
actual = EBNFSelectorParser.parse(AlphaLexer.lex('aa'))
|
451
|
+
assert_equal(expected, actual)
|
452
|
+
|
453
|
+
expected = ['b', 'b']
|
454
|
+
actual = EBNFSelectorParser.parse(AlphaLexer.lex('bb'))
|
455
|
+
assert_equal(expected, actual)
|
456
|
+
|
457
|
+
expected = ['b', 'b']
|
458
|
+
actual = EBNFSelectorParser.parse(AlphaLexer.lex('bcccccb'))
|
459
|
+
assert_equal(expected, actual)
|
460
|
+
end
|
461
|
+
|
399
462
|
def test_environment
|
400
463
|
actual = RotatingCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
401
464
|
assert_equal(3, actual)
|
402
|
-
|
465
|
+
|
403
466
|
actual = RotatingCalc.parse(RLTK::Lexers::Calculator.lex('/ 1 * 2 3'))
|
404
467
|
assert_equal(7, actual)
|
405
|
-
|
468
|
+
|
406
469
|
actual = RotatingCalc.parse(RLTK::Lexers::Calculator.lex('- + 1 2 3'))
|
407
470
|
assert_equal(9, actual)
|
408
|
-
|
471
|
+
|
409
472
|
parser = RotatingCalc.new
|
410
|
-
|
473
|
+
|
411
474
|
actual = parser.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
412
475
|
assert_equal(3, actual)
|
413
|
-
|
476
|
+
|
414
477
|
actual = parser.parse(RLTK::Lexers::Calculator.lex('/ 1 2'))
|
415
478
|
assert_equal(3, actual)
|
416
479
|
end
|
417
|
-
|
480
|
+
|
418
481
|
def test_error_productions
|
419
|
-
|
482
|
+
|
420
483
|
# Test to see if error reporting is working correctly.
|
421
|
-
|
484
|
+
|
422
485
|
test_string = "first line;\n"
|
423
486
|
test_string += "second line\n"
|
424
487
|
test_string += "third line;\n"
|
425
488
|
test_string += "fourth line\n"
|
426
|
-
|
489
|
+
|
427
490
|
assert_raises(RLTK::HandledError) { ErrorLine.parse(ELLexer.lex(test_string)) }
|
428
|
-
|
491
|
+
|
429
492
|
begin
|
430
493
|
ErrorLine.parse(ELLexer.lex(test_string))
|
431
|
-
|
494
|
+
|
432
495
|
rescue RLTK::HandledError => e
|
433
496
|
assert_equal([2,4], e.errors)
|
434
497
|
end
|
435
|
-
|
498
|
+
|
436
499
|
# Test to see if we can continue parsing after errors are encounterd.
|
437
|
-
|
500
|
+
|
438
501
|
begin
|
439
502
|
ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 + + 1'))
|
440
|
-
|
503
|
+
|
441
504
|
rescue RLTK::HandledError => e
|
442
505
|
assert_equal(1, e.errors.first.length)
|
443
506
|
assert_equal(2, e.result)
|
444
507
|
end
|
445
|
-
|
508
|
+
|
446
509
|
# Test to see if we pop tokens correctly after an error is
|
447
510
|
# encountered.
|
448
|
-
|
511
|
+
|
449
512
|
begin
|
450
513
|
ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 + + + + + + 1'))
|
451
|
-
|
514
|
+
|
452
515
|
rescue RLTK::HandledError => e
|
453
516
|
assert_equal(5, e.errors.first.length)
|
454
517
|
assert_equal(2, e.result)
|
455
518
|
end
|
456
519
|
end
|
457
|
-
|
520
|
+
|
458
521
|
def test_infix_calc
|
459
522
|
actual = RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::Calculator.lex('1 + 2'))
|
460
523
|
assert_equal(3, actual)
|
461
|
-
|
524
|
+
|
462
525
|
actual = RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::Calculator.lex('1 + 2 * 3'))
|
463
526
|
assert_equal(7, actual)
|
464
|
-
|
527
|
+
|
465
528
|
actual = RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::Calculator.lex('(1 + 2) * 3'))
|
466
529
|
assert_equal(9, actual)
|
467
|
-
|
530
|
+
|
468
531
|
assert_raises(RLTK::NotInLanguage) { RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 + 3 *')) }
|
469
532
|
end
|
470
|
-
|
533
|
+
|
471
534
|
def test_input
|
472
535
|
assert_raises(RLTK::BadToken) { RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::EBNF.lex('A B C')) }
|
473
536
|
end
|
474
|
-
|
537
|
+
|
475
538
|
def test_nonempty_list
|
476
539
|
#######################
|
477
540
|
# NonEmptyListParser0 #
|
478
541
|
#######################
|
479
|
-
|
542
|
+
|
480
543
|
expected = ['a']
|
481
544
|
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a'))
|
482
545
|
assert_equal(expected, actual)
|
483
|
-
|
546
|
+
|
484
547
|
expected = ['a', 'a']
|
485
548
|
actual = NonEmptyListParser0.parse(AlphaLexer.lex('a, a'))
|
486
549
|
assert_equal(expected, actual)
|
487
|
-
|
550
|
+
|
488
551
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('')) }
|
489
552
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',')) }
|
490
553
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('aa')) }
|
491
554
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex('a,')) }
|
492
555
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser0.parse(AlphaLexer.lex(',a')) }
|
493
|
-
|
556
|
+
|
494
557
|
#######################
|
495
558
|
# NonEmptyListParser1 #
|
496
559
|
#######################
|
497
|
-
|
560
|
+
|
498
561
|
expected = ['a']
|
499
562
|
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a'))
|
500
563
|
assert_equal(expected, actual)
|
501
|
-
|
564
|
+
|
502
565
|
expected = ['b']
|
503
566
|
actual = NonEmptyListParser1.parse(AlphaLexer.lex('b'))
|
504
567
|
assert_equal(expected, actual)
|
505
|
-
|
568
|
+
|
506
569
|
expected = ['a', 'b', 'a', 'b']
|
507
570
|
actual = NonEmptyListParser1.parse(AlphaLexer.lex('a, b, a, b'))
|
508
571
|
assert_equal(expected, actual)
|
509
|
-
|
572
|
+
|
510
573
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser1.parse(AlphaLexer.lex('a b')) }
|
511
574
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser1.parse(AlphaLexer.lex('a, ')) }
|
512
|
-
|
575
|
+
|
513
576
|
#######################
|
514
577
|
# NonEmptyListParser2 #
|
515
578
|
#######################
|
516
|
-
|
579
|
+
|
517
580
|
expected = ['a']
|
518
581
|
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a'))
|
519
582
|
assert_equal(expected, actual)
|
520
|
-
|
583
|
+
|
521
584
|
expected = ['b']
|
522
585
|
actual = NonEmptyListParser2.parse(AlphaLexer.lex('b'))
|
523
586
|
assert_equal(expected, actual)
|
524
|
-
|
587
|
+
|
525
588
|
expected = [['c', 'd']]
|
526
589
|
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d'))
|
527
590
|
assert_equal(expected, actual)
|
528
|
-
|
591
|
+
|
529
592
|
expected = [['c', 'd'], ['c', 'd']]
|
530
593
|
actual = NonEmptyListParser2.parse(AlphaLexer.lex('c d, c d'))
|
531
594
|
assert_equal(expected, actual)
|
532
|
-
|
595
|
+
|
533
596
|
expected = ['a', 'b', ['c', 'd']]
|
534
597
|
actual = NonEmptyListParser2.parse(AlphaLexer.lex('a, b, c d'))
|
535
598
|
assert_equal(expected, actual)
|
536
|
-
|
599
|
+
|
537
600
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('c')) }
|
538
601
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser2.parse(AlphaLexer.lex('d')) }
|
539
|
-
|
602
|
+
|
540
603
|
#######################
|
541
604
|
# NonEmptyListParser3 #
|
542
605
|
#######################
|
543
|
-
|
606
|
+
|
544
607
|
expected = [['a'], ['a', 'a'], ['a', 'a', 'a']]
|
545
608
|
actual = NonEmptyListParser3.parse(AlphaLexer.lex('a, aa, aaa'))
|
546
609
|
assert_equal(expected, actual)
|
547
|
-
|
610
|
+
|
548
611
|
#######################
|
549
612
|
# NonEmptyListParser4 #
|
550
613
|
#######################
|
551
|
-
|
614
|
+
|
552
615
|
expected = ['a', 'a', 'a']
|
553
616
|
actual = NonEmptyListParser4.parse(AlphaLexer.lex('a a a'))
|
554
617
|
assert_equal(expected, actual)
|
555
|
-
|
618
|
+
|
556
619
|
#######################
|
557
620
|
# NonEmptyListParser5 #
|
558
621
|
#######################
|
559
|
-
|
622
|
+
|
560
623
|
expected = ['a', 'a', 'a']
|
561
624
|
actual = NonEmptyListParser5.parse(AlphaLexer.lex('a b a b c a'))
|
562
625
|
assert_equal(expected, actual)
|
563
|
-
|
626
|
+
|
564
627
|
assert_raises(RLTK::NotInLanguage) { NonEmptyListParser5.parse(AlphaLexer.lex('a b b a')) }
|
565
628
|
end
|
566
|
-
|
629
|
+
|
567
630
|
def test_postfix_calc
|
568
631
|
actual = RLTK::Parsers::PostfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 +'))
|
569
632
|
assert_equal(3, actual)
|
570
|
-
|
633
|
+
|
571
634
|
actual = RLTK::Parsers::PostfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 3 * +'))
|
572
635
|
assert_equal(7, actual)
|
573
|
-
|
636
|
+
|
574
637
|
actual = RLTK::Parsers::PostfixCalc.parse(RLTK::Lexers::Calculator.lex('1 2 + 3 *'))
|
575
638
|
assert_equal(9, actual)
|
576
|
-
|
639
|
+
|
577
640
|
assert_raises(RLTK::NotInLanguage) { RLTK::Parsers::InfixCalc.parse(RLTK::Lexers::Calculator.lex('* + 1 2 3')) }
|
578
641
|
end
|
579
|
-
|
642
|
+
|
580
643
|
def test_prefix_calc
|
581
644
|
actual = RLTK::Parsers::PrefixCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 2'))
|
582
645
|
assert_equal(3, actual)
|
583
|
-
|
646
|
+
|
584
647
|
actual = RLTK::Parsers::PrefixCalc.parse(RLTK::Lexers::Calculator.lex('+ 1 * 2 3'))
|
585
648
|
assert_equal(7, actual)
|
586
|
-
|
649
|
+
|
587
650
|
actual = RLTK::Parsers::PrefixCalc.parse(RLTK::Lexers::Calculator.lex('* + 1 2 3'))
|
588
651
|
assert_equal(9, actual)
|
589
|
-
|
652
|
+
|
590
653
|
assert_raises(RLTK::NotInLanguage) { RLTK::Parsers::PrefixCalc.parse(RLTK::Lexers::Calculator.lex('1 + 2 * 3')) }
|
591
654
|
end
|
592
|
-
|
655
|
+
|
593
656
|
def test_selection_parser
|
594
657
|
actual = SelectionParser.parse(ABLexer.lex('aaabbb'))
|
595
658
|
expected = 6
|
596
|
-
|
659
|
+
|
597
660
|
assert_equal(expected, actual)
|
598
661
|
end
|
599
|
-
|
662
|
+
|
663
|
+
def test_token_hooks
|
664
|
+
parser = TokenHookParser.new
|
665
|
+
|
666
|
+
parser.parse(AlphaLexer.lex('a a a a'))
|
667
|
+
assert_equal(4, parser.env.counter)
|
668
|
+
|
669
|
+
parser.parse(AlphaLexer.lex('b b b b'))
|
670
|
+
assert_equal(12, parser.env.counter)
|
671
|
+
end
|
672
|
+
|
600
673
|
def test_underscore_tokens
|
601
674
|
actual = UnderscoreParser.parse(UnderscoreLexer.lex('abc')).join
|
602
675
|
expected = 'abc'
|
603
|
-
|
676
|
+
|
604
677
|
assert_equal(expected, actual)
|
605
678
|
end
|
606
|
-
|
679
|
+
|
607
680
|
def test_use
|
608
681
|
tmpfile = File.join(Dir.tmpdir, 'usetest')
|
609
|
-
|
682
|
+
|
610
683
|
FileUtils.rm(tmpfile) if File.exist?(tmpfile)
|
611
|
-
|
684
|
+
|
612
685
|
parser0 = Class.new(RLTK::Parser) do
|
613
686
|
production(:a, 'A+') { |a| a.length }
|
614
|
-
|
687
|
+
|
615
688
|
finalize use: tmpfile
|
616
689
|
end
|
617
|
-
|
690
|
+
|
618
691
|
result0 = parser0.parse(ABLexer.lex('a'))
|
619
|
-
|
692
|
+
|
620
693
|
assert(File.exist?(tmpfile), 'Serialized parser file not found.')
|
621
|
-
|
694
|
+
|
622
695
|
parser1 = Class.new(RLTK::Parser) do
|
623
696
|
production(:a, 'A+') { |a| a.length }
|
624
|
-
|
697
|
+
|
625
698
|
finalize use: tmpfile
|
626
699
|
end
|
627
|
-
|
700
|
+
|
628
701
|
result1 = parser1.parse(ABLexer.lex('a'))
|
629
|
-
|
702
|
+
|
630
703
|
assert_equal(result0, result1)
|
631
|
-
|
704
|
+
|
632
705
|
File.unlink(tmpfile)
|
633
706
|
end
|
707
|
+
|
708
|
+
def test_uesless_parser_exception
|
709
|
+
assert_raises(RLTK::UselessParserException) { UselessParser.new }
|
710
|
+
end
|
634
711
|
end
|