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