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

Side by Side Diff: petitparser/lib/src/core/parser.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « petitparser/lib/src/core/expression.dart ('k') | petitparser/lib/src/core/parsers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « petitparser/lib/src/core/expression.dart ('k') | petitparser/lib/src/core/parsers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698