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 |