rparsec-ruby19 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/rparsec.rb +3 -0
- data/rparsec/context.rb +83 -0
- data/rparsec/error.rb +28 -0
- data/rparsec/expressions.rb +184 -0
- data/rparsec/functors.rb +274 -0
- data/rparsec/id_monad.rb +17 -0
- data/rparsec/keywords.rb +114 -0
- data/rparsec/locator.rb +40 -0
- data/rparsec/misc.rb +130 -0
- data/rparsec/monad.rb +62 -0
- data/rparsec/operators.rb +103 -0
- data/rparsec/parser.rb +894 -0
- data/rparsec/parser_monad.rb +23 -0
- data/rparsec/parsers.rb +623 -0
- data/rparsec/token.rb +43 -0
- data/test/src/expression_test.rb +124 -0
- data/test/src/full_parser_test.rb +95 -0
- data/test/src/functor_test.rb +66 -0
- data/test/src/import.rb +5 -0
- data/test/src/keyword_test.rb +28 -0
- data/test/src/operator_test.rb +21 -0
- data/test/src/parser_test.rb +53 -0
- data/test/src/perf_benchmark.rb +25 -0
- data/test/src/s_expression_test.rb +33 -0
- data/test/src/scratch.rb +41 -0
- data/test/src/simple_monad_test.rb +22 -0
- data/test/src/simple_parser_test.rb +423 -0
- data/test/src/sql.rb +268 -0
- data/test/src/sql_parser.rb +258 -0
- data/test/src/sql_test.rb +128 -0
- data/test/src/tests.rb +13 -0
- metadata +95 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'import'
|
2
|
+
import :parsers, :functors, :expressions
|
3
|
+
require 'parser_test'
|
4
|
+
|
5
|
+
class SExpressionTestCase < ParserTestCase
|
6
|
+
def delim
|
7
|
+
whitespace.many_
|
8
|
+
end
|
9
|
+
def ignore parser
|
10
|
+
parser << delim
|
11
|
+
end
|
12
|
+
def lparen
|
13
|
+
ignore(char('('))
|
14
|
+
end
|
15
|
+
def rparen
|
16
|
+
ignore(char(')'))
|
17
|
+
end
|
18
|
+
def parser
|
19
|
+
expr = nil
|
20
|
+
lazy_expr = lazy{expr}
|
21
|
+
term = number.map(&To_f) | lparen >> lazy_expr << rparen
|
22
|
+
binop = char('+') >> Plus | char('-') >> Minus | char('*') >> Mul | char('/') >> Div
|
23
|
+
binop = ignore binop
|
24
|
+
term = ignore term
|
25
|
+
binary = sequence(binop, lazy_expr, lazy_expr) do |op, e1, e2|
|
26
|
+
op.call(e1, e2)
|
27
|
+
end
|
28
|
+
expr = delim >> (term | binary)
|
29
|
+
end
|
30
|
+
def test1
|
31
|
+
assertParser('- (+ 1 * 2 2.0) (1)', 4, parser)
|
32
|
+
end
|
33
|
+
end
|
data/test/src/scratch.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'strscan'
|
3
|
+
|
4
|
+
puts __FILE__
|
5
|
+
str = ''
|
6
|
+
N = 10
|
7
|
+
N.times{str << 'abc'}
|
8
|
+
|
9
|
+
def scanner
|
10
|
+
StringScanner.new(str)
|
11
|
+
end
|
12
|
+
|
13
|
+
ptn1 = /bc/
|
14
|
+
ptn2 = /^bc/
|
15
|
+
|
16
|
+
Benchmark.bm do |x|
|
17
|
+
x.report("check with anchor") {N.times{StringScanner.new(str).scan(ptn2)}}
|
18
|
+
x.report("check without anchor") {N.times{StringScanner.new(str).scan(ptn1)}}
|
19
|
+
x.report("check_until with anchor") {N.times{StringScanner.new(str).check_until(ptn2)}}
|
20
|
+
x.report("check_until without anchor") {N.times{StringScanner.new(str).check_until(ptn1)}}
|
21
|
+
x.report("=~ with anchor") {N.times{ptn2 =~ str}}
|
22
|
+
x.report("=~ without anchor") {N.times{ptn1 =~ str[N/2,N]}}
|
23
|
+
end
|
24
|
+
|
25
|
+
module X
|
26
|
+
def f1
|
27
|
+
'x1'
|
28
|
+
end
|
29
|
+
def method_missing n
|
30
|
+
puts "missing #{n}"
|
31
|
+
end
|
32
|
+
F2 = 'F2'
|
33
|
+
extend self
|
34
|
+
end
|
35
|
+
puts X::F2
|
36
|
+
#puts X::f1
|
37
|
+
#puts X.f1
|
38
|
+
puts X::F2
|
39
|
+
include X
|
40
|
+
puts F2
|
41
|
+
puts X.F2
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'import'
|
2
|
+
require 'runit/testcase'
|
3
|
+
import :id_monad, :monad
|
4
|
+
|
5
|
+
include RParsec
|
6
|
+
class Idm
|
7
|
+
include Monad
|
8
|
+
MyMonad = IdMonad.new
|
9
|
+
def initialize(v)
|
10
|
+
initMonad(MyMonad, v);
|
11
|
+
end
|
12
|
+
def to_s
|
13
|
+
@obj.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SimpleMonadTest < RUNIT::TestCase
|
18
|
+
def test1
|
19
|
+
assert 20, Idm.new(10).map{|i|i*2}
|
20
|
+
assert 10, Idm.new(10).plus(Idm.new(20))
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,423 @@
|
|
1
|
+
require 'import'
|
2
|
+
import :parsers
|
3
|
+
require 'parser_test'
|
4
|
+
|
5
|
+
class SimpleParserTest < ParserTestCase
|
6
|
+
def testValue
|
7
|
+
assertParser('', 1, value(1))
|
8
|
+
end
|
9
|
+
def testFail
|
10
|
+
assertError('', 'wrong', failure('wrong'))
|
11
|
+
end
|
12
|
+
def testGoodPlusGoodReturnFirst
|
13
|
+
assertParser('', 1, value(1)|value(2))
|
14
|
+
end
|
15
|
+
def testFailPlusGoodReturnGood
|
16
|
+
assertParser('', 2, failure('wrong')|value(2))
|
17
|
+
end
|
18
|
+
def testFailPlusFailFailsWithFirstError
|
19
|
+
assertError('', 'wrong', failure('wrong') | failure('wrong too'))
|
20
|
+
end
|
21
|
+
def testFailBreaksSeq
|
22
|
+
assertError('', 'wrong', failure('wrong') >> value(2))
|
23
|
+
end
|
24
|
+
def testGoodSeqGoodReturnsSecond
|
25
|
+
assertParser('', 2, value(1).seq(value(2)))
|
26
|
+
end
|
27
|
+
def testGoodSeqFailFails
|
28
|
+
assertError('', 'wrong', value(1) >> failure('wrong'))
|
29
|
+
end
|
30
|
+
def testFailSeqFailFails
|
31
|
+
assertError('', 'wrong', failure('wrong') >> failure('wrong too'))
|
32
|
+
end
|
33
|
+
def testMap
|
34
|
+
assertParser('', 2, value(1).map{|x|x*2})
|
35
|
+
relative = Proc.new{|x|x-?a}
|
36
|
+
assertParser('b', 1, char('b').map(&relative))
|
37
|
+
end
|
38
|
+
def testMapOnFailFails
|
39
|
+
assertError('', 'wrong', failure('wrong').map{|x|x*2})
|
40
|
+
end
|
41
|
+
def testBinds
|
42
|
+
assertParser('', 3, value(1).bind do |a|
|
43
|
+
value(2).bind{|b|value(a+b)}
|
44
|
+
end)
|
45
|
+
assertParser('', 2, value(1).repeat(2).bindn do |a,b|
|
46
|
+
value(a+b)
|
47
|
+
end)
|
48
|
+
end
|
49
|
+
def testSum
|
50
|
+
assertParser('', 1, sum(value(1), value(2), value(3)))
|
51
|
+
end
|
52
|
+
def testNestedErrorRecoveredShouldNotAppearInFinalError
|
53
|
+
assertError('', 'wrong too', (failure('wrong') | value(1)) >> failure('wrong too'))
|
54
|
+
end
|
55
|
+
def testSatisfies
|
56
|
+
assertParser('abc', ?a, Parsers.satisfies('a expected'){|c|c==(?a)})
|
57
|
+
assertError('abc', 'b expected', Parsers.satisfies('b expected'){|c|c==(?b)})
|
58
|
+
end
|
59
|
+
def testIs
|
60
|
+
assertParser('abc', ?a, is(?a))
|
61
|
+
assertError('abc', '98 expected', is(?b))
|
62
|
+
end
|
63
|
+
def testIsnt
|
64
|
+
assertParser('abc', ?a, isnt(?b))
|
65
|
+
assertError('abc', '97 unexpected', isnt(?a))
|
66
|
+
assertError('abc', "'b' unexpected", not_char(?b) >> not_char('b'), 1)
|
67
|
+
end
|
68
|
+
def testCharAndEof
|
69
|
+
assertParser('abc', ?c, char('a') >> char('b') >> char('c') >> eof())
|
70
|
+
end
|
71
|
+
def testAre
|
72
|
+
assertParser('abc', 'ab', string('ab'))
|
73
|
+
assertError('abc', '"ab" expected', char('a') >> str('ab'), 1)
|
74
|
+
end
|
75
|
+
def testSequence
|
76
|
+
assertParser('abc', ?c, sequence(char(?a),char('b'),char('c')))
|
77
|
+
a = ?a
|
78
|
+
relative = proc {|c|c-a}
|
79
|
+
parser = sequence(
|
80
|
+
char('c').map(&relative),
|
81
|
+
char('b').map(&relative),
|
82
|
+
char('a').map(&relative)
|
83
|
+
){|x,y,z| x+y+z}
|
84
|
+
assertParser('cba', 3, parser)
|
85
|
+
end
|
86
|
+
def testPlusAutomaticallyRecoverInputConsumption
|
87
|
+
assertError('abc', '"bcd" expected', char('a') >> str('bcd').plus(str('abc')), 1)
|
88
|
+
assertParser('abc', 'abc', char('a') >> str('bcd') | str('abc'))
|
89
|
+
assertError('abc', "'d' expected", char('a') >> char(?b) >> char(?d) | char(?a) >> char(?c) | str('abd'), 2)
|
90
|
+
end
|
91
|
+
def testLookaheadRecoversInputConsumption
|
92
|
+
assertParser('abc', 'abc', (char('x') | char('a') >> str('bcd') | str('abc') | char('x')).lookahead(2))
|
93
|
+
end
|
94
|
+
def testLocator
|
95
|
+
line, col = CodeLocator.new("abc").locate(2)
|
96
|
+
assert_equal([1,3],[line,col])
|
97
|
+
end
|
98
|
+
def testInputConsumptionBiggerThanLookaheadShouldFail
|
99
|
+
assertError('abc', "'d' expected", sum(str('ab')>>char('d'), str('abc')).lookahead(2), 2)
|
100
|
+
end
|
101
|
+
|
102
|
+
def testInputConsumptionDoesNotFailForAlt
|
103
|
+
assertParser('abc', 'abc', alt(str('ab')>>char('d'), str('abc')))
|
104
|
+
end
|
105
|
+
def testAtomParserIsAlwaysRecoverable
|
106
|
+
assertParser('abc', 'abc', (str('ab')>>char('d')).atomize | str('abc'))
|
107
|
+
end
|
108
|
+
def testSimpleNot
|
109
|
+
assertParser('abc', nil, str('abd').not)
|
110
|
+
assertError('abc', 'abc unexpected', str('abc').not)
|
111
|
+
end
|
112
|
+
def testNotDoesntConsume
|
113
|
+
assertParser('abc', 'abc', ~str('abc') | str('abc'))
|
114
|
+
end
|
115
|
+
def testNotDoesntRecoverAlreadyConsumedInputWhenFailingUnlessUsingLookahead
|
116
|
+
parser = (char('a') >> str('abc')).not
|
117
|
+
assertError('abc', '"abc" expected', parser, 1)
|
118
|
+
parser = parser.lookahead(2)
|
119
|
+
assertParser('abc', nil, parser)
|
120
|
+
end
|
121
|
+
def testLookeaheadUsedInPlusCanBeUsedByNot
|
122
|
+
parser = (char('a') >> str('abc') | char('a') >> str('bcd')).lookahead(2)
|
123
|
+
# assertError('abc', '"abc" expected or "bcd" expected', parser, 1)
|
124
|
+
assertError('abc', '"abc" expected', parser, 1)
|
125
|
+
assertParser('abc', nil, parser.not)
|
126
|
+
end
|
127
|
+
def testNotString
|
128
|
+
assertParser('abc', ?a, not_string('abcd'))
|
129
|
+
assertError('abc', '"abc" unexpected', not_string('abc'))
|
130
|
+
assertError('aabcd', '"abc" unexpected', not_string('abc')*2, 1)
|
131
|
+
end
|
132
|
+
def testArent
|
133
|
+
assertError('abc', 'abc unexpected', arent('abc'))
|
134
|
+
assertParser('abc', ?a, arent('abcd'))
|
135
|
+
end
|
136
|
+
def testAmong
|
137
|
+
assertParser('abc', ?a, among(?b, ?a))
|
138
|
+
assertParser('abc', ?a, among('ba'))
|
139
|
+
assertError('abc', "one of [98, 99] expected", among(?b,?c))
|
140
|
+
end
|
141
|
+
def testNotAmong
|
142
|
+
assertError('abc', "one of [98, 97] unexpected", not_among(?b, ?a))
|
143
|
+
assertParser('abc', ?a, not_among(?b,?c))
|
144
|
+
end
|
145
|
+
def testGetIndex
|
146
|
+
assertParser('abc', 1, char('a') >> get_index)
|
147
|
+
end
|
148
|
+
def testMultilineErrorMessage
|
149
|
+
assertError("ab\nc", "'d' expected", str("ab\nc") >> char(?d), 4, 2, 2)
|
150
|
+
end
|
151
|
+
def testExpect
|
152
|
+
assertError("abc", 'word expected', str("abcd").expect("word expected"))
|
153
|
+
end
|
154
|
+
def testExpectDoesntRecover
|
155
|
+
assertError('abc', '"bcd" expected', (char(?a) >> str('bcd')).expect('word expected'), 1)
|
156
|
+
end
|
157
|
+
def testLonger
|
158
|
+
assertParser('abc', 'abc', longer(char('a')>>char('b'), str('abc')))
|
159
|
+
end
|
160
|
+
def testShorter
|
161
|
+
assertParser('abc', ?b, shorter(char('a')>>char('b')>>char('c'), char(?a) >> char(?c), char('a')>>char('b')))
|
162
|
+
end
|
163
|
+
def testLongerReportsDeepestError
|
164
|
+
assertError('abc', "'d' expected",
|
165
|
+
longer(char('a')>>char('b')>>char('d'), char('a')>>char('c')), 2)
|
166
|
+
end
|
167
|
+
def testShorterReportsDeepestError
|
168
|
+
assertError('abc', "'d' expected",
|
169
|
+
shorter(char('a')>>char('b')>>char('d'), char('a')>>char('c')), 2)
|
170
|
+
end
|
171
|
+
def testFollowed
|
172
|
+
assertParser('abc', ?a, char(?a)<<char(?b))
|
173
|
+
end
|
174
|
+
def testEof
|
175
|
+
assertParser('abc', 'abc', str('abc') << eof)
|
176
|
+
assertError('abc', 'EOF expected', str('ab') << eof, 2)
|
177
|
+
end
|
178
|
+
def testAny
|
179
|
+
assertParser('abc', ?a, any)
|
180
|
+
assertError('abc', '', str('abc')<<any, 3)
|
181
|
+
end
|
182
|
+
def testRepeat_
|
183
|
+
assertParser('abc', ?c, any*3)
|
184
|
+
assertError('abc', '', any.repeat_(4), 3)
|
185
|
+
assertError('abc', "'d' expected", any*3 >> char(?d), 3)
|
186
|
+
end
|
187
|
+
def testMany_
|
188
|
+
assertParser('abc', ?c, any.many_)
|
189
|
+
assertParser('abc', ?c, any.many_(3))
|
190
|
+
assertError('abc', "a..b expected", range(?a, ?b).many_(3), 2)
|
191
|
+
assertParser('abc', ?b, range(?a, ?b).many_())
|
192
|
+
assertParser('abc', 1, value(1).many_())
|
193
|
+
assertError('abc', "'b' expected", value(1).many_ >> char(?b))
|
194
|
+
end
|
195
|
+
def testNonDeterministicRepeat_
|
196
|
+
assertParser('abc', ?c, any.repeat_(3,4))
|
197
|
+
assertParser('abc', ?b, any.some_(2))
|
198
|
+
assertError('abc', "min=4, max=3", range(?a, ?b).repeat_(4,3))
|
199
|
+
assertParser('abc', ?b, range(?a, ?b).some_(10))
|
200
|
+
# should we break for infinite loop? they are not really infinite for some.
|
201
|
+
assertError('abc', "'b' expected", value(1).some_(2) >> char(?b))
|
202
|
+
assertParser('abc', nil, any.some_(0))
|
203
|
+
end
|
204
|
+
def testRange
|
205
|
+
assertParser('abc', ?a, range(?a, ?c))
|
206
|
+
assertError('abc', 'd..e expected', range(?d, 'e'))
|
207
|
+
assertError('abc', 'c expected', range(?c, ?b, 'c expected'))
|
208
|
+
end
|
209
|
+
def testBetween
|
210
|
+
assertParser('abc', ?b, char(?a) >> char('b') << char(?c))
|
211
|
+
end
|
212
|
+
def testRepeat
|
213
|
+
assertParser('abc', [?a, ?b, ?c], any.repeat(3))
|
214
|
+
assertParser('abc', [?a, ?b], any.repeat(2))
|
215
|
+
assertParser('abc', [], any.repeat(0))
|
216
|
+
assertError('abc', '', any.repeat(4), 3)
|
217
|
+
assertError('abc', "a..b expected", range(?a, ?b).repeat(3), 2)
|
218
|
+
end
|
219
|
+
def testMany
|
220
|
+
assertParser('abc', [?a, ?b, ?c], any.many)
|
221
|
+
assertParser('abc', [?a, ?b], range(?a, ?b).many)
|
222
|
+
assertError('abc', '', any.many(4), 3)
|
223
|
+
end
|
224
|
+
def testSome
|
225
|
+
assertParser('abc', [?a, ?b, ?c], any.some(3))
|
226
|
+
assertParser('abc', [?a, ?b], any.some(2))
|
227
|
+
assertError('abc', "a..b expected", range(?a,?b).repeat(3,4), 2)
|
228
|
+
assertParser('abc', ?c, any.some(2) >> any)
|
229
|
+
end
|
230
|
+
def testSeparated1
|
231
|
+
assertParser('a,b,c', [?a,?b,?c], any.separated1(char(',')))
|
232
|
+
assertParser('abc', [?a], any.separated1(char(',')))
|
233
|
+
assertError('a,', "'a' expected", char('a').separated1(char(',')), 2)
|
234
|
+
assertError('', '', any.separated1(char(',')))
|
235
|
+
end
|
236
|
+
def testSeparated
|
237
|
+
assertParser('a,b,c', [?a,?b,?c], any.separated(char(',')))
|
238
|
+
assertParser('abc', [?a], any.separated(char(',')))
|
239
|
+
assertError('a,', "'a' expected", char('a').separated(char(',')), 2)
|
240
|
+
assertParser('', [], any.separated(char(',')))
|
241
|
+
end
|
242
|
+
def testValueCalledImplicitlyForOverloadedOrOperator
|
243
|
+
assertParser('abc', 1, char(',')|1)
|
244
|
+
end
|
245
|
+
def testOptional
|
246
|
+
assertParser('abc', nil, char(?,).optional)
|
247
|
+
assertParser('abc', 'xyz', char(?,).optional('xyz'))
|
248
|
+
assertError('abc', "'.' expected", (any.some_(2) >> char(?.)).optional, 2)
|
249
|
+
# assertParser('abc', nil, (any.some_(2) >> char(?.)).optional)
|
250
|
+
end
|
251
|
+
def testThrowCatch
|
252
|
+
assertParser('abc', :hello, (char('a')>>throwp(:hello)).catchp(:hello))
|
253
|
+
assertParser('abc', ?a, char(?a).catchp(:hello))
|
254
|
+
end
|
255
|
+
def testDelimited1
|
256
|
+
assertParser('a,b,c', [?a,?b,?c], any.delimited1(char(',')))
|
257
|
+
assertParser('abc', [?a], any.delimited1(char(',')))
|
258
|
+
assertParser('a,', [?a], char('a').delimited1(char(',')))
|
259
|
+
assertError('', '', any.delimited1(char(',')))
|
260
|
+
assertParser('a,b', ?b, char(?a).delimited1(char(',')) >> char(?b))
|
261
|
+
end
|
262
|
+
def testDelimited
|
263
|
+
assertParser('a,b,c', [?a,?b,?c], any.delimited(char(',')))
|
264
|
+
assertParser('abc', [?a], any.delimited(char(',')))
|
265
|
+
assertParser('a,b,', [?a,?b], range('a', 'b').delimited(char(',')))
|
266
|
+
assertParser('', [], any.delimited(char(',')))
|
267
|
+
assertParser('a,b', ?b, char(?a).delimited(char(',')) >> char(?b))
|
268
|
+
end
|
269
|
+
def testRegexp
|
270
|
+
assertParser('abc', 'ab', regexp('(a|b)+', 'a or b expected'))
|
271
|
+
assertError('abc', 'x or y expected', char('a') >> regexp('(x|y)+', 'x or y expected'), 1)
|
272
|
+
end
|
273
|
+
def testWord
|
274
|
+
assertParser('abc123', 'abc123', word)
|
275
|
+
assertError('1abc123', 'word expected', word)
|
276
|
+
assertParser('abc a123', 'a123', word >> char(' ') >> word)
|
277
|
+
end
|
278
|
+
def testInteger
|
279
|
+
assertParser('123', '123', integer)
|
280
|
+
assertError('a123', 'integer expected', integer)
|
281
|
+
assertError('123a', 'integer expected', integer)
|
282
|
+
end
|
283
|
+
def testNumber
|
284
|
+
assertParser('123.456', '123.456', number)
|
285
|
+
assertParser('0123', '0123', number)
|
286
|
+
assertParser('123.2.5', '5', number >> char('.') >> number)
|
287
|
+
assertError('a123', 'number expected', number)
|
288
|
+
end
|
289
|
+
def testStringCaseInsensitive
|
290
|
+
assertParser('abc', 'abc', string_nocase('ABc'))
|
291
|
+
assertError('abc', "'ABc' expected", string_nocase('A') >> string_nocase('ABc'), 1)
|
292
|
+
end
|
293
|
+
def testFragment
|
294
|
+
assertParser('abc', 'bc', any >> (any*2).fragment)
|
295
|
+
assertError('abc', "'b' expected", any >> (char('b')*2).fragment, 2)
|
296
|
+
end
|
297
|
+
def testToken
|
298
|
+
assertGrammar('abc', 'abcabc', word.token(:word).many, token(:word){|x|x+x})
|
299
|
+
assertGrammar('abc defg', 1, word.token(:word).delimited(char(' ')), token(:word) >> token(:word) >> value(1))
|
300
|
+
assertGrammarError('abc defg', 'integer expected', 'defg', word.token(:word).delimited(char(' ')),
|
301
|
+
token(:word) >> token(:integer), 4)
|
302
|
+
end
|
303
|
+
def testGetIndexFromGrammar
|
304
|
+
assertGrammar('abc cdef', 1, word.token(:word).many, token(:word) >> get_index)
|
305
|
+
end
|
306
|
+
def testWhitespace
|
307
|
+
assertParser(' ', ?\s, whitespace)
|
308
|
+
assertParser("\t", ?\t, whitespace)
|
309
|
+
assertParser("\n", ?\n, whitespace)
|
310
|
+
assertError('abc', 'whitespace expected', whitespace)
|
311
|
+
end
|
312
|
+
def testWhitespaces
|
313
|
+
assertParser(' ', ?\s, whitespaces)
|
314
|
+
assertParser("\n\t", ?\t, whitespaces)
|
315
|
+
assertError("\n \tabc ", "whitespace(s) expected, 'a' at line 2, col 3.", whitespaces >> whitespaces, 3)
|
316
|
+
end
|
317
|
+
def testCommentLineWithLexeme
|
318
|
+
assertParser('#abc', nil, comment_line('#'))
|
319
|
+
code = <<-HERE
|
320
|
+
//HELLO
|
321
|
+
123
|
322
|
+
HERE
|
323
|
+
delim = (comment_line('//')|whitespaces)
|
324
|
+
assertParser(code, ["123"], integer.lexeme(delim) >> eof)
|
325
|
+
assertParser('//', nil, comment_line('//'))
|
326
|
+
code = '123'
|
327
|
+
assertParser(code, ["123"], integer.lexeme(delim) >> eof)
|
328
|
+
|
329
|
+
end
|
330
|
+
def testBlockComment
|
331
|
+
cmt =comment_block('/*', '*/')
|
332
|
+
assertParser('/*abc*/', nil, cmt)
|
333
|
+
assertError('/*abcd ', '"*/" expected', cmt, 7)
|
334
|
+
end
|
335
|
+
def testLazy
|
336
|
+
expr = nil
|
337
|
+
lazy_expr = lazy{expr}
|
338
|
+
expr = integer.map(&To_i) | char('(') >> lazy_expr << char(')')
|
339
|
+
assertParser('123', 123, expr)
|
340
|
+
assertParser('((123))', 123, expr)
|
341
|
+
end
|
342
|
+
def testPeek
|
343
|
+
assertParser('abc', ?a, char('a').peek)
|
344
|
+
assertParser('abc', ?a, char('a').peek.repeat_(2))
|
345
|
+
assertError('abc', "'b' expected", char('a').peek >> char('b'))
|
346
|
+
end
|
347
|
+
def testParserTypeCheck
|
348
|
+
verifyTypeMismatch(:plus, '1st', Parser, String) do
|
349
|
+
char('a').plus('a')
|
350
|
+
end
|
351
|
+
verifyTypeMismatch(:seq, '1st', Parser, String) do
|
352
|
+
char('a').seq('a')
|
353
|
+
end
|
354
|
+
verifyTypeMismatch(:followed, '1st', Parser, String) do
|
355
|
+
char('a') << 'a'
|
356
|
+
end
|
357
|
+
verifyTypeMismatch(:sequence, '2nd', Parser, Fixnum) do
|
358
|
+
sequence(char('a'), 1, 2)
|
359
|
+
end
|
360
|
+
verifyTypeMismatch(:sum, '2nd', Parser, Fixnum) do
|
361
|
+
sum(char('a'), 1, 2)
|
362
|
+
end
|
363
|
+
verifyTypeMismatch(:longest, '2nd', Parser, Fixnum) do
|
364
|
+
longest(char('a'), 1, 2)
|
365
|
+
end
|
366
|
+
verifyTypeMismatch(:shortest, '2nd', Parser, Fixnum) do
|
367
|
+
shortest(char('a'), 1, 2)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
def testSetIndex
|
371
|
+
parser = get_index.bind do |ind|
|
372
|
+
char('a') << set_index(ind)
|
373
|
+
end
|
374
|
+
assertParser('abc', [?a,?a,?a], parser.repeat(3))
|
375
|
+
end
|
376
|
+
def testMapn
|
377
|
+
assertParser('abc', ?b, any.repeat(3).mapn{|a,b,c|c-b+a})
|
378
|
+
end
|
379
|
+
def testWatch
|
380
|
+
i = nil
|
381
|
+
assertParser('abc', ?b, any.repeat_(2) >> watch{i=1});
|
382
|
+
assert_equal(1, i)
|
383
|
+
assertParser('abc', ?b, any.repeat_(2) >>
|
384
|
+
watch{|x|assert_equal(?b, x)}
|
385
|
+
)
|
386
|
+
assertParser('abc', [?a,?b], any.repeat(2) >>
|
387
|
+
watchn do |x,y|
|
388
|
+
assert_equal(?a, x)
|
389
|
+
assert_equal(?b, y)
|
390
|
+
end
|
391
|
+
)
|
392
|
+
assertParser('abc', ?b, any.repeat_(2) >> watch);
|
393
|
+
end
|
394
|
+
def testMapCurrent
|
395
|
+
assertParser('abc', ?b, any >> map{|x|x+1})
|
396
|
+
assertParser('abc', ?a, any >> map)
|
397
|
+
assertParser('abc', ?a, any.map)
|
398
|
+
assertParser('abc', ?a, any.mapn)
|
399
|
+
end
|
400
|
+
def testMapnCurrent
|
401
|
+
assertParser('abc', ?a, any.repeat(2) >> mapn{|a,_|a})
|
402
|
+
assertParser('abc', ?c, any.repeat_(2) >> mapn(&Inc))
|
403
|
+
assertParser('abc', [?a,?b], any.repeat(2) >> mapn)
|
404
|
+
end
|
405
|
+
def verifyTypeMismatch(mtd, n, expected, actual)
|
406
|
+
begin
|
407
|
+
yield
|
408
|
+
assert_fail('should have failed with type mismatch')
|
409
|
+
rescue ArgumentError => e
|
410
|
+
assert_equal("#{actual} assigned to #{expected} for the #{n} argument of #{mtd}.",
|
411
|
+
e.message)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
def verifyArrayTypeMismatch(mtd, n_arg, n_elem, expected, actual)
|
415
|
+
begin
|
416
|
+
yield
|
417
|
+
assert_fail('should have failed with type mismatch')
|
418
|
+
rescue ArgumentError => e
|
419
|
+
assert_equal("#{actual} assigned to #{expected} for the #{n_elem} element of the #{n_arg} argument of #{mtd}.",
|
420
|
+
e.message)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|