rparsec-ruby19 1.0
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.
- 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
|