OLD | NEW |
| (Empty) |
1 part of petitparser; | |
2 | |
3 /** | |
4 * Abstract base class of all parsers. | |
5 */ | |
6 abstract class Parser { | |
7 | |
8 /** | |
9 * Primitive method doing the actual parsing. | |
10 * | |
11 * The method is overridden in concrete subclasses to implement the | |
12 * parser specific logic. The methods takes a parse [context] and | |
13 * returns the resulting context, which is either a [Success] or | |
14 * [Failure] context. | |
15 */ | |
16 Result parseOn(Context context); | |
17 | |
18 /** | |
19 * Returns the parse result of the [input]. | |
20 * | |
21 * The implementation creates a default parse context on the input and calls | |
22 * the internal parsing logic of the receiving parser. | |
23 * | |
24 * For example, `letter().plus().parse('abc')` results in an instance of | |
25 * [Success], where [Result.position] is `3` and [Success.value] is | |
26 * `[a, b, c]`. | |
27 * | |
28 * Similarly, `letter().plus().parse('123')` results in an instance of | |
29 * [Failure], where [Result.position] is `0` and [Failure.message] is | |
30 * ['letter expected']. | |
31 */ | |
32 Result parse(input) { | |
33 return parseOn(new Context(input, 0)); | |
34 } | |
35 | |
36 /** | |
37 * Tests if the [input] can be successfully parsed. | |
38 * | |
39 * For example, `letter().plus().accept('abc')` returns `true`, and | |
40 * `letter().plus().accept('123')` returns `false`. | |
41 */ | |
42 bool accept(input) { | |
43 return parse(input).isSuccess; | |
44 } | |
45 | |
46 /** | |
47 * Returns a list of all successful overlapping parses of the [input]. | |
48 * | |
49 * For example, `letter().plus().matches('abc de')` results in the list | |
50 * `[['a', 'b', 'c'], ['b', 'c'], ['c'], ['d', 'e'], ['e']]`. See | |
51 * [Parser.matchesSkipping] to retrieve non-overlapping parse results. | |
52 */ | |
53 Iterable matches(input) { | |
54 var list = new List(); | |
55 and() | |
56 .map((each) => list.add(each)) | |
57 .seq(any()) | |
58 .or(any()) | |
59 .star() | |
60 .parse(input); | |
61 return list; | |
62 } | |
63 | |
64 /** | |
65 * Returns a list of all successful non-overlapping parses of the input. | |
66 * | |
67 * For example, `letter().plus().matchesSkipping('abc de')` results in the | |
68 * list `[['a', 'b', 'c'], ['d', 'e']]`. See [Parser.matches] to retrieve | |
69 * overlapping parse results. | |
70 */ | |
71 Iterable matchesSkipping(input) { | |
72 var list = new List(); | |
73 map((each) => list.add(each)).or(any()).star().parse(input); | |
74 return list; | |
75 } | |
76 | |
77 /** | |
78 * Returns new parser that accepts the receiver, if possible. The resulting | |
79 * parser returns the result of the receiver, or `null` if not applicable. | |
80 * The returned value can be provided as an optional argument [otherwise]. | |
81 * | |
82 * For example, the parser `letter().optional()` accepts a letter as input | |
83 * and returns that letter. When given something else the parser succeeds as | |
84 * well, does not consume anything and returns `null`. | |
85 */ | |
86 Parser optional([otherwise]) => new OptionalParser(this, otherwise); | |
87 | |
88 /** | |
89 * Returns a parser that accepts the receiver zero or more times. The | |
90 * resulting parser returns a list of the parse results of the receiver. | |
91 * | |
92 * This is a greedy and blind implementation that tries to consume as much | |
93 * input as possible and that does not consider what comes afterwards. | |
94 * | |
95 * For example, the parser `letter().star()` accepts the empty string or | |
96 * any sequence of letters and returns a possibly empty list of the parsed | |
97 * letters. | |
98 */ | |
99 Parser star() => repeat(0, unbounded); | |
100 | |
101 /** | |
102 * Returns a parser that parses the receiver zero or more times until it | |
103 * reaches a [limit]. This is a greedy non-blind implementation of the | |
104 * [Parser.star] operator. The [limit] is not consumed. | |
105 */ | |
106 Parser starGreedy(Parser limit) => repeatGreedy(limit, 0, unbounded); | |
107 | |
108 /** | |
109 * Returns a parser that parses the receiver zero or more times until it | |
110 * reaches a [limit]. This is a lazy non-blind implementation of the | |
111 * [Parser.star] operator. The [limit] is not consumed. | |
112 */ | |
113 Parser starLazy(Parser limit) => repeatLazy(limit, 0, unbounded); | |
114 | |
115 /** | |
116 * Returns a parser that accepts the receiver one or more times. The | |
117 * resulting parser returns a list of the parse results of the receiver. | |
118 * | |
119 * This is a greedy and blind implementation that tries to consume as much | |
120 * input as possible and that does not consider what comes afterwards. | |
121 * | |
122 * For example, the parser `letter().plus()` accepts any sequence of | |
123 * letters and returns a list of the parsed letters. | |
124 */ | |
125 Parser plus() => repeat(1, unbounded); | |
126 | |
127 /** | |
128 * Returns a parser that parses the receiver one or more times until it | |
129 * reaches [limit]. This is a greedy non-blind implementation of the | |
130 * [Parser.plus] operator. The [limit] is not consumed. | |
131 */ | |
132 Parser plusGreedy(Parser limit) => repeatGreedy(limit, 1, unbounded); | |
133 | |
134 /** | |
135 * Returns a parser that parses the receiver one or more times until it | |
136 * reaches a [limit]. This is a lazy non-blind implementation of the | |
137 * [Parser.plus] operator. The [limit] is not consumed. | |
138 */ | |
139 Parser plusLazy(Parser limit) => repeatLazy(limit, 1, unbounded); | |
140 | |
141 /** | |
142 * Returns a parser that accepts the receiver between [min] and [max] times. | |
143 * The resulting parser returns a list of the parse results of the receiver. | |
144 * | |
145 * This is a greedy and blind implementation that tries to consume as much | |
146 * input as possible and that does not consider what comes afterwards. | |
147 * | |
148 * For example, the parser `letter().repeat(2, 4)` accepts a sequence of | |
149 * two, three, or four letters and returns the accepted letters as a list. | |
150 */ | |
151 Parser repeat(int min, int max) { | |
152 return new PossessiveRepeatingParser(this, min, max); | |
153 } | |
154 | |
155 /** | |
156 * Returns a parser that parses the receiver at least [min] and at most [max] | |
157 * times until it reaches a [limit]. This is a greedy non-blind implementation
of | |
158 * the [Parser.repeat] operator. The [limit] is not consumed. | |
159 */ | |
160 Parser repeatGreedy(Parser limit, int min, int max) { | |
161 return new GreedyRepeatingParser(this, limit, min, max); | |
162 } | |
163 | |
164 /** | |
165 * Returns a parser that parses the receiver at least [min] and at most [max] | |
166 * times until it reaches a [limit]. This is a lazy non-blind implementation o
f | |
167 * the [Parser.repeat] operator. The [limit] is not consumed. | |
168 */ | |
169 Parser repeatLazy(Parser limit, int min, int max) { | |
170 return new LazyRepeatingParser(this, limit, min, max); | |
171 } | |
172 | |
173 /** | |
174 * Returns a parser that accepts the receiver exactly [count] times. The | |
175 * resulting parser returns a list of the parse results of the receiver. | |
176 * | |
177 * For example, the parser `letter().times(2)` accepts two letters and | |
178 * returns a list of the two parsed letters. | |
179 */ | |
180 Parser times(int count) => repeat(count, count); | |
181 | |
182 /** | |
183 * Returns a parser that accepts the receiver followed by [other]. The | |
184 * resulting parser returns a list of the parse result of the receiver | |
185 * followed by the parse result of [other]. Calling this method on an | |
186 * existing sequence code not nest this sequence into a new one, but | |
187 * instead augments the existing sequence with [other]. | |
188 * | |
189 * For example, the parser `letter().seq(digit()).seq(letter())` accepts a | |
190 * letter followed by a digit and another letter. The parse result of the | |
191 * input string `'a1b'` is the list `['a', '1', 'b']`. | |
192 */ | |
193 Parser seq(Parser other) => new SequenceParser([this, other]); | |
194 | |
195 /** | |
196 * Convenience operator returning a parser that accepts the receiver followed | |
197 * by [other]. See [Parser.seq] for details. | |
198 */ | |
199 Parser operator &(Parser other) => this.seq(other); | |
200 | |
201 /** | |
202 * Returns a parser that accepts the receiver or [other]. The resulting | |
203 * parser returns the parse result of the receiver, if the receiver fails | |
204 * it returns the parse result of [other] (exclusive ordered choice). | |
205 * | |
206 * For example, the parser `letter().or(digit())` accepts a letter or a | |
207 * digit. An example where the order matters is the following choice between | |
208 * overlapping parsers: `letter().or(char('a'))`. In the example the parser | |
209 * `char('a')` will never be activated, because the input is always consumed | |
210 * `letter()`. This can be problematic if the author intended to attach a | |
211 * production action to `char('a')`. | |
212 */ | |
213 Parser or(Parser other) => new ChoiceParser([this, other]); | |
214 | |
215 /** | |
216 * Convenience operator returning a parser that accepts the receiver or | |
217 * [other]. See [Parser.or] for details. | |
218 */ | |
219 Parser operator |(Parser other) => this.or(other); | |
220 | |
221 /** | |
222 * Returns a parser (logical and-predicate) that succeeds whenever the | |
223 * receiver does, but never consumes input. | |
224 * | |
225 * For example, the parser `char('_').and().seq(identifier)` accepts | |
226 * identifiers that start with an underscore character. Since the predicate | |
227 * does not consume accepted input, the parser `identifier` is given the | |
228 * ability to process the complete identifier. | |
229 */ | |
230 Parser and() => new AndParser(this); | |
231 | |
232 /** | |
233 * Returns a parser (logical not-predicate) that succeeds whenever the | |
234 * receiver fails, but never consumes input. | |
235 * | |
236 * For example, the parser `char('_').not().seq(identifier)` accepts | |
237 * identifiers that do not start with an underscore character. If the parser | |
238 * `char('_')` accepts the input, the negation and subsequently the | |
239 * complete parser fails. Otherwise the parser `identifier` is given the | |
240 * ability to process the complete identifier. | |
241 */ | |
242 Parser not([String message]) => new NotParser(this, message); | |
243 | |
244 /** | |
245 * Returns a parser that consumes any input token (character), but the | |
246 * receiver. | |
247 * | |
248 * For example, the parser `letter().neg()` accepts any input but a letter. | |
249 * The parser fails for inputs like `'a'` or `'Z'`, but succeeds for | |
250 * input like `'1'`, `'_'` or `'$'`. | |
251 */ | |
252 Parser neg([String message]) => not(message).seq(any()).pick(1); | |
253 | |
254 /** | |
255 * Returns a parser that discards the result of the receiver, and returns | |
256 * a sub-string of the consumed range in the string/list being parsed. | |
257 * | |
258 * For example, the parser `letter().plus().flatten()` returns `'abc'` | |
259 * for the input `'abc'`. In contrast, the parser `letter().plus()` would | |
260 * return `['a', 'b', 'c']` for the same input instead. | |
261 */ | |
262 Parser flatten() => new FlattenParser(this); | |
263 | |
264 /** | |
265 * Returns a parser that returns a [Token]. The token carries the parsed | |
266 * value of the receiver [Token.value], as well as the consumed input | |
267 * [Token.input] from [Token.start] to [Token.stop] of the input being | |
268 * parsed. | |
269 * | |
270 * For example, the parser `letter().plus().token()` returns the token | |
271 * `Token[start: 0, stop: 3, value: abc]` for the input `'abc'`. | |
272 */ | |
273 Parser token() => new TokenParser(this); | |
274 | |
275 /** | |
276 * Returns a parser that consumes input before and after the receiver. The | |
277 * optional argument is a parser that consumes the excess input. By default | |
278 * `whitespace()` is used. Two arguments can be provided to have different | |
279 * parsers on the [left] and [right] side. | |
280 * | |
281 * For example, the parser `letter().plus().trim()` returns `['a', 'b']` | |
282 * for the input `' ab\n'` and consumes the complete input string. | |
283 */ | |
284 Parser trim([Parser left, Parser right]) { | |
285 if (left == null) left = whitespace(); | |
286 if (right == null) right = left; | |
287 return new TrimmingParser(this, left, right); | |
288 } | |
289 | |
290 /** | |
291 * Returns a parser that succeeds only if the receiver consumes the complete | |
292 * input, otherwise return a failure with the optional [message]. | |
293 * | |
294 * For example, the parser `letter().end()` succeeds on the input `'a'` | |
295 * and fails on `'ab'`. In contrast the parser `letter()` alone would | |
296 * succeed on both inputs, but not consume everything for the second input. | |
297 */ | |
298 Parser end([String message = 'end of input expected']) { | |
299 return new EndOfInputParser(this, message); | |
300 } | |
301 | |
302 /** | |
303 * Returns a parser that points to the receiver, but can be changed to point | |
304 * to something else at a later point in time. | |
305 * | |
306 * For example, the parser `letter().settable()` behaves exactly the same | |
307 * as `letter()`, but it can be replaced with another parser using | |
308 * [SettableParser.set]. | |
309 */ | |
310 SettableParser settable() => new SettableParser(this); | |
311 | |
312 /** | |
313 * Returns a parser that evaluates a [function] as the production action | |
314 * on success of the receiver. | |
315 * | |
316 * For example, the parser `digit().map((char) => int.parse(char))` returns | |
317 * the number `1` for the input string `'1'`. If the delegate fail, the | |
318 * production action is not executed and the failure is passed on. | |
319 */ | |
320 Parser map(Function function) => new ActionParser(this, function); | |
321 | |
322 /** | |
323 * Returns a parser that transform a successful parse result by returning | |
324 * the element at [index] of a list. A negative index can be used to access | |
325 * the elements from the back of the list. | |
326 * | |
327 * For example, the parser `letter().star().pick(-1)` returns the last | |
328 * letter parsed. For the input `'abc'` it returns `'c'`. | |
329 */ | |
330 Parser pick(int index) { | |
331 return this.map((List list) { | |
332 return list[index < 0 ? list.length + index : index]; | |
333 }); | |
334 } | |
335 | |
336 /** | |
337 * Returns a parser that transforms a successful parse result by returning | |
338 * the permuted elements at [indexes] of a list. Negative indexes can be | |
339 * used to access the elements from the back of the list. | |
340 * | |
341 * For example, the parser `letter().star().permute([0, -1])` returns the | |
342 * first and last letter parsed. For the input `'abc'` it returns | |
343 * `['a', 'c']`. | |
344 */ | |
345 Parser permute(List<int> indexes) { | |
346 return this.map((List list) { | |
347 return indexes.map((index) { | |
348 return list[index < 0 ? list.length + index : index]; | |
349 }).toList(); | |
350 }); | |
351 } | |
352 | |
353 /** | |
354 * Returns a parser that consumes the receiver one or more times separated | |
355 * by the [separator] parser. The resulting parser returns a flat list of | |
356 * the parse results of the receiver interleaved with the parse result of the | |
357 * separator parser. | |
358 * | |
359 * If the optional argument [includeSeparators] is set to `false`, then the | |
360 * separators are not included in the parse result. If the optional argument | |
361 * [optionalSeparatorAtEnd] is set to `true` the parser also accepts an | |
362 * optional separator at the end. | |
363 * | |
364 * For example, the parser `digit().separatedBy(char('-'))` returns a parser | |
365 * that consumes input like `'1-2-3'` and returns a list of the elements and | |
366 * separators: `['1', '-', '2', '-', '3']`. | |
367 */ | |
368 Parser separatedBy(Parser separator, | |
369 {bool includeSeparators: true, bool optionalSeparatorAtEnd: false}) { | |
370 var repeater = new SequenceParser([separator, this]).star(); | |
371 var parser = new SequenceParser(optionalSeparatorAtEnd | |
372 ? [this, repeater, separator.optional(separator)] | |
373 : [this, repeater]); | |
374 return parser.map((List list) { | |
375 var result = new List(); | |
376 result.add(list[0]); | |
377 for (var tuple in list[1]) { | |
378 if (includeSeparators) { | |
379 result.add(tuple[0]); | |
380 } | |
381 result.add(tuple[1]); | |
382 } | |
383 if (includeSeparators && | |
384 optionalSeparatorAtEnd && | |
385 !identical(list[2], separator)) { | |
386 result.add(list[2]); | |
387 } | |
388 return result; | |
389 }); | |
390 } | |
391 | |
392 /** | |
393 * Returns a shallow copy of the receiver. | |
394 * | |
395 * Override this method in all subclasses. | |
396 */ | |
397 Parser copy(); | |
398 | |
399 /** | |
400 * Recursively tests for structural equality of two parsers. | |
401 * | |
402 * The code can automatically deals with recursive parsers and parsers that | |
403 * refer to other parsers. This code is supposed to be overridden by parsers | |
404 * that add other state. | |
405 */ | |
406 bool isEqualTo(Parser other, [Set<Parser> seen]) { | |
407 if (seen == null) { | |
408 seen = new Set(); | |
409 } | |
410 if (this == other || seen.contains(this)) { | |
411 return true; | |
412 } | |
413 seen.add(this); | |
414 return runtimeType == other.runtimeType && | |
415 hasEqualProperties(other) && | |
416 hasEqualChildren(other, seen); | |
417 } | |
418 | |
419 /** | |
420 * Compare the properties of two parsers. Normally this method should not be | |
421 * called directly, instead use [Parser#equals]. | |
422 * | |
423 * Override this method in all subclasses that add new state. | |
424 */ | |
425 bool hasEqualProperties(Parser other) => true; | |
426 | |
427 /** | |
428 * Compare the children of two parsers. Normally this method should not be | |
429 * called directly, instead use [Parser#equals]. | |
430 * | |
431 * Normally this method does not need to be overridden, as this method works | |
432 * generically on the returned [Parser#children]. | |
433 */ | |
434 bool hasEqualChildren(Parser other, Set<Parser> seen) { | |
435 var thisChildren = children, | |
436 otherChildren = other.children; | |
437 if (thisChildren.length != otherChildren.length) { | |
438 return false; | |
439 } | |
440 for (var i = 0; i < thisChildren.length; i++) { | |
441 if (!thisChildren[i].isEqualTo(otherChildren[i], seen)) { | |
442 return false; | |
443 } | |
444 } | |
445 return true; | |
446 } | |
447 | |
448 /** | |
449 * Returns a list of directly referenced parsers. | |
450 * | |
451 * For example, `letter().children` returns the empty collection `[]`, | |
452 * because the letter parser is a primitive or leaf parser that does not | |
453 * depend or call any other parser. | |
454 * | |
455 * In contrast, `letter().or(digit()).children` returns a collection | |
456 * containing both the `letter()` and `digit()` parser. | |
457 */ | |
458 List<Parser> get children => const []; | |
459 | |
460 /** | |
461 * Changes the receiver by replacing [source] with [target]. Does nothing | |
462 * if [source] does not exist in [Parser.children]. | |
463 * | |
464 * The following example creates a letter parser and then defines a parser | |
465 * called `example` that accepts one or more letters. Eventually the parser | |
466 * `example` is modified by replacing the `letter` parser with a new | |
467 * parser that accepts a digit. The resulting `example` parser accepts one | |
468 * or more digits. | |
469 * | |
470 * var letter = letter(); | |
471 * var example = letter.plus(); | |
472 * example.replace(letter, digit()); | |
473 */ | |
474 void replace(Parser source, Parser target) { | |
475 // no children, nothing to do | |
476 } | |
477 } | |
OLD | NEW |