Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(399)

Side by Side Diff: packages/petitparser/test/petitparser_test.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 library petitparser.test.core_test;
2
3 import 'dart:math' as math;
4 import 'package:test/test.dart' hide anyOf;
5
6 import 'package:petitparser/petitparser.dart';
7
8 void expectSuccess(Parser parser, dynamic input, dynamic expected,
9 [int position]) {
10 var result = parser.parse(input);
11 expect(result.isSuccess, isTrue);
12 expect(result.isFailure, isFalse);
13 expect(result.value, expected);
14 expect(result.position, position != null ? position : input.length);
15 }
16
17 void expectFailure(Parser parser, dynamic input,
18 [int position = 0, String message]) {
19 var result = parser.parse(input);
20 expect(result.isFailure, isTrue);
21 expect(result.isSuccess, isFalse);
22 expect(result.position, position);
23 if (message != null) {
24 expect(result.message, message);
25 }
26 }
27
28 class ListGrammarDefinition extends GrammarDefinition {
29 start() => ref(list).end();
30 list() => ref(element) & char(',') & ref(list) | ref(element);
31 element() => digit().plus().flatten();
32 }
33
34 class ListParserDefinition extends ListGrammarDefinition {
35 element() => super.element().map((value) => int.parse(value));
36 }
37
38 class TokenizedListGrammarDefinition extends GrammarDefinition {
39 start() => ref(list).end();
40 list() => ref(element) & ref(token, char(',')) & ref(list) | ref(element);
41 element() => ref(token, digit().plus());
42 token(p) => p.flatten().trim();
43 }
44
45 class BuggedGrammarDefinition extends GrammarDefinition {
46 start() => epsilon();
47
48 directRecursion1() => ref(directRecursion1);
49
50 indirectRecursion1() => ref(indirectRecursion2);
51 indirectRecursion2() => ref(indirectRecursion3);
52 indirectRecursion3() => ref(indirectRecursion1);
53
54 delegation1() => ref(delegation2);
55 delegation2() => ref(delegation3);
56 delegation3() => epsilon();
57 }
58
59 class LambdaGrammarDefinition extends GrammarDefinition {
60 start() => ref(expression).end();
61 expression() => ref(variable) | ref(abstraction) | ref(application);
62
63 variable() => (letter() & word().star()).flatten().trim();
64 abstraction() => token('\\') & ref(variable) & token('.') & ref(expression);
65 application() => token('(') & ref(expression) & ref(expression) & token(')');
66
67 token(value) => char(value).trim();
68 }
69
70 class ExpressionGrammarDefinition extends GrammarDefinition {
71 start() => ref(terms).end();
72 terms() => ref(addition) | ref(factors);
73
74 addition() => ref(factors).separatedBy(token(char('+') | char('-')));
75 factors() => ref(multiplication) | ref(power);
76
77 multiplication() => ref(power).separatedBy(token(char('*') | char('/')));
78 power() => ref(primary).separatedBy(char('^').trim());
79
80 primary() => ref(number) | ref(parentheses);
81 number() => token(char('-').optional() & digit().plus() & (char('.') & digit() .plus()).optional());
82
83 parentheses() => token('(') & ref(terms) & token(')');
84 token(value) => value is String ? char(value).trim() : value.flatten().trim();
85 }
86
87 class PluggableCompositeParser extends CompositeParser {
88 final Function _function;
89
90 PluggableCompositeParser(this._function) : super();
91
92 void initialize() {
93 _function(this);
94 }
95 }
96
97 main() {
98 group('parsers', () {
99 test('and()', () {
100 var parser = char('a').and();
101 expectSuccess(parser, 'a', 'a', 0);
102 expectFailure(parser, 'b', 0, '"a" expected');
103 expectFailure(parser, '');
104 });
105 test('or() operator', () {
106 var parser = char('a') | char('b');
107 expectSuccess(parser, 'a', 'a');
108 expectSuccess(parser, 'b', 'b');
109 expectFailure(parser, 'c');
110 expectFailure(parser, '');
111 });
112 test('or() of two', () {
113 var parser = char('a').or(char('b'));
114 expectSuccess(parser, 'a', 'a');
115 expectSuccess(parser, 'b', 'b');
116 expectFailure(parser, 'c');
117 expectFailure(parser, '');
118 });
119 test('or() of three', () {
120 var parser = char('a').or(char('b')).or(char('c'));
121 expectSuccess(parser, 'a', 'a');
122 expectSuccess(parser, 'b', 'b');
123 expectSuccess(parser, 'c', 'c');
124 expectFailure(parser, 'd');
125 expectFailure(parser, '');
126 });
127 test('end()', () {
128 var parser = char('a').end();
129 expectFailure(parser, '', 0, '"a" expected');
130 expectSuccess(parser, 'a', 'a');
131 expectFailure(parser, 'aa', 1, 'end of input expected');
132 });
133 test('epsilon()', () {
134 var parser = epsilon();
135 expectSuccess(parser, '', null);
136 expectSuccess(parser, 'a', null, 0);
137 });
138 test('failure()', () {
139 var parser = failure('failure');
140 expectFailure(parser, '', 0, 'failure');
141 expectFailure(parser, 'a', 0, 'failure');
142 });
143 test('flatten()', () {
144 var parser = digit().plus().flatten();
145 expectFailure(parser, '');
146 expectFailure(parser, 'a');
147 expectSuccess(parser, '1', '1');
148 expectSuccess(parser, '12', '12');
149 expectSuccess(parser, '123', '123');
150 expectSuccess(parser, '1234', '1234');
151 });
152 test('token() on string', () {
153 var parser = digit().plus().token();
154 expectFailure(parser, '');
155 expectFailure(parser, 'a');
156 var token = parser.parse('123').value;
157 expect(token.value, ['1', '2', '3']);
158 expect(token.buffer, '123');
159 expect(token.start, 0);
160 expect(token.stop, 3);
161 expect(token.input, '123');
162 expect(token.length, 3);
163 expect(token.line, 1);
164 expect(token.column, 1);
165 expect(token.toString(), 'Token[1:1]: [1, 2, 3]');
166 });
167 test('token() on list', () {
168 var parser = any().plus().token();
169 var token = parser.parse([1, 2, 3]).value;
170 expect(token.value, [1, 2, 3]);
171 expect(token.buffer, [1, 2, 3]);
172 expect(token.start, 0);
173 expect(token.stop, 3);
174 expect(token.input, [1, 2, 3]);
175 expect(token.length, 3);
176 expect(token.toString(), 'Token[0]: [1, 2, 3]');
177 });
178 test('map()', () {
179 var parser = digit().map((String each) {
180 return each.codeUnitAt(0) - '0'.codeUnitAt(0);
181 });
182 expectSuccess(parser, '1', 1);
183 expectSuccess(parser, '4', 4);
184 expectSuccess(parser, '9', 9);
185 expectFailure(parser, '');
186 expectFailure(parser, 'a');
187 });
188 test('pick(1)', () {
189 var parser = digit().seq(letter()).pick(1);
190 expectSuccess(parser, '1a', 'a');
191 expectSuccess(parser, '2b', 'b');
192 expectFailure(parser, '');
193 expectFailure(parser, '1', 1, 'letter expected');
194 expectFailure(parser, '12', 1, 'letter expected');
195 });
196 test('pick(-1)', () {
197 var parser = digit().seq(letter()).pick(-1);
198 expectSuccess(parser, '1a', 'a');
199 expectSuccess(parser, '2b', 'b');
200 expectFailure(parser, '');
201 expectFailure(parser, '1', 1, 'letter expected');
202 expectFailure(parser, '12', 1, 'letter expected');
203 });
204 test('permute([1, 0])', () {
205 var parser = digit().seq(letter()).permute([1, 0]);
206 expectSuccess(parser, '1a', ['a', '1']);
207 expectSuccess(parser, '2b', ['b', '2']);
208 expectFailure(parser, '');
209 expectFailure(parser, '1', 1, 'letter expected');
210 expectFailure(parser, '12', 1, 'letter expected');
211 });
212 test('permute([-1, 0])', () {
213 var parser = digit().seq(letter()).permute([-1, 0]);
214 expectSuccess(parser, '1a', ['a', '1']);
215 expectSuccess(parser, '2b', ['b', '2']);
216 expectFailure(parser, '');
217 expectFailure(parser, '1', 1, 'letter expected');
218 expectFailure(parser, '12', 1, 'letter expected');
219 });
220 test('not()', () {
221 var parser = char('a').not('not "a" expected');
222 expectFailure(parser, 'a', 0, 'not "a" expected');
223 expectSuccess(parser, 'b', null, 0);
224 expectSuccess(parser, '', null);
225 });
226 test('neg()', () {
227 var parser = digit().neg('no digit expected');
228 expectFailure(parser, '1', 0, 'no digit expected');
229 expectFailure(parser, '9', 0, 'no digit expected');
230 expectSuccess(parser, 'a', 'a');
231 expectSuccess(parser, ' ', ' ');
232 expectFailure(parser, '', 0, 'input expected');
233 });
234 test('optional()', () {
235 var parser = char('a').optional();
236 expectSuccess(parser, 'a', 'a');
237 expectSuccess(parser, 'b', null, 0);
238 expectSuccess(parser, '', null);
239 });
240 test('plus()', () {
241 var parser = char('a').plus();
242 expectFailure(parser, '', 0, '"a" expected');
243 expectSuccess(parser, 'a', ['a']);
244 expectSuccess(parser, 'aa', ['a', 'a']);
245 expectSuccess(parser, 'aaa', ['a', 'a', 'a']);
246 });
247 test('plusGreedy()', () {
248 var parser = word().plusGreedy(digit());
249 expectFailure(parser, '', 0, 'letter or digit expected');
250 expectFailure(parser, 'a', 1, 'digit expected');
251 expectFailure(parser, 'ab', 1, 'digit expected');
252 expectFailure(parser, '1', 1, 'digit expected');
253 expectSuccess(parser, 'a1', ['a'], 1);
254 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
255 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
256 expectSuccess(parser, '12', ['1'], 1);
257 expectSuccess(parser, 'a12', ['a', '1'], 2);
258 expectSuccess(parser, 'ab12', ['a', 'b', '1'], 3);
259 expectSuccess(parser, 'abc12', ['a', 'b', 'c', '1'], 4);
260 expectSuccess(parser, '123', ['1', '2'], 2);
261 expectSuccess(parser, 'a123', ['a', '1', '2'], 3);
262 expectSuccess(parser, 'ab123', ['a', 'b', '1', '2'], 4);
263 expectSuccess(parser, 'abc123', ['a', 'b', 'c', '1', '2'], 5);
264 });
265 test('plusLazy()', () {
266 var parser = word().plusLazy(digit());
267 expectFailure(parser, '');
268 expectFailure(parser, 'a', 1, 'digit expected');
269 expectFailure(parser, 'ab', 2, 'digit expected');
270 expectFailure(parser, '1', 1, 'digit expected');
271 expectSuccess(parser, 'a1', ['a'], 1);
272 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
273 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
274 expectSuccess(parser, '12', ['1'], 1);
275 expectSuccess(parser, 'a12', ['a'], 1);
276 expectSuccess(parser, 'ab12', ['a', 'b'], 2);
277 expectSuccess(parser, 'abc12', ['a', 'b', 'c'], 3);
278 expectSuccess(parser, '123', ['1'], 1);
279 expectSuccess(parser, 'a123', ['a'], 1);
280 expectSuccess(parser, 'ab123', ['a', 'b'], 2);
281 expectSuccess(parser, 'abc123', ['a', 'b', 'c'], 3);
282 });
283 test('times()', () {
284 var parser = char('a').times(2);
285 expectFailure(parser, '', 0, '"a" expected');
286 expectFailure(parser, 'a', 1, '"a" expected');
287 expectSuccess(parser, 'aa', ['a', 'a']);
288 expectSuccess(parser, 'aaa', ['a', 'a'], 2);
289 });
290 test('repeat()', () {
291 var parser = char('a').repeat(2, 3);
292 expectFailure(parser, '', 0, '"a" expected');
293 expectFailure(parser, 'a', 1, '"a" expected');
294 expectSuccess(parser, 'aa', ['a', 'a']);
295 expectSuccess(parser, 'aaa', ['a', 'a', 'a']);
296 expectSuccess(parser, 'aaaa', ['a', 'a', 'a'], 3);
297 });
298 test('repeat() unbounded', () {
299 var input = new List.filled(100000, 'a');
300 var parser = char('a').repeat(2, unbounded);
301 expectSuccess(parser, input.join(), input);
302 });
303 test('repeatGreedy()', () {
304 var parser = word().repeatGreedy(digit(), 2, 4);
305 expectFailure(parser, '', 0, 'letter or digit expected');
306 expectFailure(parser, 'a', 1, 'letter or digit expected');
307 expectFailure(parser, 'ab', 2, 'digit expected');
308 expectFailure(parser, 'abc', 2, 'digit expected');
309 expectFailure(parser, 'abcd', 2, 'digit expected');
310 expectFailure(parser, 'abcde', 2, 'digit expected');
311 expectFailure(parser, '1', 1, 'letter or digit expected');
312 expectFailure(parser, 'a1', 2, 'digit expected');
313 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
314 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
315 expectSuccess(parser, 'abcd1', ['a', 'b', 'c', 'd'], 4);
316 expectFailure(parser, 'abcde1', 2, 'digit expected');
317 expectFailure(parser, '12', 2, 'digit expected');
318 expectSuccess(parser, 'a12', ['a', '1'], 2);
319 expectSuccess(parser, 'ab12', ['a', 'b', '1'], 3);
320 expectSuccess(parser, 'abc12', ['a', 'b', 'c', '1'], 4);
321 expectSuccess(parser, 'abcd12', ['a', 'b', 'c', 'd'], 4);
322 expectFailure(parser, 'abcde12', 2, 'digit expected');
323 expectSuccess(parser, '123', ['1', '2'], 2);
324 expectSuccess(parser, 'a123', ['a', '1', '2'], 3);
325 expectSuccess(parser, 'ab123', ['a', 'b', '1', '2'], 4);
326 expectSuccess(parser, 'abc123', ['a', 'b', 'c', '1'], 4);
327 expectSuccess(parser, 'abcd123', ['a', 'b', 'c', 'd'], 4);
328 expectFailure(parser, 'abcde123', 2, 'digit expected');
329 });
330 test('repeatGreedy() unbounded', () {
331 var inputLetter = new List.filled(100000, 'a');
332 var inputDigit = new List.filled(100000, '1');
333 var parser = word().repeatGreedy(digit(), 2, unbounded);
334 expectSuccess(parser, inputLetter.join() + '1', inputLetter, inputLetter.l ength);
335 expectSuccess(parser, inputDigit.join() + '1', inputDigit, inputDigit.leng th);
336 });
337 test('repeatLazy()', () {
338 var parser = word().repeatLazy(digit(), 2, 4);
339 expectFailure(parser, '', 0, 'letter or digit expected');
340 expectFailure(parser, 'a', 1, 'letter or digit expected');
341 expectFailure(parser, 'ab', 2, 'digit expected');
342 expectFailure(parser, 'abc', 3, 'digit expected');
343 expectFailure(parser, 'abcd', 4, 'digit expected');
344 expectFailure(parser, 'abcde', 4, 'digit expected');
345 expectFailure(parser, '1', 1, 'letter or digit expected');
346 expectFailure(parser, 'a1', 2, 'digit expected');
347 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
348 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
349 expectSuccess(parser, 'abcd1', ['a', 'b', 'c', 'd'], 4);
350 expectFailure(parser, 'abcde1', 4, 'digit expected');
351 expectFailure(parser, '12', 2, 'digit expected');
352 expectSuccess(parser, 'a12', ['a', '1'], 2);
353 expectSuccess(parser, 'ab12', ['a', 'b'], 2);
354 expectSuccess(parser, 'abc12', ['a', 'b', 'c'], 3);
355 expectSuccess(parser, 'abcd12', ['a', 'b', 'c', 'd'], 4);
356 expectFailure(parser, 'abcde12', 4, 'digit expected');
357 expectSuccess(parser, '123', ['1', '2'], 2);
358 expectSuccess(parser, 'a123', ['a', '1'], 2);
359 expectSuccess(parser, 'ab123', ['a', 'b'], 2);
360 expectSuccess(parser, 'abc123', ['a', 'b', 'c'], 3);
361 expectSuccess(parser, 'abcd123', ['a', 'b', 'c', 'd'], 4);
362 expectFailure(parser, 'abcde123', 4, 'digit expected');
363 });
364 test('repeatLazy() unbounded', () {
365 var input = new List.filled(100000, 'a');
366 var parser = word().repeatLazy(digit(), 2, unbounded);
367 expectSuccess(parser, input.join() + '1111', input, input.length);
368 });
369 test('separatedBy()', () {
370 var parser = char('a').separatedBy(char('b'));
371 expectFailure(parser, '', 0, '"a" expected');
372 expectSuccess(parser, 'a', ['a']);
373 expectSuccess(parser, 'ab', ['a'], 1);
374 expectSuccess(parser, 'aba', ['a', 'b', 'a']);
375 expectSuccess(parser, 'abab', ['a', 'b', 'a'], 3);
376 expectSuccess(parser, 'ababa', ['a', 'b', 'a', 'b', 'a']);
377 expectSuccess(parser, 'ababab', ['a', 'b', 'a', 'b', 'a'], 5);
378 });
379 test('separatedBy() without separators', () {
380 var parser = char('a').separatedBy(char('b'), includeSeparators: false);
381 expectFailure(parser, '', 0, '"a" expected');
382 expectSuccess(parser, 'a', ['a']);
383 expectSuccess(parser, 'ab', ['a'], 1);
384 expectSuccess(parser, 'aba', ['a', 'a']);
385 expectSuccess(parser, 'abab', ['a', 'a'], 3);
386 expectSuccess(parser, 'ababa', ['a', 'a', 'a']);
387 expectSuccess(parser, 'ababab', ['a', 'a', 'a'], 5);
388 });
389 test('separatedBy() separator at end', () {
390 var parser =
391 char('a').separatedBy(char('b'), optionalSeparatorAtEnd: true);
392 expectFailure(parser, '', 0, '"a" expected');
393 expectSuccess(parser, 'a', ['a']);
394 expectSuccess(parser, 'ab', ['a', 'b']);
395 expectSuccess(parser, 'aba', ['a', 'b', 'a']);
396 expectSuccess(parser, 'abab', ['a', 'b', 'a', 'b']);
397 expectSuccess(parser, 'ababa', ['a', 'b', 'a', 'b', 'a']);
398 expectSuccess(parser, 'ababab', ['a', 'b', 'a', 'b', 'a', 'b']);
399 });
400 test('separatedBy() without separators & separator at end', () {
401 var parser = char('a').separatedBy(char('b'),
402 includeSeparators: false, optionalSeparatorAtEnd: true);
403 expectFailure(parser, '', 0, '"a" expected');
404 expectSuccess(parser, 'a', ['a']);
405 expectSuccess(parser, 'ab', ['a']);
406 expectSuccess(parser, 'aba', ['a', 'a']);
407 expectSuccess(parser, 'abab', ['a', 'a']);
408 expectSuccess(parser, 'ababa', ['a', 'a', 'a']);
409 expectSuccess(parser, 'ababab', ['a', 'a', 'a']);
410 });
411 test('seq() operator', () {
412 var parser = char('a') & char('b');
413 expectSuccess(parser, 'ab', ['a', 'b']);
414 expectFailure(parser, '');
415 expectFailure(parser, 'x');
416 expectFailure(parser, 'a', 1);
417 expectFailure(parser, 'ax', 1);
418 });
419 test('seq() of two', () {
420 var parser = char('a').seq(char('b'));
421 expectSuccess(parser, 'ab', ['a', 'b']);
422 expectFailure(parser, '');
423 expectFailure(parser, 'x');
424 expectFailure(parser, 'a', 1);
425 expectFailure(parser, 'ax', 1);
426 });
427 test('seq() of three', () {
428 var parser = char('a').seq(char('b')).seq(char('c'));
429 expectSuccess(parser, 'abc', ['a', 'b', 'c']);
430 expectFailure(parser, '');
431 expectFailure(parser, 'x');
432 expectFailure(parser, 'a', 1);
433 expectFailure(parser, 'ax', 1);
434 expectFailure(parser, 'ab', 2);
435 expectFailure(parser, 'abx', 2);
436 });
437 test('star()', () {
438 var parser = char('a').star();
439 expectSuccess(parser, '', []);
440 expectSuccess(parser, 'a', ['a']);
441 expectSuccess(parser, 'aa', ['a', 'a']);
442 expectSuccess(parser, 'aaa', ['a', 'a', 'a']);
443 });
444 test('starGreedy()', () {
445 var parser = word().starGreedy(digit());
446 expectFailure(parser, '', 0, 'digit expected');
447 expectFailure(parser, 'a', 0, 'digit expected');
448 expectFailure(parser, 'ab', 0, 'digit expected');
449 expectSuccess(parser, '1', [], 0);
450 expectSuccess(parser, 'a1', ['a'], 1);
451 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
452 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
453 expectSuccess(parser, '12', ['1'], 1);
454 expectSuccess(parser, 'a12', ['a', '1'], 2);
455 expectSuccess(parser, 'ab12', ['a', 'b', '1'], 3);
456 expectSuccess(parser, 'abc12', ['a', 'b', 'c', '1'], 4);
457 expectSuccess(parser, '123', ['1', '2'], 2);
458 expectSuccess(parser, 'a123', ['a', '1', '2'], 3);
459 expectSuccess(parser, 'ab123', ['a', 'b', '1', '2'], 4);
460 expectSuccess(parser, 'abc123', ['a', 'b', 'c', '1', '2'], 5);
461 });
462 test('starLazy()', () {
463 var parser = word().starLazy(digit());
464 expectFailure(parser, '');
465 expectFailure(parser, 'a', 1, 'digit expected');
466 expectFailure(parser, 'ab', 2, 'digit expected');
467 expectSuccess(parser, '1', [], 0);
468 expectSuccess(parser, 'a1', ['a'], 1);
469 expectSuccess(parser, 'ab1', ['a', 'b'], 2);
470 expectSuccess(parser, 'abc1', ['a', 'b', 'c'], 3);
471 expectSuccess(parser, '12', [], 0);
472 expectSuccess(parser, 'a12', ['a'], 1);
473 expectSuccess(parser, 'ab12', ['a', 'b'], 2);
474 expectSuccess(parser, 'abc12', ['a', 'b', 'c'], 3);
475 expectSuccess(parser, '123', [], 0);
476 expectSuccess(parser, 'a123', ['a'], 1);
477 expectSuccess(parser, 'ab123', ['a', 'b'], 2);
478 expectSuccess(parser, 'abc123', ['a', 'b', 'c'], 3);
479 });
480 test('trim()', () {
481 var parser = char('a').trim();
482 expectSuccess(parser, 'a', 'a');
483 expectSuccess(parser, ' a', 'a');
484 expectSuccess(parser, 'a ', 'a');
485 expectSuccess(parser, ' a ', 'a');
486 expectSuccess(parser, ' a', 'a');
487 expectSuccess(parser, 'a ', 'a');
488 expectSuccess(parser, ' a ', 'a');
489 expectFailure(parser, '', 0, '"a" expected');
490 expectFailure(parser, 'b', 0, '"a" expected');
491 expectFailure(parser, ' b', 1, '"a" expected');
492 expectFailure(parser, ' b', 2, '"a" expected');
493 });
494 test('trim() both', () {
495 var parser = char('a').trim(char('*'));
496 expectSuccess(parser, 'a', 'a');
497 expectSuccess(parser, '*a', 'a');
498 expectSuccess(parser, 'a*', 'a');
499 expectSuccess(parser, '*a*', 'a');
500 expectSuccess(parser, '**a', 'a');
501 expectSuccess(parser, 'a**', 'a');
502 expectSuccess(parser, '**a**', 'a');
503 expectFailure(parser, '', 0, '"a" expected');
504 expectFailure(parser, 'b', 0, '"a" expected');
505 expectFailure(parser, '*b', 1, '"a" expected');
506 expectFailure(parser, '**b', 2, '"a" expected');
507 });
508 test('trim() left/right', () {
509 var parser = char('a').trim(char('*'), char('#'));
510 expectSuccess(parser, 'a', 'a');
511 expectSuccess(parser, '*a', 'a');
512 expectSuccess(parser, 'a#', 'a');
513 expectSuccess(parser, '*a#', 'a');
514 expectSuccess(parser, '**a', 'a');
515 expectSuccess(parser, 'a##', 'a');
516 expectSuccess(parser, '**a##', 'a');
517 expectFailure(parser, '', 0, '"a" expected');
518 expectFailure(parser, 'b', 0, '"a" expected');
519 expectFailure(parser, '*b', 1, '"a" expected');
520 expectFailure(parser, '**b', 2, '"a" expected');
521 expectFailure(parser, '#a', 0, '"a" expected');
522 expectSuccess(parser, 'a*', 'a', 1);
523 });
524 test('undefined()', () {
525 var parser = undefined();
526 expectFailure(parser, '', 0, 'undefined parser');
527 expectFailure(parser, 'a', 0, 'undefined parser');
528 parser.set(char('a'));
529 expectSuccess(parser, 'a', 'a');
530 });
531 test('setable()', () {
532 var parser = char('a').settable();
533 expectSuccess(parser, 'a', 'a');
534 expectFailure(parser, 'b', 0, '"a" expected');
535 expectFailure(parser, '');
536 });
537 });
538 group('characters', () {
539 test('anyOf()', () {
540 var parser = anyOf('uncopyrightable');
541 expectSuccess(parser, 'c', 'c');
542 expectSuccess(parser, 'g', 'g');
543 expectSuccess(parser, 'h', 'h');
544 expectSuccess(parser, 'i', 'i');
545 expectSuccess(parser, 'o', 'o');
546 expectSuccess(parser, 'p', 'p');
547 expectSuccess(parser, 'r', 'r');
548 expectSuccess(parser, 't', 't');
549 expectSuccess(parser, 'y', 'y');
550 expectFailure(parser, 'x', 0, 'any of "uncopyrightable" expected');
551 });
552 test('noneOf()', () {
553 var parser = noneOf('uncopyrightable');
554 expectSuccess(parser, 'x', 'x');
555 expectFailure(parser, 'c', 0, 'none of "uncopyrightable" expected');
556 expectFailure(parser, 'g', 0, 'none of "uncopyrightable" expected');
557 expectFailure(parser, 'h', 0, 'none of "uncopyrightable" expected');
558 expectFailure(parser, 'i', 0, 'none of "uncopyrightable" expected');
559 expectFailure(parser, 'o', 0, 'none of "uncopyrightable" expected');
560 expectFailure(parser, 'p', 0, 'none of "uncopyrightable" expected');
561 expectFailure(parser, 'r', 0, 'none of "uncopyrightable" expected');
562 expectFailure(parser, 't', 0, 'none of "uncopyrightable" expected');
563 expectFailure(parser, 'y', 0, 'none of "uncopyrightable" expected');
564 });
565 test('char() with number', () {
566 var parser = char(97, 'lowercase a');
567 expectSuccess(parser, 'a', 'a');
568 expectFailure(parser, 'b', 0, 'lowercase a');
569 expectFailure(parser, '');
570 });
571 test('char() invalid', () {
572 expect(() => char('ab'), throwsArgumentError);
573 });
574 test('digit()', () {
575 var parser = digit();
576 expectSuccess(parser, '1', '1');
577 expectSuccess(parser, '9', '9');
578 expectFailure(parser, 'a', 0, 'digit expected');
579 expectFailure(parser, '');
580 });
581 test('letter()', () {
582 var parser = letter();
583 expectSuccess(parser, 'a', 'a');
584 expectSuccess(parser, 'X', 'X');
585 expectFailure(parser, '0', 0, 'letter expected');
586 expectFailure(parser, '');
587 });
588 test('lowercase()', () {
589 var parser = lowercase();
590 expectSuccess(parser, 'a', 'a');
591 expectSuccess(parser, 'z', 'z');
592 expectFailure(parser, 'A', 0, 'lowercase letter expected');
593 expectFailure(parser, '0', 0, 'lowercase letter expected');
594 expectFailure(parser, '');
595 });
596 test('pattern() with single', () {
597 var parser = pattern('abc');
598 expectSuccess(parser, 'a', 'a');
599 expectSuccess(parser, 'b', 'b');
600 expectSuccess(parser, 'c', 'c');
601 expectFailure(parser, 'd', 0, '[abc] expected');
602 expectFailure(parser, '');
603 });
604 test('pattern() with range', () {
605 var parser = pattern('a-c');
606 expectSuccess(parser, 'a', 'a');
607 expectSuccess(parser, 'b', 'b');
608 expectSuccess(parser, 'c', 'c');
609 expectFailure(parser, 'd', 0, '[a-c] expected');
610 expectFailure(parser, '');
611 });
612 test('pattern() with overlapping range', () {
613 var parser = pattern('b-da-c');
614 expectSuccess(parser, 'a', 'a');
615 expectSuccess(parser, 'b', 'b');
616 expectSuccess(parser, 'c', 'c');
617 expectSuccess(parser, 'd', 'd');
618 expectFailure(parser, 'e', 0, '[b-da-c] expected');
619 expectFailure(parser, '', 0, '[b-da-c] expected');
620 });
621 test('pattern() with adjacent range', () {
622 var parser = pattern('c-ea-c');
623 expectSuccess(parser, 'a', 'a');
624 expectSuccess(parser, 'b', 'b');
625 expectSuccess(parser, 'c', 'c');
626 expectSuccess(parser, 'd', 'd');
627 expectSuccess(parser, 'e', 'e');
628 expectFailure(parser, 'f', 0, '[c-ea-c] expected');
629 expectFailure(parser, '', 0, '[c-ea-c] expected');
630 });
631 test('pattern() with prefix range', () {
632 var parser = pattern('a-ea-c');
633 expectSuccess(parser, 'a', 'a');
634 expectSuccess(parser, 'b', 'b');
635 expectSuccess(parser, 'c', 'c');
636 expectSuccess(parser, 'd', 'd');
637 expectSuccess(parser, 'e', 'e');
638 expectFailure(parser, 'f', 0, '[a-ea-c] expected');
639 expectFailure(parser, '', 0, '[a-ea-c] expected');
640 });
641 test('pattern() with postfix range', () {
642 var parser = pattern('a-ec-e');
643 expectSuccess(parser, 'a', 'a');
644 expectSuccess(parser, 'b', 'b');
645 expectSuccess(parser, 'c', 'c');
646 expectSuccess(parser, 'd', 'd');
647 expectSuccess(parser, 'e', 'e');
648 expectFailure(parser, 'f', 0, '[a-ec-e] expected');
649 expectFailure(parser, '', 0, '[a-ec-e] expected');
650 });
651 test('pattern() with repeated range', () {
652 var parser = pattern('a-ea-e');
653 expectSuccess(parser, 'a', 'a');
654 expectSuccess(parser, 'b', 'b');
655 expectSuccess(parser, 'c', 'c');
656 expectSuccess(parser, 'd', 'd');
657 expectSuccess(parser, 'e', 'e');
658 expectFailure(parser, 'f', 0, '[a-ea-e] expected');
659 expectFailure(parser, '', 0, '[a-ea-e] expected');
660 });
661 test('pattern() with composed range', () {
662 var parser = pattern('ac-df-');
663 expectSuccess(parser, 'a', 'a');
664 expectSuccess(parser, 'c', 'c');
665 expectSuccess(parser, 'd', 'd');
666 expectSuccess(parser, 'f', 'f');
667 expectSuccess(parser, '-', '-');
668 expectFailure(parser, 'b', 0, '[ac-df-] expected');
669 expectFailure(parser, 'e', 0, '[ac-df-] expected');
670 expectFailure(parser, 'g', 0, '[ac-df-] expected');
671 expectFailure(parser, '');
672 });
673 test('pattern() with negated single', () {
674 var parser = pattern('^a');
675 expectSuccess(parser, 'b', 'b');
676 expectFailure(parser, 'a', 0, '[^a] expected');
677 expectFailure(parser, '');
678 });
679 test('pattern() with negated range', () {
680 var parser = pattern('^a-c');
681 expectSuccess(parser, 'd', 'd');
682 expectFailure(parser, 'a', 0, '[^a-c] expected');
683 expectFailure(parser, 'b', 0, '[^a-c] expected');
684 expectFailure(parser, 'c', 0, '[^a-c] expected');
685 expectFailure(parser, '');
686 });
687 test('range()', () {
688 var parser = range('e', 'o');
689 expectSuccess(parser, 'e', 'e');
690 expectSuccess(parser, 'i', 'i');
691 expectSuccess(parser, 'o', 'o');
692 expectFailure(parser, 'p', 0, 'e..o expected');
693 expectFailure(parser, 'd', 0, 'e..o expected');
694 expectFailure(parser, '');
695 });
696 test('uppercase()', () {
697 var parser = uppercase();
698 expectSuccess(parser, 'A', 'A');
699 expectSuccess(parser, 'Z', 'Z');
700 expectFailure(parser, 'a', 0, 'uppercase letter expected');
701 expectFailure(parser, '0', 0, 'uppercase letter expected');
702 expectFailure(parser, '');
703 });
704 test('whitespace()', () {
705 var parser = whitespace();
706 expectSuccess(parser, ' ', ' ');
707 expectSuccess(parser, '\t', '\t');
708 expectSuccess(parser, '\r', '\r');
709 expectSuccess(parser, '\f', '\f');
710 expectFailure(parser, 'z', 0, 'whitespace expected');
711 expectFailure(parser, '');
712 });
713 test('whitespace() unicode', () {
714 var string = new String.fromCharCodes([
715 0x09,
716 0x0A,
717 0x0B,
718 0x0C,
719 0x0D,
720 0x20,
721 0x85,
722 0xA0,
723 0x1680,
724 0x180E,
725 0x2000,
726 0x2001,
727 0x2002,
728 0x2003,
729 0x2004,
730 0x2005,
731 0x2006,
732 0x2007,
733 0x2008,
734 0x2009,
735 0x200A,
736 0x2028,
737 0x2029,
738 0x202F,
739 0x205F,
740 0x3000,
741 0xFEFF
742 ]);
743 var parser = whitespace().star().flatten().end();
744 expectSuccess(parser, string, string);
745 });
746 test('word()', () {
747 var parser = word();
748 expectSuccess(parser, 'a', 'a');
749 expectSuccess(parser, 'z', 'z');
750 expectSuccess(parser, 'A', 'A');
751 expectSuccess(parser, 'Z', 'Z');
752 expectSuccess(parser, '0', '0');
753 expectSuccess(parser, '9', '9');
754 expectSuccess(parser, '_', '_');
755 expectFailure(parser, '-', 0, 'letter or digit expected');
756 expectFailure(parser, '');
757 });
758 });
759 group('predicates', () {
760 test('any()', () {
761 var parser = any();
762 expectSuccess(parser, 'a', 'a');
763 expectSuccess(parser, 'b', 'b');
764 expectFailure(parser, '', 0, 'input expected');
765 });
766 test('anyIn()', () {
767 var parser = anyIn(['a', 'b']);
768 expectSuccess(parser, 'a', 'a');
769 expectSuccess(parser, 'b', 'b');
770 expectFailure(parser, 'c');
771 expectFailure(parser, '');
772 });
773 test('string()', () {
774 var parser = string('foo');
775 expectSuccess(parser, 'foo', 'foo');
776 expectFailure(parser, '');
777 expectFailure(parser, 'f');
778 expectFailure(parser, 'fo');
779 expectFailure(parser, 'Foo');
780 });
781 test('stringIgnoreCase()', () {
782 var parser = stringIgnoreCase('foo');
783 expectSuccess(parser, 'foo', 'foo');
784 expectSuccess(parser, 'FOO', 'FOO');
785 expectSuccess(parser, 'fOo', 'fOo');
786 expectFailure(parser, '');
787 expectFailure(parser, 'f');
788 expectFailure(parser, 'Fo');
789 });
790 });
791 group('token', () {
792 var parser = any().map((value) => value.codeUnitAt(0)).token().star();
793 var buffer = '1\r12\r\n123\n1234';
794 var result = parser.parse(buffer).value;
795 test('value', () {
796 var expected = [49, 13, 49, 50, 13, 10, 49, 50, 51, 10, 49, 50, 51, 52];
797 expect(result.map((token) => token.value), expected);
798 });
799 test('buffer', () {
800 var expected = new List.filled(buffer.length, buffer);
801 expect(result.map((token) => token.buffer), expected);
802 });
803 test('start', () {
804 var expected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
805 expect(result.map((token) => token.start), expected);
806 });
807 test('stop', () {
808 var expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
809 expect(result.map((token) => token.stop), expected);
810 });
811 test('length', () {
812 var expected = new List.filled(buffer.length, 1);
813 expect(result.map((token) => token.length), expected);
814 });
815 test('line', () {
816 var expected = [1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4];
817 expect(result.map((token) => token.line), expected);
818 });
819 test('column', () {
820 var expected = [1, 2, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4];
821 expect(result.map((token) => token.column), expected);
822 });
823 test('input', () {
824 var expected = ['1', '\r', '1', '2', '\r', '\n', '1', '2', '3', '\n', '1', '2', '3', '4'];
825 expect(result.map((token) => token.input), expected);
826 });
827 test('unique', () {
828 expect(new Set.from(result).length, result.length);
829 });
830 test('equals', () {
831 for (var i = 0; i < result.length; i++) {
832 for (var j = 0; j < result.length; j++) {
833 var condition = i == j ? isTrue : isFalse;
834 expect(result[i] == result[j], condition);
835 expect(result[i].hashCode == result[j].hashCode, condition);
836 }
837 }
838 });
839 });
840 group('context', () {
841 var buffer = 'a\nc';
842 var context = new Context(buffer, 0);
843 test('context', () {
844 expect(context.buffer, buffer);
845 expect(context.position, 0);
846 expect(context.toString(), 'Context[1:1]');
847 });
848 test('success', () {
849 var success = context.success('result');
850 expect(success.buffer, buffer);
851 expect(success.position, 0);
852 expect(success.value, 'result');
853 expect(success.message, isNull);
854 expect(success.isSuccess, isTrue);
855 expect(success.isFailure, isFalse);
856 expect(success.toString(), 'Success[1:1]: result');
857 });
858 test('success with position', () {
859 var success = context.success('result', 2);
860 expect(success.buffer, buffer);
861 expect(success.position, 2);
862 expect(success.value, 'result');
863 expect(success.message, isNull);
864 expect(success.isSuccess, isTrue);
865 expect(success.isFailure, isFalse);
866 expect(success.toString(), 'Success[2:1]: result');
867 });
868 test('failure', () {
869 var failure = context.failure('error');
870 expect(failure.buffer, buffer);
871 expect(failure.position, 0);
872 try {
873 failure.value;
874 fail('Expected ParserError to be thrown');
875 } on ParserError catch (error) {
876 expect(error.failure, same(failure));
877 expect(error.toString(), 'error at 1:1');
878 }
879 expect(failure.message, 'error');
880 expect(failure.isSuccess, isFalse);
881 expect(failure.isFailure, isTrue);
882 expect(failure.toString(), 'Failure[1:1]: error');
883 });
884 test('failure with position', () {
885 var failure = context.failure('error', 2);
886 expect(failure.buffer, buffer);
887 expect(failure.position, 2);
888 try {
889 failure.value;
890 fail('Expected ParserError to be thrown');
891 } on ParserError catch (error) {
892 expect(error.failure, same(failure));
893 expect(error.toString(), 'error at 2:1');
894 }
895 expect(failure.message, 'error');
896 expect(failure.isSuccess, isFalse);
897 expect(failure.isFailure, isTrue);
898 expect(failure.toString(), 'Failure[2:1]: error');
899 });
900 });
901 group('parsing', () {
902 test('parse()', () {
903 var parser = char('a');
904 expect(parser.parse('a').isSuccess, isTrue);
905 expect(parser.parse('b').isSuccess, isFalse);
906 });
907 test('accept()', () {
908 var parser = char('a');
909 expect(parser.accept('a'), isTrue);
910 expect(parser.accept('b'), isFalse);
911 });
912 test('matches()', () {
913 var parser = digit().seq(digit()).flatten();
914 expect(parser.matches('a123b45'), ['12', '23', '45']);
915 });
916 test('matchesSkipping()', () {
917 var parser = digit().seq(digit()).flatten();
918 expect(parser.matchesSkipping('a123b45'), ['12', '45']);
919 });
920 });
921 group('examples', () {
922 final identifier = letter().seq(word().star()).flatten();
923 final number = char('-')
924 .optional()
925 .seq(digit().plus())
926 .seq(char('.').seq(digit().plus()).optional())
927 .flatten();
928 final quoted = char('"')
929 .seq(char('"').neg().star())
930 .seq(char('"'))
931 .flatten();
932 final keyword = string('return')
933 .seq(whitespace().plus().flatten())
934 .seq(identifier.or(number).or(quoted))
935 .map((list) => list.last);
936 final javadoc = string('/**')
937 .seq(string('*/').neg().star())
938 .seq(string('*/'))
939 .flatten();
940 test('valid identifier', () {
941 expectSuccess(identifier, 'a', 'a');
942 expectSuccess(identifier, 'a1', 'a1');
943 expectSuccess(identifier, 'a12', 'a12');
944 expectSuccess(identifier, 'ab', 'ab');
945 expectSuccess(identifier, 'a1b', 'a1b');
946 });
947 test('incomplete identifier', () {
948 expectSuccess(identifier, 'a=', 'a', 1);
949 expectSuccess(identifier, 'a1-', 'a1', 2);
950 expectSuccess(identifier, 'a12+', 'a12', 3);
951 expectSuccess(identifier, 'ab ', 'ab', 2);
952 });
953 test('invalid identifier', () {
954 expectFailure(identifier, '', 0, 'letter expected');
955 expectFailure(identifier, '1', 0, 'letter expected');
956 expectFailure(identifier, '1a', 0, 'letter expected');
957 });
958 test('positive number', () {
959 expectSuccess(number, '1', '1');
960 expectSuccess(number, '12', '12');
961 expectSuccess(number, '12.3', '12.3');
962 expectSuccess(number, '12.34', '12.34');
963 });
964 test('negative number', () {
965 expectSuccess(number, '-1', '-1');
966 expectSuccess(number, '-12', '-12');
967 expectSuccess(number, '-12.3', '-12.3');
968 expectSuccess(number, '-12.34', '-12.34');
969 });
970 test('incomplete number', () {
971 expectSuccess(number, '1..', '1', 1);
972 expectSuccess(number, '12-', '12', 2);
973 expectSuccess(number, '12.3.', '12.3', 4);
974 expectSuccess(number, '12.34.', '12.34', 5);
975 });
976 test('invalid number', () {
977 expectFailure(number, '', 0, 'digit expected');
978 expectFailure(number, '-', 1, 'digit expected');
979 expectFailure(number, '-x', 1, 'digit expected');
980 expectFailure(number, '.', 0, 'digit expected');
981 expectFailure(number, '.1', 0, 'digit expected');
982 });
983 test('valid string', () {
984 expectSuccess(quoted, '""', '""');
985 expectSuccess(quoted, '"a"', '"a"');
986 expectSuccess(quoted, '"ab"', '"ab"');
987 expectSuccess(quoted, '"abc"', '"abc"');
988 });
989 test('incomplete string', () {
990 expectSuccess(quoted, '""x', '""', 2);
991 expectSuccess(quoted, '"a"x', '"a"', 3);
992 expectSuccess(quoted, '"ab"x', '"ab"', 4);
993 expectSuccess(quoted, '"abc"x', '"abc"', 5);
994 });
995 test('invalid string', () {
996 expectFailure(quoted, '"', 1, '""" expected');
997 expectFailure(quoted, '"a', 2, '""" expected');
998 expectFailure(quoted, '"ab', 3, '""" expected');
999 expectFailure(quoted, 'a"', 0, '""" expected');
1000 expectFailure(quoted, 'ab"', 0, '""" expected');
1001 });
1002 test('return statement', () {
1003 expectSuccess(keyword, 'return f', 'f');
1004 expectSuccess(keyword, 'return f', 'f');
1005 expectSuccess(keyword, 'return foo', 'foo');
1006 expectSuccess(keyword, 'return foo', 'foo');
1007 expectSuccess(keyword, 'return 1', '1');
1008 expectSuccess(keyword, 'return 1', '1');
1009 expectSuccess(keyword, 'return -2.3', '-2.3');
1010 expectSuccess(keyword, 'return -2.3', '-2.3');
1011 expectSuccess(keyword, 'return "a"', '"a"');
1012 expectSuccess(keyword, 'return "a"', '"a"');
1013 });
1014 test('invalid statement', () {
1015 expectFailure(keyword, 'retur f', 0, 'return expected');
1016 expectFailure(keyword, 'return1', 6, 'whitespace expected');
1017 expectFailure(keyword, 'return _', 8, '""" expected');
1018 });
1019 test('javadoc', () {
1020 expectSuccess(javadoc, '/** foo */', '/** foo */');
1021 expectSuccess(javadoc, '/** * * */', '/** * * */');
1022 });
1023 });
1024 group('copying, matching, replacing', () {
1025 void verify(Parser parser) {
1026 var copy = parser.copy();
1027 // check copying
1028 expect(copy, isNot(same(parser)));
1029 expect(copy.toString(), parser.toString());
1030 expect(copy.runtimeType, parser.runtimeType);
1031 expect(copy.children,
1032 pairwiseCompare(parser.children, identical, 'same children'));
1033 // check equality
1034 expect(copy.isEqualTo(copy), isTrue);
1035 expect(parser.isEqualTo(parser), isTrue);
1036 expect(copy.isEqualTo(parser), isTrue);
1037 expect(parser.isEqualTo(copy), isTrue);
1038 // check replacing
1039 var replaced = new List();
1040 for (var i = 0; i < copy.children.length; i++) {
1041 var source = copy.children[i],
1042 target = any();
1043 copy.replace(source, target);
1044 expect(copy.children[i], same(target));
1045 replaced.add(target);
1046 }
1047 expect(copy.children,
1048 pairwiseCompare(replaced, identical, 'replaced children'));
1049 }
1050 test('any()', () => verify(any()));
1051 test('and()', () => verify(digit().and()));
1052 test('char()', () => verify(char('a')));
1053 test('digit()', () => verify(digit()));
1054 test('delegate()', () => verify(new DelegateParser(any())));
1055 test('end()', () => verify(digit().end()));
1056 test('epsilon()', () => verify(epsilon()));
1057 test('failure()', () => verify(failure()));
1058 test('flatten()', () => verify(digit().flatten()));
1059 test('map()', () => verify(digit().map((a) => a)));
1060 test('not()', () => verify(digit().not()));
1061 test('optional()', () => verify(digit().optional()));
1062 test('or()', () => verify(digit().or(word())));
1063 test('plus()', () => verify(digit().plus()));
1064 test('plusGreedy()', () => verify(digit().plusGreedy(word())));
1065 test('plusLazy()', () => verify(digit().plusLazy(word())));
1066 test('repeat()', () => verify(digit().repeat(2, 3)));
1067 test('repeatGreedy()', () => verify(digit().repeatGreedy(word(), 2, 3)));
1068 test('repeatLazy()', () => verify(digit().repeatLazy(word(), 2, 3)));
1069 test('seq()', () => verify(digit().seq(word())));
1070 test('setable()', () => verify(digit().settable()));
1071 test('star()', () => verify(digit().star()));
1072 test('starGreedy()', () => verify(digit().starGreedy(word())));
1073 test('starLazy()', () => verify(digit().starLazy(word())));
1074 test('string()', () => verify(string('ab')));
1075 test('times()', () => verify(digit().times(2)));
1076 test('token()', () => verify(digit().token()));
1077 test('trim()', () => verify(digit().trim(char('a'), char('b'))));
1078 test('undefined()', () => verify(undefined()));
1079 });
1080 group('regressions', () {
1081 test('flatten().trim()', () {
1082 var parser = word().plus().flatten().trim();
1083 expectSuccess(parser, 'ab1', 'ab1');
1084 expectSuccess(parser, ' ab1 ', 'ab1');
1085 expectSuccess(parser, ' ab1 ', 'ab1');
1086 });
1087 test('trim().flatten()', () {
1088 var parser = word().plus().trim().flatten();
1089 expectSuccess(parser, 'ab1', 'ab1');
1090 expectSuccess(parser, ' ab1 ', ' ab1 ');
1091 expectSuccess(parser, ' ab1 ', ' ab1 ');
1092 });
1093 });
1094 group('definition', () {
1095 var grammarDefinition = new ListGrammarDefinition();
1096 var parserDefinition = new ListParserDefinition();
1097 var tokenDefinition = new TokenizedListGrammarDefinition();
1098 var buggedDefinition = new BuggedGrammarDefinition();
1099
1100 test('reference without parameters', () {
1101 var firstReference = grammarDefinition.ref(grammarDefinition.start);
1102 var secondReference = grammarDefinition.ref(grammarDefinition.start);
1103 expect(firstReference, isNot(same(secondReference)));
1104 expect(firstReference == secondReference, isTrue);
1105 });
1106 test('reference with different production', () {
1107 var firstReference = grammarDefinition.ref(grammarDefinition.start);
1108 var secondReference = grammarDefinition.ref(grammarDefinition.element);
1109 expect(firstReference, isNot(same(secondReference)));
1110 expect(firstReference == secondReference, isFalse);
1111 });
1112 test('reference with same parameters', () {
1113 var firstReference = grammarDefinition.ref(grammarDefinition.start, 'a');
1114 var secondReference = grammarDefinition.ref(grammarDefinition.start, 'a');
1115 expect(firstReference, isNot(same(secondReference)));
1116 expect(firstReference == secondReference, isTrue);
1117 });
1118 test('reference with different parameters', () {
1119 var firstReference = grammarDefinition.ref(grammarDefinition.start, 'a');
1120 var secondReference = grammarDefinition.ref(grammarDefinition.start, 'b');
1121 expect(firstReference, isNot(same(secondReference)));
1122 expect(firstReference == secondReference, isFalse);
1123 });
1124 test('grammar', () {
1125 var parser = grammarDefinition.build();
1126 expectSuccess(parser, '1,2', ['1', ',', '2']);
1127 expectSuccess(parser, '1,2,3', ['1', ',', ['2', ',', '3']]);
1128 });
1129 test('parser', () {
1130 var parser = parserDefinition.build();
1131 expectSuccess(parser, '1,2', [1, ',', 2]);
1132 expectSuccess(parser, '1,2,3', [1, ',', [2, ',', 3]]);
1133 });
1134 test('token', () {
1135 var parser = tokenDefinition.build();
1136 expectSuccess(parser, '1, 2', ['1', ',', '2']);
1137 expectSuccess(parser, '1, 2, 3', ['1', ',', ['2', ',', '3']]);
1138 });
1139 test('direct recursion', () {
1140 expect(() =>
1141 buggedDefinition.build(start: buggedDefinition.directRecursion1),
1142 throwsStateError);
1143 });
1144 test('indirect recursion', () {
1145 expect(() => buggedDefinition.build(
1146 start: buggedDefinition.indirectRecursion1), throwsStateError);
1147 expect(() => buggedDefinition.build(
1148 start: buggedDefinition.indirectRecursion2), throwsStateError);
1149 expect(() => buggedDefinition.build(
1150 start: buggedDefinition.indirectRecursion3), throwsStateError);
1151 });
1152 test('delegation', () {
1153 expect(buggedDefinition.build(
1154 start: buggedDefinition.delegation1) is EpsilonParser, isTrue);
1155 expect(buggedDefinition.build(
1156 start: buggedDefinition.delegation2) is EpsilonParser, isTrue);
1157 expect(buggedDefinition.build(
1158 start: buggedDefinition.delegation3) is EpsilonParser, isTrue);
1159 });
1160 test('lambda example', () {
1161 var definition = new LambdaGrammarDefinition();
1162 var parser = definition.build();
1163 expect(parser.accept('x'), isTrue);
1164 expect(parser.accept('xy'), isTrue);
1165 expect(parser.accept('x12'), isTrue);
1166 expect(parser.accept('\\x.y'), isTrue);
1167 expect(parser.accept('\\x.\\y.z'), isTrue);
1168 expect(parser.accept('(x x)'), isTrue);
1169 expect(parser.accept('(x y)'), isTrue);
1170 expect(parser.accept('(x (y z))'), isTrue);
1171 expect(parser.accept('((x y) z)'), isTrue);
1172 });
1173 test('expression example', () {
1174 var definition = new ExpressionGrammarDefinition();
1175 var parser = definition.build();
1176 expect(parser.accept('1'), isTrue);
1177 expect(parser.accept('12'), isTrue);
1178 expect(parser.accept('1.23'), isTrue);
1179 expect(parser.accept('-12.3'), isTrue);
1180 expect(parser.accept('1 + 2'), isTrue);
1181 expect(parser.accept('1 + 2 + 3'), isTrue);
1182 expect(parser.accept('1 - 2'), isTrue);
1183 expect(parser.accept('1 - 2 - 3'), isTrue);
1184 expect(parser.accept('1 * 2'), isTrue);
1185 expect(parser.accept('1 * 2 * 3'), isTrue);
1186 expect(parser.accept('1 / 2'), isTrue);
1187 expect(parser.accept('1 / 2 / 3'), isTrue);
1188 expect(parser.accept('1 ^ 2'), isTrue);
1189 expect(parser.accept('1 ^ 2 ^ 3'), isTrue);
1190 expect(parser.accept('1 + (2 * 3)'), isTrue);
1191 expect(parser.accept('(1 + 2) * 3'), isTrue);
1192 });
1193 });
1194 group('expression', () {
1195 Parser build({attachAction: true}) {
1196 var action = attachAction ? (func) => func : (func) => null;
1197 var root = failure().settable();
1198 var builder = new ExpressionBuilder();
1199 builder.group()
1200 ..primitive(char('(').trim().seq(root).seq(char(')').trim()).pick(1))
1201 ..primitive(digit().plus().seq(char('.').seq(digit().plus()).optional())
1202 .flatten().trim().map((a) => double.parse(a)));
1203 builder.group()
1204 ..prefix(char('-').trim(), action((op, a) => -a));
1205 builder.group()
1206 ..postfix(string('++').trim(), action((a, op) => ++a))
1207 ..postfix(string('--').trim(), action((a, op) => --a));
1208 builder.group()
1209 ..right(char('^').trim(), action((a, op, b) => math.pow(a, b)));
1210 builder.group()
1211 ..left(char('*').trim(), action((a, op, b) => a * b))
1212 ..left(char('/').trim(), action((a, op, b) => a / b));
1213 builder.group()
1214 ..left(char('+').trim(), action((a, op, b) => a + b))
1215 ..left(char('-').trim(), action((a, op, b) => a - b));
1216 root.set(builder.build());
1217 return root.end();
1218 }
1219 var epsilon = 1e-5;
1220 var evaluator = build(attachAction: true);
1221 var parser = build(attachAction: false);
1222 test('number', () {
1223 expect(evaluator.parse('0').value, closeTo(0, epsilon));
1224 expect(evaluator.parse('0.0').value, closeTo(0, epsilon));
1225 expect(evaluator.parse('1').value, closeTo(1, epsilon));
1226 expect(evaluator.parse('1.2').value, closeTo(1.2, epsilon));
1227 expect(evaluator.parse('34').value, closeTo(34, epsilon));
1228 expect(evaluator.parse('34.7').value, closeTo(34.7, epsilon));
1229 expect(evaluator.parse('56.78').value, closeTo(56.78, epsilon));
1230 });
1231 test('number negative', () {
1232 expect(evaluator.parse('-1').value, closeTo(-1, epsilon));
1233 expect(evaluator.parse('-1.2').value, closeTo(-1.2, epsilon));
1234 });
1235 test('number parse', () {
1236 expect(parser.parse('0').value, 0);
1237 expect(parser.parse('-1').value, ['-', 1]);
1238 });
1239 test('add', () {
1240 expect(evaluator.parse('1 + 2').value, closeTo(3, epsilon));
1241 expect(evaluator.parse('2 + 1').value, closeTo(3, epsilon));
1242 expect(evaluator.parse('1 + 2.3').value, closeTo(3.3, epsilon));
1243 expect(evaluator.parse('2.3 + 1').value, closeTo(3.3, epsilon));
1244 expect(evaluator.parse('1 + -2').value, closeTo(-1, epsilon));
1245 expect(evaluator.parse('-2 + 1').value, closeTo(-1, epsilon));
1246 });
1247 test('add many', () {
1248 expect(evaluator.parse('1').value, closeTo(1, epsilon));
1249 expect(evaluator.parse('1 + 2').value, closeTo(3, epsilon));
1250 expect(evaluator.parse('1 + 2 + 3').value, closeTo(6, epsilon));
1251 expect(evaluator.parse('1 + 2 + 3 + 4').value, closeTo(10, epsilon));
1252 expect(evaluator.parse('1 + 2 + 3 + 4 + 5').value, closeTo(15, epsilon));
1253 });
1254 test('add parse', () {
1255 expect(parser.parse('1 + 2 + 3').value, [[1, '+', 2], '+', 3]);
1256 });
1257 test('sub', () {
1258 expect(evaluator.parse('1 - 2').value, closeTo(-1, epsilon));
1259 expect(evaluator.parse('1.2 - 1.2').value, closeTo(0, epsilon));
1260 expect(evaluator.parse('1 - -2').value, closeTo(3, epsilon));
1261 expect(evaluator.parse('-1 - -2').value, closeTo(1, epsilon));
1262 });
1263 test('sub many', () {
1264 expect(evaluator.parse('1').value, closeTo(1, epsilon));
1265 expect(evaluator.parse('1 - 2').value, closeTo(-1, epsilon));
1266 expect(evaluator.parse('1 - 2 - 3').value, closeTo(-4, epsilon));
1267 expect(evaluator.parse('1 - 2 - 3 - 4').value, closeTo(-8, epsilon));
1268 expect(evaluator.parse('1 - 2 - 3 - 4 - 5').value, closeTo(-13, epsilon));
1269 });
1270 test('sub parse', () {
1271 expect(parser.parse('1 - 2 - 3').value, [[1, '-', 2], '-', 3]);
1272 });
1273 test('mul', () {
1274 expect(evaluator.parse('2 * 3').value, closeTo(6, epsilon));
1275 expect(evaluator.parse('2 * -4').value, closeTo(-8, epsilon));
1276 });
1277 test('mul many', () {
1278 expect(evaluator.parse('1 * 2').value, closeTo(2, epsilon));
1279 expect(evaluator.parse('1 * 2 * 3').value, closeTo(6, epsilon));
1280 expect(evaluator.parse('1 * 2 * 3 * 4').value, closeTo(24, epsilon));
1281 expect(evaluator.parse('1 * 2 * 3 * 4 * 5').value, closeTo(120, epsilon));
1282 });
1283 test('mul parse', () {
1284 expect(parser.parse('1 * 2 * 3').value, [[1, '*', 2], '*', 3]);
1285 });
1286 test('div', () {
1287 expect(evaluator.parse('12 / 3').value, closeTo(4, epsilon));
1288 expect(evaluator.parse('-16 / -4').value, closeTo(4, epsilon));
1289 });
1290 test('div many', () {
1291 expect(evaluator.parse('100 / 2').value, closeTo(50, epsilon));
1292 expect(evaluator.parse('100 / 2 / 2').value, closeTo(25, epsilon));
1293 expect(evaluator.parse('100 / 2 / 2 / 5').value, closeTo(5, epsilon));
1294 expect(evaluator.parse('100 / 2 / 2 / 5 / 5').value, closeTo(1, epsilon));
1295 });
1296 test('mul parse', () {
1297 expect(parser.parse('1 / 2 / 3').value, [[1, '/', 2], '/', 3]);
1298 });
1299 test('pow', () {
1300 expect(evaluator.parse('2 ^ 3').value, closeTo(8, epsilon));
1301 expect(evaluator.parse('-2 ^ 3').value, closeTo(-8, epsilon));
1302 expect(evaluator.parse('-2 ^ -3').value, closeTo(-0.125, epsilon));
1303 });
1304 test('pow many', () {
1305 expect(evaluator.parse('4 ^ 3').value, closeTo(64, epsilon));
1306 expect(evaluator.parse('4 ^ 3 ^ 2').value, closeTo(262144, epsilon));
1307 expect(evaluator.parse('4 ^ 3 ^ 2 ^ 1').value, closeTo(262144, epsilon));
1308 expect(evaluator.parse('4 ^ 3 ^ 2 ^ 1 ^ 0').value, closeTo(262144, epsilon ));
1309 });
1310 test('pow parse', () {
1311 expect(parser.parse('1 ^ 2 ^ 3').value, [1, '^', [2, '^', 3]]);
1312 });
1313 test('parens', () {
1314 expect(evaluator.parse('(1)').value, closeTo(1, epsilon));
1315 expect(evaluator.parse('(1 + 2)').value, closeTo(3, epsilon));
1316 expect(evaluator.parse('((1))').value, closeTo(1, epsilon));
1317 expect(evaluator.parse('((1 + 2))').value, closeTo(3, epsilon));
1318 expect(evaluator.parse('2 * (3 + 4)').value, closeTo(14, epsilon));
1319 expect(evaluator.parse('(2 + 3) * 4').value, closeTo(20, epsilon));
1320 expect(evaluator.parse('6 / (2 + 4)').value, closeTo(1, epsilon));
1321 expect(evaluator.parse('(2 + 6) / 2').value, closeTo(4, epsilon));
1322 });
1323 test('priority', () {
1324 expect(evaluator.parse('2 * 3 + 4').value, closeTo(10, epsilon));
1325 expect(evaluator.parse('2 + 3 * 4').value, closeTo(14, epsilon));
1326 expect(evaluator.parse('6 / 3 + 4').value, closeTo(6, epsilon));
1327 expect(evaluator.parse('2 + 6 / 2').value, closeTo(5, epsilon));
1328 });
1329 test('priority parse', () {
1330 expect(parser.parse('2 * 3 + 4').value, [[2.0, '*', 3.0], '+', 4.0]);
1331 expect(parser.parse('2 + 3 * 4').value, [2.0, '+', [3.0, '*', 4.0]]);
1332 });
1333 test('postfix add', () {
1334 expect(evaluator.parse('0++').value, closeTo(1, epsilon));
1335 expect(evaluator.parse('0++++').value, closeTo(2, epsilon));
1336 expect(evaluator.parse('0++++++').value, closeTo(3, epsilon));
1337 expect(evaluator.parse('0+++1').value, closeTo(2, epsilon));
1338 expect(evaluator.parse('0+++++1').value, closeTo(3, epsilon));
1339 expect(evaluator.parse('0+++++++1').value, closeTo(4, epsilon));
1340 });
1341 test('postfix sub', () {
1342 expect(evaluator.parse('1--').value, closeTo(0, epsilon));
1343 expect(evaluator.parse('2----').value, closeTo(0, epsilon));
1344 expect(evaluator.parse('3------').value, closeTo(0, epsilon));
1345 expect(evaluator.parse('2---1').value, closeTo(0, epsilon));
1346 expect(evaluator.parse('3-----1').value, closeTo(0, epsilon));
1347 expect(evaluator.parse('4-------1').value, closeTo(0, epsilon));
1348 });
1349 test('prefix negate', () {
1350 expect(evaluator.parse('1').value, closeTo(1, epsilon));
1351 expect(evaluator.parse('-1').value, closeTo(-1, epsilon));
1352 expect(evaluator.parse('--1').value, closeTo(1, epsilon));
1353 expect(evaluator.parse('---1').value, closeTo(-1, epsilon));
1354 });
1355 });
1356 group('tutorial', () {
1357 test('simple grammar', () {
1358 var id = letter().seq(letter().or(digit()).star());
1359 var id1 = id.parse('yeah');
1360 var id2 = id.parse('f12');
1361 expect(id1.value, ['y', ['e', 'a', 'h']]);
1362 expect(id2.value, ['f', ['1', '2']]);
1363 var id3 = id.parse('123');
1364 expect(id3.message, 'letter expected');
1365 expect(id3.position, 0);
1366 expect(id.accept('foo'), isTrue);
1367 expect(id.accept('123'), isFalse);
1368 });
1369 test('different parsers', () {
1370 var id = letter().seq(word().star()).flatten();
1371 var matches = id.matchesSkipping('foo 123 bar4');
1372 expect(matches, ['foo', 'bar4']);
1373 });
1374 test('complicated grammar', () {
1375 var number = digit().plus().flatten().trim().map(int.parse);
1376 var term = undefined();
1377 var prod = undefined();
1378 var prim = undefined();
1379 term.set(prod.seq(char('+').trim()).seq(term).map((values) {
1380 return values[0] + values[2];
1381 }).or(prod));
1382 prod.set(prim.seq(char('*').trim()).seq(prod).map((values) {
1383 return values[0] * values[2];
1384 }).or(prim));
1385 prim.set(char('(').trim().seq(term).seq(char(')'.trim())).map((values) {
1386 return values[1];
1387 }).or(number));
1388 var start = term.end();
1389 expect(7, start.parse('1 + 2 * 3').value);
1390 expect(9, start.parse('(1 + 2) * 3').value);
1391 });
1392 });
1393 group('composite (deprecated)', () {
1394 test('start', () {
1395 var parser = new PluggableCompositeParser((self) {
1396 self.def('start', char('a'));
1397 });
1398 expectSuccess(parser, 'a', 'a', 1);
1399 expectFailure(parser, 'b', 0, '"a" expected');
1400 expectFailure(parser, '');
1401 });
1402 test('circular', () {
1403 var parser = new PluggableCompositeParser((self) {
1404 self.def('start', self.ref('loop').or(char('b')));
1405 self.def('loop', char('a').seq(self.ref('start')));
1406 });
1407 expect(parser.accept('b'), isTrue);
1408 expect(parser.accept('ab'), isTrue);
1409 expect(parser.accept('aab'), isTrue);
1410 expect(parser.accept('aaab'), isTrue);
1411 });
1412 test('redefine parser', () {
1413 var parser = new PluggableCompositeParser((self) {
1414 self.def('start', char('b'));
1415 self.redef('start', char('a'));
1416 });
1417 expectSuccess(parser, 'a', 'a', 1);
1418 expectFailure(parser, 'b', 0, '"a" expected');
1419 expectFailure(parser, '');
1420 });
1421 test('redefine function', () {
1422 var parser = new PluggableCompositeParser((self) {
1423 var b = char('b');
1424 self.def('start', b);
1425 self.redef('start', (old) {
1426 expect(b, old);
1427 return char('a');
1428 });
1429 });
1430 expectSuccess(parser, 'a', 'a', 1);
1431 expectFailure(parser, 'b', 0, '"a" expected');
1432 expectFailure(parser, '');
1433 });
1434 test('define completed', () {
1435 var parser = new PluggableCompositeParser((self) {
1436 self.def('start', char('a'));
1437 });
1438 expect(() => parser.def('other', char('b')), throws);
1439 expect(() => parser.redef('start', char('b')), throws);
1440 expect(() => parser.action('start', (each) => each), throws);
1441 });
1442 test('reference completed', () {
1443 var parsers = {
1444 'start': char('a'),
1445 'for_b': char('b'),
1446 'for_c': char('c')
1447 };
1448 var parser = new PluggableCompositeParser((self) {
1449 for (var key in parsers.keys) {
1450 self.def(key, parsers[key]);
1451 }
1452 });
1453 for (var key in parsers.keys) {
1454 expect(parsers[key], parser[key]);
1455 expect(parsers[key], parser.ref(key));
1456 }
1457 });
1458 test('reference unknown', () {
1459 var parser = new PluggableCompositeParser((self) {
1460 self.def('start', char('a'));
1461 });
1462 try {
1463 parser.ref('star1');
1464 fail('Expected UndefinedProductionError to be thrown');
1465 } on UndefinedProductionError catch (error) {
1466 expect(error.toString(), 'Undefined production: star1');
1467 }
1468 });
1469 test('duplicated start', () {
1470 new PluggableCompositeParser((self) {
1471 self.def('start', char('a'));
1472 try {
1473 self.def('start', char('b'));
1474 fail('Expected UndefinedProductionError to be thrown');
1475 } on RedefinedProductionError catch (error) {
1476 expect(error.toString(), 'Redefined production: start');
1477 }
1478 });
1479 });
1480 test('undefined start', () {
1481 expect(() => new PluggableCompositeParser((self) {}), throws);
1482 });
1483 test('undefined redef', () {
1484 new PluggableCompositeParser((self) {
1485 self.def('start', char('a'));
1486 expect(() => self.redef('star1', char('b')), throws);
1487 });
1488 });
1489 test('example (lambda)', () {
1490 var parser = new PluggableCompositeParser((self) {
1491 self.def('start', self.ref('expression').end());
1492 self.def('variable', letter().seq(word().star()).flatten().trim());
1493 self.def('expression', self
1494 .ref('variable')
1495 .or(self.ref('abstraction'))
1496 .or(self.ref('application')));
1497 self.def('abstraction', char('\\')
1498 .trim()
1499 .seq(self.ref('variable'))
1500 .seq(char('.').trim())
1501 .seq(self.ref('expression')));
1502 self.def('application', char('(')
1503 .trim()
1504 .seq(self.ref('expression'))
1505 .seq(self.ref('expression'))
1506 .seq(char(')').trim()));
1507 });
1508 expect(parser.accept('x'), isTrue);
1509 expect(parser.accept('xy'), isTrue);
1510 expect(parser.accept('x12'), isTrue);
1511 expect(parser.accept('\\x.y'), isTrue);
1512 expect(parser.accept('\\x.\\y.z'), isTrue);
1513 expect(parser.accept('(x x)'), isTrue);
1514 expect(parser.accept('(x y)'), isTrue);
1515 expect(parser.accept('(x (y z))'), isTrue);
1516 expect(parser.accept('((x y) z)'), isTrue);
1517 });
1518 test('example (expression)', () {
1519 var parser = new PluggableCompositeParser((self) {
1520 self.def('start', self.ref('terms').end());
1521 self.def('terms', self.ref('addition').or(self.ref('factors')));
1522 self.def('addition',
1523 self.ref('factors').separatedBy(char('+').or(char('-')).trim()));
1524 self.def('factors', self.ref('multiplication').or(self.ref('power')));
1525 self.def('multiplication',
1526 self.ref('power').separatedBy(char('*').or(char('/')).trim()));
1527 self.def('power', self.ref('primary').separatedBy(char('^').trim()));
1528 self.def('primary', self.ref('number').or(self.ref('parentheses')));
1529 self.def('number', char('-')
1530 .optional()
1531 .seq(digit().plus())
1532 .seq(char('.').seq(digit().plus()).optional())
1533 .flatten()
1534 .trim());
1535 self.def('parentheses',
1536 char('(').trim().seq(self.ref('terms')).seq(char(')').trim()));
1537 });
1538 expect(parser.accept('1'), isTrue);
1539 expect(parser.accept('12'), isTrue);
1540 expect(parser.accept('1.23'), isTrue);
1541 expect(parser.accept('-12.3'), isTrue);
1542 expect(parser.accept('1 + 2'), isTrue);
1543 expect(parser.accept('1 + 2 + 3'), isTrue);
1544 expect(parser.accept('1 - 2'), isTrue);
1545 expect(parser.accept('1 - 2 - 3'), isTrue);
1546 expect(parser.accept('1 * 2'), isTrue);
1547 expect(parser.accept('1 * 2 * 3'), isTrue);
1548 expect(parser.accept('1 / 2'), isTrue);
1549 expect(parser.accept('1 / 2 / 3'), isTrue);
1550 expect(parser.accept('1 ^ 2'), isTrue);
1551 expect(parser.accept('1 ^ 2 ^ 3'), isTrue);
1552 expect(parser.accept('1 + (2 * 3)'), isTrue);
1553 expect(parser.accept('(1 + 2) * 3'), isTrue);
1554 });
1555 });
1556 }
OLDNEW
« no previous file with comments | « packages/petitparser/test/lisp_test.dart ('k') | packages/petitparser/test/reflection_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698