Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Translates a string of characters into a YAML serialization tree. | 6 * Translates a string of characters into a YAML serialization tree. |
| 7 * | 7 * |
| 8 * This parser is designed to closely follow the spec. All productions in the | 8 * This parser is designed to closely follow the spec. All productions in the |
| 9 * spec are numbered, and the corresponding methods in the parser have the same | 9 * spec are numbered, and the corresponding methods in the parser have the same |
| 10 * numbers. This is certainly not the most efficient way of parsing YAML, but it | 10 * numbers. This is certainly not the most efficient way of parsing YAML, but it |
| 11 * is the easiest to write and read in the context of the spec. | 11 * is the easiest to write and read in the context of the spec. |
| 12 * | 12 * |
| 13 * Methods corresponding to productions are also named as in the spec, | 13 * Methods corresponding to productions are also named as in the spec, |
| 14 * translating the name of the method (although not the annotation characters) | 14 * translating the name of the method (although not the annotation characters) |
| 15 * into camel-case for dart style.. For example, the spec has a production named | 15 * into camel-case for dart style.. For example, the spec has a production named |
| 16 * `nb-ns-plain-in-line`, and the method implementing it is named | 16 * `nb-ns-plain-in-line`, and the method implementing it is named |
| 17 * `nb_ns_plainInLine`. The exception to that rule is methods that just | 17 * `nb_ns_plainInLine`. The exception to that rule is methods that just |
| 18 * recognize character classes; these are named `is*`. | 18 * recognize character classes; these are named `is*`. |
| 19 */ | 19 */ |
| 20 class _Parser { | 20 class _Parser { |
| 21 static final TAB = 0x9; | 21 static final TAB = 0x9; |
| 22 static final LF = 0xA; | 22 static final LF = 0xA; |
| 23 static final CR = 0xD; | 23 static final CR = 0xD; |
| 24 static final SP = 0x20; | 24 static final SP = 0x20; |
| 25 static final TILDE = 0x7E; | 25 static final TILDE = 0x7E; |
| 26 static final NEL = 0x85; | 26 static final NEL = 0x85; |
| 27 static final PLUS = 0x2B; | |
| 27 static final HYPHEN = 0x2D; | 28 static final HYPHEN = 0x2D; |
| 28 static final QUESTION_MARK = 0x3F; | 29 static final QUESTION_MARK = 0x3F; |
| 29 static final COLON = 0x3A; | 30 static final COLON = 0x3A; |
| 30 static final COMMA = 0x2C; | 31 static final COMMA = 0x2C; |
| 31 static final LEFT_BRACKET = 0x5B; | 32 static final LEFT_BRACKET = 0x5B; |
| 32 static final RIGHT_BRACKET = 0x5D; | 33 static final RIGHT_BRACKET = 0x5D; |
| 33 static final LEFT_BRACE = 0x7B; | 34 static final LEFT_BRACE = 0x7B; |
| 34 static final RIGHT_BRACE = 0x7D; | 35 static final RIGHT_BRACE = 0x7D; |
| 35 static final HASH = 0x23; | 36 static final HASH = 0x23; |
| 36 static final AMPERSAND = 0x26; | 37 static final AMPERSAND = 0x26; |
| 37 static final ASTERISK = 0x2A; | 38 static final ASTERISK = 0x2A; |
| 38 static final EXCLAMATION = 0x21; | 39 static final EXCLAMATION = 0x21; |
| 39 static final VERTICAL_BAR = 0x7C; | 40 static final VERTICAL_BAR = 0x7C; |
| 40 static final GREATER_THAN = 0x3E; | 41 static final GREATER_THAN = 0x3E; |
| 41 static final SINGLE_QUOTE = 0x27; | 42 static final SINGLE_QUOTE = 0x27; |
| 42 static final DOUBLE_QUOTE = 0x22; | 43 static final DOUBLE_QUOTE = 0x22; |
| 43 static final PERCENT = 0x25; | 44 static final PERCENT = 0x25; |
| 44 static final AT = 0x40; | 45 static final AT = 0x40; |
| 45 static final GRAVE_ACCENT = 0x60; | 46 static final GRAVE_ACCENT = 0x60; |
| 46 | 47 |
| 47 static final NULL = 0x0; | 48 static final NULL = 0x0; |
| 48 static final BELL = 0x7; | 49 static final BELL = 0x7; |
| 49 static final BACKSPACE = 0x8; | 50 static final BACKSPACE = 0x8; |
| 50 static final VERTICAL_TAB = 0xB; | 51 static final VERTICAL_TAB = 0xB; |
| 51 static final FORM_FEED = 0xC; | 52 static final FORM_FEED = 0xC; |
| 52 static final ESCAPE = 0x1B; | 53 static final ESCAPE = 0x1B; |
| 54 static final SLASH = 0x2F; | |
| 53 static final BACKSLASH = 0x5C; | 55 static final BACKSLASH = 0x5C; |
| 56 static final UNDERSCORE = 0x5F; | |
| 54 static final NBSP = 0xA0; | 57 static final NBSP = 0xA0; |
| 55 static final LINE_SEPARATOR = 0x2028; | 58 static final LINE_SEPARATOR = 0x2028; |
| 56 static final PARAGRAPH_SEPARATOR = 0x2029; | 59 static final PARAGRAPH_SEPARATOR = 0x2029; |
| 57 | 60 |
| 61 static final NUMBER_0 = 0x30; | |
| 62 static final NUMBER_9 = 0x39; | |
| 63 | |
| 64 static final LETTER_A = 0x61; | |
| 65 static final LETTER_B = 0x62; | |
| 66 static final LETTER_E = 0x65; | |
| 67 static final LETTER_F = 0x66; | |
| 68 static final LETTER_N = 0x6E; | |
| 69 static final LETTER_R = 0x72; | |
| 70 static final LETTER_T = 0x74; | |
| 71 static final LETTER_U = 0x75; | |
| 72 static final LETTER_V = 0x76; | |
| 73 static final LETTER_X = 0x78; | |
| 74 | |
| 75 static final LETTER_CAP_A = 0x41; | |
| 76 static final LETTER_CAP_F = 0x46; | |
| 77 static final LETTER_CAP_L = 0x4C; | |
| 78 static final LETTER_CAP_N = 0x4E; | |
| 79 static final LETTER_CAP_P = 0x50; | |
| 80 static final LETTER_CAP_U = 0x55; | |
| 81 static final LETTER_CAP_X = 0x58; | |
| 82 | |
| 58 static final C_SEQUENCE_ENTRY = 4; | 83 static final C_SEQUENCE_ENTRY = 4; |
| 59 static final C_MAPPING_KEY = 5; | 84 static final C_MAPPING_KEY = 5; |
| 60 static final C_MAPPING_VALUE = 6; | 85 static final C_MAPPING_VALUE = 6; |
| 61 static final C_COLLECT_ENTRY = 7; | 86 static final C_COLLECT_ENTRY = 7; |
| 62 static final C_SEQUENCE_START = 8; | 87 static final C_SEQUENCE_START = 8; |
| 63 static final C_SEQUENCE_END = 9; | 88 static final C_SEQUENCE_END = 9; |
| 64 static final C_MAPPING_START = 10; | 89 static final C_MAPPING_START = 10; |
| 65 static final C_MAPPING_END = 11; | 90 static final C_MAPPING_END = 11; |
| 66 static final C_COMMENT = 12; | 91 static final C_COMMENT = 12; |
| 67 static final C_ANCHOR = 13; | 92 static final C_ANCHOR = 13; |
| 68 static final C_ALIAS = 14; | 93 static final C_ALIAS = 14; |
| 69 static final C_TAG = 15; | 94 static final C_TAG = 15; |
| 70 static final C_LITERAL = 16; | 95 static final C_LITERAL = 16; |
| 71 static final C_FOLDED = 17; | 96 static final C_FOLDED = 17; |
| 72 static final C_SINGLE_QUOTE = 18; | 97 static final C_SINGLE_QUOTE = 18; |
| 73 static final C_DOUBLE_QUOTE = 19; | 98 static final C_DOUBLE_QUOTE = 19; |
| 74 static final C_DIRECTIVE = 20; | 99 static final C_DIRECTIVE = 20; |
| 75 static final C_RESERVED = 21; | 100 static final C_RESERVED = 21; |
| 76 | 101 |
| 77 static final BLOCK_OUT = 0; | 102 static final BLOCK_OUT = 0; |
| 78 static final BLOCK_IN = 1; | 103 static final BLOCK_IN = 1; |
| 79 static final FLOW_OUT = 2; | 104 static final FLOW_OUT = 2; |
| 80 static final FLOW_IN = 3; | 105 static final FLOW_IN = 3; |
| 81 static final BLOCK_KEY = 4; | 106 static final BLOCK_KEY = 4; |
| 82 static final FLOW_KEY = 5; | 107 static final FLOW_KEY = 5; |
| 83 | 108 |
| 109 static final CHOMPING_STRIP = 0; | |
| 110 static final CHOMPING_KEEP = 1; | |
| 111 static final CHOMPING_CLIP = 2; | |
| 112 | |
| 84 /** The source string being parsed. */ | 113 /** The source string being parsed. */ |
| 85 final String s; | 114 final String s; |
| 86 | 115 |
| 87 /** The current position in the source string. */ | 116 /** The current position in the source string. */ |
| 88 int pos = 0; | 117 int pos = 0; |
| 89 | 118 |
| 90 /** The length of the string being parsed. */ | 119 /** The length of the string being parsed. */ |
| 91 final int len; | 120 final int len; |
| 92 | 121 |
| 93 /** The current (0-based) line in the source string. */ | 122 /** The current (0-based) line in the source string. */ |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 116 | 145 |
| 117 /** | 146 /** |
| 118 * The name of the context of the farthest position that has been parsed | 147 * The name of the context of the farthest position that has been parsed |
| 119 * successfully before backtracking. Used for error reporting. | 148 * successfully before backtracking. Used for error reporting. |
| 120 */ | 149 */ |
| 121 String farthestContext = "document"; | 150 String farthestContext = "document"; |
| 122 | 151 |
| 123 /** A stack of the names of parse contexts. Used for error reporting. */ | 152 /** A stack of the names of parse contexts. Used for error reporting. */ |
| 124 List<String> contextStack; | 153 List<String> contextStack; |
| 125 | 154 |
| 155 /** | |
| 156 * The buffer containing string currently being captured. | |
|
Bob Nystrom
2012/05/18 21:06:30
"string" -> "the string"
nweiz
2012/05/18 21:47:04
Done.
| |
| 157 */ | |
| 158 StringBuffer capturedString; | |
| 159 | |
| 160 /** | |
| 161 * The beginning of the current section of the captured string. | |
| 162 */ | |
| 163 int captureStart; | |
| 164 | |
| 165 /** | |
| 166 * Whether the current string capture is being overridden. | |
| 167 */ | |
| 168 bool capturingAs = false; | |
| 169 | |
| 126 _Parser(String s) | 170 _Parser(String s) |
| 127 : this.s = s, | 171 : this.s = s, |
| 128 len = s.length, | 172 len = s.length, |
| 129 contextStack = <String>["document"]; | 173 contextStack = <String>["document"]; |
| 130 | 174 |
| 131 /** | 175 /** |
| 132 * Return the character at the current position, then move that position | 176 * Return the character at the current position, then move that position |
| 133 * forward one character. Also updates the current line and column numbers. | 177 * forward one character. Also updates the current line and column numbers. |
| 134 */ | 178 */ |
| 135 int next() { | 179 int next() { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 */ | 222 */ |
| 179 bool consume(bool matcher(int)) { | 223 bool consume(bool matcher(int)) { |
| 180 if (matcher(peek())) { | 224 if (matcher(peek())) { |
| 181 next(); | 225 next(); |
| 182 return true; | 226 return true; |
| 183 } | 227 } |
| 184 return false; | 228 return false; |
| 185 } | 229 } |
| 186 | 230 |
| 187 /** | 231 /** |
| 232 * Consumes the current character if it equals [char]. | |
| 233 */ | |
| 234 bool consumeChar(int char) => consume((c) => c == char); | |
| 235 | |
| 236 /** | |
| 188 * Calls [consumer] until it returns a falsey value. Returns a list of all | 237 * Calls [consumer] until it returns a falsey value. Returns a list of all |
| 189 * truthy return values of [consumer], or null if it didn't consume anything. | 238 * truthy return values of [consumer], or null if it didn't consume anything. |
| 190 * | 239 * |
| 191 * Conceptually, repeats a production one or more times. | 240 * Conceptually, repeats a production one or more times. |
| 192 */ | 241 */ |
| 193 List oneOrMore(consumer()) { | 242 List oneOrMore(consumer()) { |
| 194 var first = consumer(); | 243 var first = consumer(); |
| 195 if (!truth(first)) return null; | 244 if (!truth(first)) return null; |
| 196 var out = [first]; | 245 var out = [first]; |
| 197 while (true) { | 246 while (true) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 if (truth(res)) return res; | 284 if (truth(res)) return res; |
| 236 } | 285 } |
| 237 return null; | 286 return null; |
| 238 } | 287 } |
| 239 | 288 |
| 240 /** | 289 /** |
| 241 * Calls [consumer] and returns its result, but rolls back the parser state if | 290 * Calls [consumer] and returns its result, but rolls back the parser state if |
| 242 * [consumer] returns a falsey value. | 291 * [consumer] returns a falsey value. |
| 243 */ | 292 */ |
| 244 transaction(consumer()) { | 293 transaction(consumer()) { |
| 245 int oldPos = pos, oldLine = line, oldColumn = column; | 294 int oldPos = pos, oldLine = line, oldColumn = column, |
| 295 oldCaptureStart = captureStart; | |
|
Bob Nystrom
2012/05/18 21:06:30
How about splitting these into separate declaratio
nweiz
2012/05/18 21:47:04
Done.
| |
| 296 String capturedSoFar = capturedString == null ? null : | |
| 297 capturedString.toString(); | |
| 246 var res = consumer(); | 298 var res = consumer(); |
| 247 if (truth(res)) return res; | 299 if (truth(res)) return res; |
| 248 | 300 |
| 249 pos = oldPos; | 301 pos = oldPos; |
| 250 line = oldLine; | 302 line = oldLine; |
| 251 column = oldColumn; | 303 column = oldColumn; |
| 304 captureStart = oldCaptureStart; | |
| 305 capturedString = capturedSoFar == null ? null : | |
| 306 new StringBuffer(capturedSoFar); | |
| 252 return res; | 307 return res; |
| 253 } | 308 } |
| 254 | 309 |
| 255 /** | 310 /** |
| 256 * Consumes [n] characters matching [matcher], or none if there isn't a | 311 * Consumes [n] characters matching [matcher], or none if there isn't a |
| 257 * complete match. The first argument to [matcher] is the character code, the | 312 * complete match. The first argument to [matcher] is the character code, the |
| 258 * second is the index (from 0 to [n] - 1). | 313 * second is the index (from 0 to [n] - 1). |
| 259 * | 314 * |
| 260 * Returns whether or not the characters were consumed. | 315 * Returns whether or not the characters were consumed. |
| 261 */ | 316 */ |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 280 */ | 335 */ |
| 281 String stringOf(bool matcher(int)) => | 336 String stringOf(bool matcher(int)) => |
| 282 captureString(() => oneOrMore(() => consume(matcher))); | 337 captureString(() => oneOrMore(() => consume(matcher))); |
| 283 | 338 |
| 284 /** | 339 /** |
| 285 * Calls [consumer] and returns the string that was consumed while doing so, | 340 * Calls [consumer] and returns the string that was consumed while doing so, |
| 286 * or null if [consumer] returned a falsey value. Automatically wraps | 341 * or null if [consumer] returned a falsey value. Automatically wraps |
| 287 * [consumer] in `transaction`. | 342 * [consumer] in `transaction`. |
| 288 */ | 343 */ |
| 289 String captureString(consumer()) { | 344 String captureString(consumer()) { |
| 290 int start = pos; | 345 if (capturedString != null) throw 'captureString calls may not be nested'; |
|
Bob Nystrom
2012/05/18 21:06:30
This is a programmatic error, right? If so, I woul
nweiz
2012/05/18 21:47:04
Done.
| |
| 346 | |
| 347 captureStart = pos; | |
| 348 capturedString = new StringBuffer(); | |
| 291 var res = transaction(consumer); | 349 var res = transaction(consumer); |
| 292 if (!truth(res)) return null; | 350 if (!truth(res)) { |
| 293 return s.substring(start, pos); | 351 captureStart = capturedString = null; |
|
Bob Nystrom
2012/05/18 21:06:30
This chained assignment doesn't really add a lot o
nweiz
2012/05/18 21:47:04
Done.
| |
| 352 return null; | |
| 353 } | |
| 354 | |
| 355 flushCapture(); | |
| 356 var result = capturedString.toString(); | |
| 357 captureStart = capturedString = null; | |
|
Bob Nystrom
2012/05/18 21:06:30
Ditto.
nweiz
2012/05/18 21:47:04
Done.
| |
| 358 return result; | |
| 359 } | |
| 360 | |
| 361 captureAs(String replacement, consumer()) => | |
| 362 captureAndTransform(consumer, (_) => replacement); | |
|
Bob Nystrom
2012/05/18 21:06:30
+2 indent.
nweiz
2012/05/18 21:47:04
Done.
| |
| 363 | |
| 364 captureAndTransform(consumer(), String transformation(String captured)) { | |
| 365 if (capturedString == null) return consumer(); | |
| 366 if (capturingAs) return consumer(); | |
| 367 | |
| 368 flushCapture(); | |
| 369 capturingAs = true; | |
| 370 var res = consumer(); | |
| 371 capturingAs = false; | |
| 372 if (!truth(res)) return res; | |
| 373 | |
| 374 capturedString.add(transformation(s.substring(captureStart, pos))); | |
| 375 captureStart = pos; | |
| 376 return res; | |
| 377 } | |
| 378 | |
| 379 void flushCapture() { | |
| 380 capturedString.add(s.substring(captureStart, pos)); | |
| 381 captureStart = pos; | |
| 294 } | 382 } |
| 295 | 383 |
| 296 /** | 384 /** |
| 297 * Adds a tag and an anchor to [node], if they're defined. | 385 * Adds a tag and an anchor to [node], if they're defined. |
| 298 */ | 386 */ |
| 299 _Node addProps(_Node node, _Pair<_Tag, String> props) { | 387 _Node addProps(_Node node, _Pair<_Tag, String> props) { |
| 388 if (props == null || node == null) return node; | |
| 300 if (truth(props.first)) node.tag = props.first; | 389 if (truth(props.first)) node.tag = props.first; |
| 301 if (truth(props.last)) node.anchor = props.last; | 390 if (truth(props.last)) node.anchor = props.last; |
| 302 return node; | 391 return node; |
| 303 } | 392 } |
| 304 | 393 |
| 305 /** Creates a MappingNode from [pairs]. */ | 394 /** Creates a MappingNode from [pairs]. */ |
| 306 _MappingNode map(List<_Pair<_Node, _Node>> pairs) { | 395 _MappingNode map(List<_Pair<_Node, _Node>> pairs) { |
| 307 var content = new Map<_Node, _Node>(); | 396 var content = new Map<_Node, _Node>(); |
| 308 pairs.forEach((pair) => content[pair.first] = pair.last); | 397 pairs.forEach((pair) => content[pair.first] = pair.last); |
| 309 return new _MappingNode("?", content); | 398 return new _MappingNode("?", content); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 "invalid YAML in $farthestContext"); | 434 "invalid YAML in $farthestContext"); |
| 346 } | 435 } |
| 347 | 436 |
| 348 /** Returns the number of spaces after the current position. */ | 437 /** Returns the number of spaces after the current position. */ |
| 349 int countIndentation() { | 438 int countIndentation() { |
| 350 var i = 0; | 439 var i = 0; |
| 351 while (peek(i) == SP) i++; | 440 while (peek(i) == SP) i++; |
| 352 return i; | 441 return i; |
| 353 } | 442 } |
| 354 | 443 |
| 444 /** Returns the indentation for a block scalar. */ | |
| 445 int blockScalarAdditionalIndentation(_BlockHeader header, int indent) { | |
| 446 if (!header.autoDetectIndent) return header.additionalIndent; | |
| 447 | |
| 448 var maxSpaces = 0; | |
| 449 var maxSpacesLine = 0; | |
| 450 var spaces = 0; | |
| 451 transaction(() { | |
| 452 do { | |
| 453 spaces = captureString(() => zeroOrMore(() => consumeChar(SP))).length; | |
| 454 if (spaces > maxSpaces) { | |
| 455 maxSpaces = spaces; | |
| 456 maxSpacesLine = line; | |
| 457 } | |
| 458 } while (b_break()); | |
| 459 return false; | |
| 460 }); | |
| 461 | |
| 462 // If the next non-empty line isn't indented further than the start of the | |
| 463 // block scalar, that means the scalar is going to be empty. Returning any | |
| 464 // value > 0 will cause the parser not to consume any text. | |
| 465 if (spaces <= indent) return 1; | |
| 466 | |
| 467 // It's an error for a leading empty line to be indented more than the first | |
| 468 // non-empty line. | |
| 469 if (maxSpaces > spaces) { | |
| 470 throw new SyntaxError(maxSpacesLine + 1, maxSpaces, | |
| 471 "leading empty lines may not be indented more than the first " | |
|
Bob Nystrom
2012/05/18 21:06:30
Sentence case and ".".
nweiz
2012/05/18 21:47:04
Done.
| |
| 472 "non-empty line"); | |
| 473 } | |
| 474 | |
| 475 return spaces - indent; | |
| 476 } | |
| 477 | |
| 355 /** Returns whether the current position is at the beginning of a line. */ | 478 /** Returns whether the current position is at the beginning of a line. */ |
| 356 bool get atStartOfLine() => column == 0; | 479 bool get atStartOfLine() => column == 0; |
| 357 | 480 |
| 358 /** Returns whether the current position is at the end of the input. */ | 481 /** Returns whether the current position is at the end of the input. */ |
| 359 bool get atEndOfFile() => pos == len; | 482 bool get atEndOfFile() => pos == len; |
| 360 | 483 |
| 361 /** | 484 /** |
| 362 * Given an indicator character, returns the type of that indicator (or null | 485 * Given an indicator character, returns the type of that indicator (or null |
| 363 * if the indicator isn't found. | 486 * if the indicator isn't found. |
| 364 */ | 487 */ |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 393 return char == TAB || | 516 return char == TAB || |
| 394 char == LF || | 517 char == LF || |
| 395 char == CR || | 518 char == CR || |
| 396 (char >= SP && char <= TILDE) || | 519 (char >= SP && char <= TILDE) || |
| 397 char == NEL || | 520 char == NEL || |
| 398 (char >= 0xA0 && char <= 0xD7FF) || | 521 (char >= 0xA0 && char <= 0xD7FF) || |
| 399 (char >= 0xE000 && char <= 0xFFFD) || | 522 (char >= 0xE000 && char <= 0xFFFD) || |
| 400 (char >= 0x10000 && char <= 0x10FFFF); | 523 (char >= 0x10000 && char <= 0x10FFFF); |
| 401 } | 524 } |
| 402 | 525 |
| 526 // 2 | |
| 527 bool isJson(int char) => char == TAB || (char >= SP && char <= 0x10FFFF); | |
| 528 | |
| 403 // 22 | 529 // 22 |
| 404 bool c_indicator(int type) => consume((c) => indicatorType(c) == type); | 530 bool c_indicator(int type) => consume((c) => indicatorType(c) == type); |
| 405 | 531 |
| 406 // 23 | 532 // 23 |
| 407 bool isFlowIndicator(int char) { | 533 bool isFlowIndicator(int char) { |
| 408 var indicator = indicatorType(char); | 534 var indicator = indicatorType(char); |
| 409 return indicator == C_COLLECT_ENTRY || | 535 return indicator == C_COLLECT_ENTRY || |
| 410 indicator == C_SEQUENCE_START || | 536 indicator == C_SEQUENCE_START || |
| 411 indicator == C_SEQUENCE_END || | 537 indicator == C_SEQUENCE_END || |
| 412 indicator == C_MAPPING_START || | 538 indicator == C_MAPPING_START || |
| 413 indicator == C_MAPPING_END; | 539 indicator == C_MAPPING_END; |
| 414 } | 540 } |
| 415 | 541 |
| 416 // 26 | 542 // 26 |
| 417 bool isBreak(int char) => char == LF || char == CR; | 543 bool isBreak(int char) => char == LF || char == CR; |
| 418 | 544 |
| 419 // 27 | 545 // 27 |
| 420 bool isNonBreak(int char) => isPrintable(char) && !isBreak(char); | 546 bool isNonBreak(int char) => isPrintable(char) && !isBreak(char); |
| 421 | 547 |
| 548 // 28 | |
| 549 bool b_break() { | |
| 550 if (consumeChar(CR)) { | |
| 551 zeroOrOne(() => consumeChar(LF)); | |
| 552 return true; | |
| 553 } | |
| 554 return consumeChar(LF); | |
| 555 } | |
| 556 | |
| 557 // 29 | |
| 558 bool b_asLineFeed() => captureAs("\n", () => b_break()); | |
| 559 | |
| 422 // 30 | 560 // 30 |
| 423 bool b_non_content() => consume(isBreak); | 561 bool b_nonContent() => captureAs("", () => b_break()); |
| 424 | 562 |
| 425 // 33 | 563 // 33 |
| 426 bool isSpace(int char) => char == SP || char == TAB; | 564 bool isSpace(int char) => char == SP || char == TAB; |
| 427 | 565 |
| 428 // 34 | 566 // 34 |
| 429 bool isNonSpace(int char) => isNonBreak(char) && !isSpace(char); | 567 bool isNonSpace(int char) => isNonBreak(char) && !isSpace(char); |
| 430 | 568 |
| 569 // 35 | |
| 570 bool isDecDigit(int char) => char >= NUMBER_0 && char <= NUMBER_9; | |
| 571 | |
| 572 // 36 | |
| 573 bool isHexDigit(int char) { | |
| 574 return isDecDigit(char) || | |
| 575 (char >= LETTER_A && char <= LETTER_F) || | |
| 576 (char >= LETTER_CAP_A && char <= LETTER_CAP_F); | |
| 577 } | |
| 578 | |
| 579 // 41 | |
| 580 bool c_escape() => captureAs("", () => consumeChar(BACKSLASH)); | |
| 581 | |
| 582 // 42 | |
| 583 bool ns_escNull() => captureAs("\x00", () => consumeChar(NUMBER_0)); | |
| 584 | |
| 585 // 43 | |
| 586 bool ns_escBell() => captureAs("\x07", () => consumeChar(LETTER_A)); | |
| 587 | |
| 588 // 44 | |
| 589 bool ns_escBackspace() => captureAs("\b", () => consumeChar(LETTER_B)); | |
| 590 | |
| 591 // 45 | |
| 592 bool ns_escHorizontalTab() => captureAs("\t", () { | |
| 593 return consume((c) => c == LETTER_T || c == TAB); | |
| 594 }); | |
| 595 | |
| 596 // 46 | |
| 597 bool ns_escLineFeed() => captureAs("\n", () => consumeChar(LETTER_N)); | |
| 598 | |
| 599 // 47 | |
| 600 bool ns_escVerticalTab() => captureAs("\v", () => consumeChar(LETTER_V)); | |
| 601 | |
| 602 // 48 | |
| 603 bool ns_escFormFeed() => captureAs("\f", () => consumeChar(LETTER_F)); | |
| 604 | |
| 605 // 49 | |
| 606 bool ns_escCarriageReturn() => captureAs("\r", () => consumeChar(LETTER_R)); | |
| 607 | |
| 608 // 50 | |
| 609 bool ns_escEscape() => captureAs("\x1B", () => consumeChar(LETTER_E)); | |
| 610 | |
| 611 // 51 | |
| 612 bool ns_escSpace() => consumeChar(SP); | |
| 613 | |
| 614 // 52 | |
| 615 bool ns_escDoubleQuote() => consumeChar(DOUBLE_QUOTE); | |
| 616 | |
| 617 // 53 | |
| 618 bool ns_escSlash() => consumeChar(SLASH); | |
| 619 | |
| 620 // 54 | |
| 621 bool ns_escBackslash() => consumeChar(BACKSLASH); | |
| 622 | |
| 623 // 55 | |
| 624 bool ns_escNextLine() => captureAs("\x85", () => consumeChar(LETTER_CAP_N)); | |
| 625 | |
| 626 // 56 | |
| 627 bool ns_escNonBreakingSpace() => | |
| 628 captureAs("\xA0", () => consumeChar(UNDERSCORE)); | |
| 629 | |
| 630 // 57 | |
| 631 bool ns_escLineSeparator() => | |
| 632 captureAs("\u2028", () => consumeChar(LETTER_CAP_L)); | |
| 633 | |
| 634 // 58 | |
| 635 bool ns_escParagraphSeparator() => | |
| 636 captureAs("\u2029", () => consumeChar(LETTER_CAP_P)); | |
| 637 | |
| 638 // 59 | |
| 639 bool ns_esc8Bit() => ns_escNBit(LETTER_X, 2); | |
| 640 | |
| 641 // 60 | |
| 642 bool ns_esc16Bit() => ns_escNBit(LETTER_U, 4); | |
| 643 | |
| 644 // 61 | |
| 645 bool ns_esc32Bit() => ns_escNBit(LETTER_CAP_U, 8); | |
| 646 | |
| 647 // Helper method for 59 - 61 | |
| 648 bool ns_escNBit(int char, int digits) { | |
| 649 if (!captureAs('', () => consumeChar(char))) return false; | |
| 650 var captured = captureAndTransform( | |
| 651 () => nAtOnce(digits, (c, _) => isHexDigit(c)), | |
| 652 (hex) => new String.fromCharCodes([Math.parseInt("0x$hex")])); | |
| 653 return expect(captured, "$digits hexidecimal digits"); | |
| 654 } | |
| 655 | |
| 656 // 62 | |
| 657 bool c_ns_escChar() => context('escape sequence', () => transaction(() { | |
| 658 if (!truth(c_escape())) return false; | |
| 659 return truth(or([ | |
| 660 ns_escNull, ns_escBell, ns_escBackspace, ns_escHorizontalTab, | |
| 661 ns_escLineFeed, ns_escVerticalTab, ns_escFormFeed, ns_escCarriageReturn, | |
| 662 ns_escEscape, ns_escSpace, ns_escDoubleQuote, ns_escSlash, | |
| 663 ns_escBackslash, ns_escNextLine, ns_escNonBreakingSpace, | |
| 664 ns_escLineSeparator, ns_escParagraphSeparator, ns_esc8Bit, ns_esc16Bit, | |
| 665 ns_esc32Bit | |
| 666 ])); | |
| 667 })); | |
| 668 | |
| 431 // 63 | 669 // 63 |
| 432 bool s_indent(int indent) => nAtOnce(indent, (c, i) => c == SP); | 670 bool s_indent(int indent) => nAtOnce(indent, (c, i) => c == SP); |
| 433 | 671 |
| 434 // 66 | 672 // 64 |
| 435 bool s_separateInLine() => transaction(() => | 673 bool s_indentLessThan(int indent) { |
| 436 truth(oneOrMore(() => consume(isSpace))) || atStartOfLine); | 674 for (int i = 0; i < indent - 1; i++) { |
| 437 | 675 if (!consumeChar(SP)) break; |
| 438 // 69 | 676 } |
| 439 bool s_flowLinePrefix(int indent) { | |
| 440 if (!s_indent(indent)) return false; | |
| 441 zeroOrOne(s_separateInLine); | |
| 442 return true; | 677 return true; |
| 443 } | 678 } |
| 444 | 679 |
| 680 // 65 | |
| 681 bool s_indentLessThanOrEqualTo(int indent) => s_indentLessThan(indent + 1); | |
| 682 | |
| 683 // 66 | |
| 684 bool s_separateInLine() => transaction(() { | |
| 685 return captureAs('', () => | |
| 686 truth(oneOrMore(() => consume(isSpace))) || atStartOfLine); | |
| 687 }); | |
| 688 | |
| 689 // 67 | |
| 690 bool s_linePrefix(int indent, int ctx) => captureAs("", () { | |
| 691 switch (ctx) { | |
| 692 case BLOCK_OUT: | |
| 693 case BLOCK_IN: | |
| 694 return s_blockLinePrefix(indent); | |
| 695 case FLOW_OUT: | |
| 696 case FLOW_IN: | |
| 697 return s_flowLinePrefix(indent); | |
| 698 } | |
| 699 }); | |
| 700 | |
| 701 // 68 | |
| 702 bool s_blockLinePrefix(int indent) => s_indent(indent); | |
| 703 | |
| 704 // 69 | |
| 705 bool s_flowLinePrefix(int indent) => captureAs('', () { | |
| 706 if (!truth(s_indent(indent))) return false; | |
| 707 zeroOrOne(s_separateInLine); | |
| 708 return true; | |
| 709 }); | |
| 710 | |
| 711 // 70 | |
| 712 bool l_empty(int indent, int ctx) => transaction(() { | |
| 713 var start = or([ | |
| 714 () => s_linePrefix(indent, ctx), | |
| 715 () => s_indentLessThan(indent) | |
| 716 ]); | |
| 717 if (!truth(start)) return false; | |
| 718 return b_asLineFeed(); | |
| 719 }); | |
| 720 | |
| 721 // 71 | |
| 722 bool b_asSpace() => captureAs(" ", () => consume(isBreak)); | |
| 723 | |
| 724 // 72 | |
| 725 bool b_l_trimmed(int indent, int ctx) => transaction(() { | |
| 726 if (!truth(b_nonContent())) return false; | |
| 727 return truth(oneOrMore(() => captureAs("\n", () => l_empty(indent, ctx)))); | |
| 728 }); | |
| 729 | |
| 730 // 73 | |
| 731 bool b_l_folded(int indent, int ctx) => | |
| 732 or([() => b_l_trimmed(indent, ctx), b_asSpace]); | |
| 733 | |
| 445 // 74 | 734 // 74 |
| 446 bool s_flowFolded(int indent) => false; // TODO(nweiz): implement | 735 bool s_flowFolded(int indent) => transaction(() { |
| 736 zeroOrOne(s_separateInLine); | |
| 737 if (!truth(b_l_folded(indent, FLOW_IN))) return false; | |
| 738 return s_flowLinePrefix(indent); | |
| 739 }); | |
| 447 | 740 |
| 448 // 75 | 741 // 75 |
| 449 bool c_nb_commentText() { | 742 bool c_nb_commentText() { |
| 450 if (!c_indicator(C_COMMENT)) return false; | 743 if (!truth(c_indicator(C_COMMENT))) return false; |
| 451 zeroOrMore(() => consume(isNonBreak)); | 744 zeroOrMore(() => consume(isNonBreak)); |
| 452 return true; | 745 return true; |
| 453 } | 746 } |
| 454 | 747 |
| 455 // 76 | 748 // 76 |
| 456 bool b_comment() => atEndOfFile || b_non_content(); | 749 bool b_comment() => atEndOfFile || b_nonContent(); |
| 457 | 750 |
| 458 // 77 | 751 // 77 |
| 459 bool s_b_comment() { | 752 bool s_b_comment() { |
| 460 if (s_separateInLine()) { | 753 if (truth(s_separateInLine())) { |
| 461 zeroOrOne(c_nb_commentText); | 754 zeroOrOne(c_nb_commentText); |
| 462 } | 755 } |
| 463 return b_comment(); | 756 return b_comment(); |
| 464 } | 757 } |
| 465 | 758 |
| 466 // 78 | 759 // 78 |
| 467 bool l_comment() => transaction(() { | 760 bool l_comment() => transaction(() { |
| 468 if (!s_separateInLine()) return false; | 761 if (!truth(s_separateInLine())) return false; |
| 469 zeroOrOne(c_nb_commentText); | 762 zeroOrOne(c_nb_commentText); |
| 470 return b_comment(); | 763 return b_comment(); |
| 471 }); | 764 }); |
| 472 | 765 |
| 473 // 79 | 766 // 79 |
| 474 bool s_l_comments() { | 767 bool s_l_comments() { |
| 475 if (!s_b_comment() && !atStartOfLine) return false; | 768 if (!truth(s_b_comment()) && !atStartOfLine) return false; |
| 476 zeroOrMore(l_comment); | 769 zeroOrMore(l_comment); |
| 477 return true; | 770 return true; |
| 478 } | 771 } |
| 479 | 772 |
| 480 // 80 | 773 // 80 |
| 481 bool s_separate(int indent, int ctx) { | 774 bool s_separate(int indent, int ctx) { |
| 482 switch (ctx) { | 775 switch (ctx) { |
| 483 case BLOCK_OUT: | 776 case BLOCK_OUT: |
| 484 case BLOCK_IN: | 777 case BLOCK_IN: |
| 485 case FLOW_OUT: | 778 case FLOW_OUT: |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 500 | 793 |
| 501 // 82 | 794 // 82 |
| 502 bool l_directive() => false; // TODO(nweiz): implement | 795 bool l_directive() => false; // TODO(nweiz): implement |
| 503 | 796 |
| 504 // 96 | 797 // 96 |
| 505 _Pair<_Tag, String> c_ns_properties(int indent, int ctx) { | 798 _Pair<_Tag, String> c_ns_properties(int indent, int ctx) { |
| 506 var tag, anchor; | 799 var tag, anchor; |
| 507 tag = c_ns_tagProperty(); | 800 tag = c_ns_tagProperty(); |
| 508 if (truth(tag)) { | 801 if (truth(tag)) { |
| 509 anchor = transaction(() { | 802 anchor = transaction(() { |
| 510 if (!s_separate(indent, ctx)) return null; | 803 if (!truth(s_separate(indent, ctx))) return null; |
| 511 return c_ns_anchorProperty(); | 804 return c_ns_anchorProperty(); |
| 512 }); | 805 }); |
| 513 return new _Pair<_Tag, String>(tag, anchor); | 806 return new _Pair<_Tag, String>(tag, anchor); |
| 514 } | 807 } |
| 515 | 808 |
| 516 anchor = c_ns_anchorProperty(); | 809 anchor = c_ns_anchorProperty(); |
| 517 if (truth(anchor)) { | 810 if (truth(anchor)) { |
| 518 tag = transaction(() { | 811 tag = transaction(() { |
| 519 if (!s_separate(indent, ctx)) return null; | 812 if (!truth(s_separate(indent, ctx))) return null; |
| 520 return c_ns_tagProperty(); | 813 return c_ns_tagProperty(); |
| 521 }); | 814 }); |
| 522 return new _Pair<_Tag, String>(tag, anchor); | 815 return new _Pair<_Tag, String>(tag, anchor); |
| 523 } | 816 } |
| 524 | 817 |
| 525 return null; | 818 return null; |
| 526 } | 819 } |
| 527 | 820 |
| 528 // 97 | 821 // 97 |
| 529 _Tag c_ns_tagProperty() => null; // TODO(nweiz): implement | 822 _Tag c_ns_tagProperty() => null; // TODO(nweiz): implement |
| 530 | 823 |
| 531 // 101 | 824 // 101 |
| 532 String c_ns_anchorProperty() => null; // TODO(nweiz): implement | 825 String c_ns_anchorProperty() => null; // TODO(nweiz): implement |
| 533 | 826 |
| 534 // 102 | 827 // 102 |
| 535 bool isAnchorChar(int char) => isNonSpace(char) && !isFlowIndicator(char); | 828 bool isAnchorChar(int char) => isNonSpace(char) && !isFlowIndicator(char); |
| 536 | 829 |
| 537 // 103 | 830 // 103 |
| 538 String ns_anchorName() => | 831 String ns_anchorName() => |
| 539 captureString(() => oneOrMore(() => consume(isAnchorChar))); | 832 captureString(() => oneOrMore(() => consume(isAnchorChar))); |
| 540 | 833 |
| 541 // 104 | 834 // 104 |
| 542 _Node c_ns_aliasNode() { | 835 _Node c_ns_aliasNode() { |
| 543 if (!c_indicator(C_ALIAS)) return null; | 836 if (!truth(c_indicator(C_ALIAS))) return null; |
| 544 var name = expect(ns_anchorName(), 'anchor name'); | 837 var name = expect(ns_anchorName(), 'anchor name'); |
| 545 return new _AliasNode(name); | 838 return new _AliasNode(name); |
| 546 } | 839 } |
| 547 | 840 |
| 548 // 105 | 841 // 105 |
| 549 _ScalarNode e_scalar() => new _ScalarNode("?", content: ""); | 842 _ScalarNode e_scalar() => new _ScalarNode("?", content: ""); |
| 550 | 843 |
| 551 // 106 | 844 // 106 |
| 552 _ScalarNode e_node() => e_scalar(); | 845 _ScalarNode e_node() => e_scalar(); |
| 553 | 846 |
| 847 // 107 | |
| 848 bool nb_doubleChar() => or([ | |
| 849 c_ns_escChar, | |
| 850 () => consume((c) => isJson(c) && c != BACKSLASH && c != DOUBLE_QUOTE) | |
| 851 ]); | |
| 852 | |
| 853 // 108 | |
| 854 bool ns_doubleChar() => !isSpace(peek()) && truth(nb_doubleChar()); | |
| 855 | |
| 856 // 109 | |
| 857 _Node c_doubleQuoted(int indent, int ctx) => context('string', () { | |
| 858 return transaction(() { | |
| 859 if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null; | |
| 860 var contents = nb_doubleText(indent, ctx); | |
| 861 if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null; | |
| 862 return new _ScalarNode("!", contents); | |
| 863 }); | |
| 864 }); | |
| 865 | |
| 866 // 110 | |
| 867 String nb_doubleText(int indent, int ctx) => captureString(() { | |
| 868 switch (ctx) { | |
| 869 case FLOW_OUT: | |
| 870 case FLOW_IN: | |
| 871 nb_doubleMultiLine(indent); | |
| 872 break; | |
| 873 case BLOCK_KEY: | |
| 874 case FLOW_KEY: | |
| 875 nb_doubleOneLine(); | |
| 876 break; | |
| 877 } | |
| 878 return true; | |
| 879 }); | |
| 880 | |
| 881 // 111 | |
| 882 void nb_doubleOneLine() { | |
| 883 zeroOrMore(nb_doubleChar); | |
| 884 } | |
| 885 | |
| 886 // 112 | |
| 887 bool s_doubleEscaped(int indent) => transaction(() { | |
| 888 zeroOrMore(() => consume(isSpace)); | |
| 889 if (!captureAs("", () => consumeChar(BACKSLASH))) return false; | |
| 890 if (!truth(b_nonContent())) return false; | |
| 891 zeroOrMore(() => captureAs("\n", () => l_empty(indent, FLOW_IN))); | |
| 892 return s_flowLinePrefix(indent); | |
| 893 }); | |
| 894 | |
| 895 // 113 | |
| 896 bool s_doubleBreak(int indent) => or([ | |
| 897 () => s_doubleEscaped(indent), | |
| 898 () => s_flowFolded(indent) | |
| 899 ]); | |
| 900 | |
| 901 // 114 | |
| 902 void nb_ns_doubleInLine() { | |
| 903 zeroOrMore(() => transaction(() { | |
| 904 zeroOrMore(() => consume(isSpace)); | |
| 905 return ns_doubleChar(); | |
| 906 })); | |
| 907 } | |
| 908 | |
| 909 // 115 | |
| 910 bool s_doubleNextLine(int indent) { | |
| 911 if (!truth(s_doubleBreak(indent))) return false; | |
| 912 zeroOrOne(() { | |
| 913 if (!truth(ns_doubleChar())) return; | |
| 914 nb_ns_doubleInLine(); | |
| 915 or([ | |
| 916 () => s_doubleNextLine(indent), | |
| 917 () => zeroOrMore(() => consume(isSpace)) | |
| 918 ]); | |
| 919 }); | |
| 920 return true; | |
| 921 } | |
| 922 | |
| 923 // 116 | |
| 924 void nb_doubleMultiLine(int indent) { | |
| 925 nb_ns_doubleInLine(); | |
| 926 or([ | |
| 927 () => s_doubleNextLine(indent), | |
| 928 () => zeroOrMore(() => consume(isSpace)) | |
| 929 ]); | |
| 930 } | |
| 931 | |
| 932 // 117 | |
| 933 bool c_quotedQuote() => captureAs("'", () => rawString("''")); | |
| 934 | |
| 935 // 118 | |
| 936 bool nb_singleChar() => or([ | |
| 937 c_quotedQuote, | |
| 938 () => consume((c) => isJson(c) && c != SINGLE_QUOTE) | |
| 939 ]); | |
| 940 | |
| 941 // 119 | |
| 942 bool ns_singleChar() => !isSpace(peek()) && truth(nb_singleChar()); | |
| 943 | |
| 944 // 120 | |
| 945 _Node c_singleQuoted(int indent, int ctx) => context('string', () { | |
| 946 return transaction(() { | |
| 947 if (!truth(c_indicator(C_SINGLE_QUOTE))) return null; | |
| 948 var contents = nb_singleText(indent, ctx); | |
| 949 if (!truth(c_indicator(C_SINGLE_QUOTE))) return null; | |
| 950 return new _ScalarNode("!", contents); | |
| 951 }); | |
| 952 }); | |
| 953 | |
| 954 // 121 | |
| 955 String nb_singleText(int indent, int ctx) => captureString(() { | |
| 956 switch (ctx) { | |
| 957 case FLOW_OUT: | |
| 958 case FLOW_IN: | |
| 959 nb_singleMultiLine(indent); | |
| 960 break; | |
| 961 case BLOCK_KEY: | |
| 962 case FLOW_KEY: | |
| 963 nb_singleOneLine(indent); | |
| 964 break; | |
| 965 } | |
| 966 return true; | |
| 967 }); | |
| 968 | |
| 969 // 122 | |
| 970 void nb_singleOneLine(int indent) { | |
| 971 zeroOrMore(nb_singleChar); | |
| 972 } | |
| 973 | |
| 974 // 123 | |
| 975 void nb_ns_singleInLine() { | |
| 976 zeroOrMore(() => transaction(() { | |
| 977 zeroOrMore(() => consume(isSpace)); | |
| 978 return ns_singleChar(); | |
| 979 })); | |
| 980 } | |
| 981 | |
| 982 // 124 | |
| 983 bool s_singleNextLine(int indent) { | |
| 984 if (!truth(s_flowFolded(indent))) return false; | |
| 985 zeroOrOne(() { | |
| 986 if (!truth(ns_singleChar())) return; | |
| 987 nb_ns_singleInLine(); | |
| 988 or([ | |
| 989 () => s_singleNextLine(indent), | |
| 990 () => zeroOrMore(() => consume(isSpace)) | |
| 991 ]); | |
| 992 }); | |
| 993 return true; | |
| 994 } | |
| 995 | |
| 996 // 125 | |
| 997 void nb_singleMultiLine(int indent) { | |
| 998 nb_ns_singleInLine(); | |
| 999 or([ | |
| 1000 () => s_singleNextLine(indent), | |
| 1001 () => zeroOrMore(() => consume(isSpace)) | |
| 1002 ]); | |
| 1003 } | |
| 1004 | |
| 554 // 126 | 1005 // 126 |
| 555 bool ns_plainFirst(int ctx) { | 1006 bool ns_plainFirst(int ctx) { |
| 556 var char = peek(); | 1007 var char = peek(); |
| 557 var indicator = indicatorType(char); | 1008 var indicator = indicatorType(char); |
| 558 if (indicator == C_RESERVED) { | 1009 if (indicator == C_RESERVED) { |
| 559 error("reserved indicators can't start a plain scalar"); | 1010 error("reserved indicators can't start a plain scalar"); |
| 560 } | 1011 } |
| 561 var match = (isNonSpace(char) && indicator == null) || | 1012 var match = (isNonSpace(char) && indicator == null) || |
| 562 ((indicator == C_MAPPING_KEY || | 1013 ((indicator == C_MAPPING_KEY || |
| 563 indicator == C_MAPPING_VALUE || | 1014 indicator == C_MAPPING_VALUE || |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 593 var nonMappingColon = indicator == C_MAPPING_VALUE && | 1044 var nonMappingColon = indicator == C_MAPPING_VALUE && |
| 594 isPlainSafe(ctx, peek(1)); | 1045 isPlainSafe(ctx, peek(1)); |
| 595 var match = safeChar || nonCommentHash || nonMappingColon; | 1046 var match = safeChar || nonCommentHash || nonMappingColon; |
| 596 | 1047 |
| 597 if (match) next(); | 1048 if (match) next(); |
| 598 return match; | 1049 return match; |
| 599 } | 1050 } |
| 600 | 1051 |
| 601 // 131 | 1052 // 131 |
| 602 String ns_plain(int indent, int ctx) => context('plain scalar', () { | 1053 String ns_plain(int indent, int ctx) => context('plain scalar', () { |
| 603 switch (ctx) { | 1054 return captureString(() { |
| 604 case FLOW_OUT: | 1055 switch (ctx) { |
| 605 case FLOW_IN: | 1056 case FLOW_OUT: |
| 606 return ns_plainMultiLine(indent, ctx); | 1057 case FLOW_IN: |
| 607 case BLOCK_KEY: | 1058 return ns_plainMultiLine(indent, ctx); |
| 608 case FLOW_KEY: | 1059 case BLOCK_KEY: |
| 609 return ns_plainOneLine(ctx); | 1060 case FLOW_KEY: |
| 610 default: throw 'invalid context "$ctx"'; | 1061 return ns_plainOneLine(ctx); |
| 611 } | 1062 default: throw 'invalid context "$ctx"'; |
| 1063 } | |
| 1064 }); | |
| 612 }); | 1065 }); |
| 613 | 1066 |
| 614 // 132 | 1067 // 132 |
| 615 void nb_ns_plainInLine(int ctx) { | 1068 void nb_ns_plainInLine(int ctx) { |
| 616 zeroOrMore(() => transaction(() { | 1069 zeroOrMore(() => transaction(() { |
| 617 zeroOrMore(() => consume(isSpace)); | 1070 zeroOrMore(() => consume(isSpace)); |
| 618 return ns_plainChar(ctx); | 1071 return ns_plainChar(ctx); |
| 619 })); | 1072 })); |
| 620 } | 1073 } |
| 621 | 1074 |
| 622 // 133 | 1075 // 133 |
| 623 String ns_plainOneLine(int ctx) => captureString(() { | 1076 bool ns_plainOneLine(int ctx) { |
| 624 if (c_forbidden()) return false; | 1077 if (truth(c_forbidden())) return false; |
| 625 if (!ns_plainFirst(ctx)) return false; | 1078 if (!truth(ns_plainFirst(ctx))) return false; |
| 1079 nb_ns_plainInLine(ctx); | |
| 1080 return true; | |
| 1081 } | |
| 1082 | |
| 1083 // 134 | |
| 1084 bool s_ns_plainNextLine(int indent, int ctx) => transaction(() { | |
| 1085 if (!truth(s_flowFolded(indent))) return false; | |
| 1086 if (truth(c_forbidden())) return false; | |
| 1087 if (!truth(ns_plainChar(ctx))) return false; | |
| 626 nb_ns_plainInLine(ctx); | 1088 nb_ns_plainInLine(ctx); |
| 627 return true; | 1089 return true; |
| 628 }); | 1090 }); |
| 629 | 1091 |
| 630 // 134 | |
| 631 bool s_ns_plainNextLine(int indent, int ctx) => transaction(() { | |
| 632 if (c_forbidden()) return false; | |
| 633 if (!s_flowFolded(indent)) return false; | |
| 634 if (!ns_plainChar(ctx)) return false; | |
| 635 nb_ns_plainInLine(ctx); | |
| 636 return true; | |
| 637 }); | |
| 638 | |
| 639 // 135 | 1092 // 135 |
| 640 String ns_plainMultiLine(int indent, int ctx) => captureString(() { | 1093 bool ns_plainMultiLine(int indent, int ctx) { |
| 641 if (!truth(ns_plainOneLine(ctx))) return false; | 1094 if (!truth(ns_plainOneLine(ctx))) return false; |
| 642 zeroOrMore(() => s_ns_plainNextLine(indent, ctx)); | 1095 zeroOrMore(() => s_ns_plainNextLine(indent, ctx)); |
| 643 return true; | 1096 return true; |
| 1097 } | |
| 1098 | |
| 1099 // 136 | |
| 1100 int inFlow(int ctx) { | |
| 1101 switch (ctx) { | |
| 1102 case FLOW_OUT: | |
| 1103 case FLOW_IN: | |
| 1104 return FLOW_IN; | |
| 1105 case BLOCK_KEY: | |
| 1106 case FLOW_KEY: | |
| 1107 return FLOW_KEY; | |
| 1108 } | |
| 1109 } | |
| 1110 | |
| 1111 // 137 | |
| 1112 _SequenceNode c_flowSequence(int indent, int ctx) => transaction(() { | |
| 1113 if (!truth(c_indicator(C_SEQUENCE_START))) return null; | |
| 1114 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1115 var content = zeroOrOne(() => ns_s_flowSeqEntries(indent, inFlow(ctx))); | |
| 1116 if (!truth(c_indicator(C_SEQUENCE_END))) return null; | |
| 1117 return new _SequenceNode("?", new List<_Node>.from(content)); | |
| 644 }); | 1118 }); |
| 645 | 1119 |
| 1120 // 138 | |
| 1121 Collection<_Node> ns_s_flowSeqEntries(int indent, int ctx) { | |
| 1122 var first = ns_flowSeqEntry(indent, ctx); | |
| 1123 if (!truth(first)) return new Queue<_Node>(); | |
| 1124 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1125 | |
| 1126 var rest; | |
| 1127 if (truth(c_indicator(C_COLLECT_ENTRY))) { | |
| 1128 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1129 rest = zeroOrOne(() => ns_s_flowSeqEntries(indent, ctx)); | |
| 1130 } | |
| 1131 | |
| 1132 if (rest == null) rest = new Queue<_Node>(); | |
| 1133 rest.addFirst(first); | |
| 1134 | |
| 1135 return rest; | |
| 1136 } | |
| 1137 | |
| 1138 // 139 | |
| 1139 _Node ns_flowSeqEntry(int indent, int ctx) => or([ | |
| 1140 () => ns_flowPair(indent, ctx), | |
| 1141 () => ns_flowNode(indent, ctx) | |
| 1142 ]); | |
| 1143 | |
| 1144 // 140 | |
| 1145 _Node c_flowMapping(int indent, int ctx) { | |
| 1146 if (!truth(c_indicator(C_MAPPING_START))) return null; | |
| 1147 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1148 var content = zeroOrOne(() => ns_s_flowMapEntries(indent, inFlow(ctx))); | |
| 1149 if (!truth(c_indicator(C_MAPPING_END))) return null; | |
| 1150 return new _MappingNode("?", content); | |
| 1151 } | |
| 1152 | |
| 1153 // 141 | |
| 1154 YamlMap ns_s_flowMapEntries(int indent, int ctx) { | |
| 1155 var first = ns_flowMapEntry(indent, ctx); | |
| 1156 if (!truth(first)) return new YamlMap(); | |
| 1157 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1158 | |
| 1159 var rest; | |
| 1160 if (truth(c_indicator(C_COLLECT_ENTRY))) { | |
| 1161 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1162 rest = ns_s_flowMapEntries(indent, ctx); | |
| 1163 } | |
| 1164 | |
| 1165 if (rest == null) rest = new YamlMap(); | |
| 1166 | |
| 1167 // TODO(nweiz): Duplicate keys should be an error. This includes keys with | |
| 1168 // different representations but the same value (e.g. 10 vs 0xa). To make | |
| 1169 // this user-friendly we'll probably also want to associate nodes with a | |
| 1170 // source range. | |
| 1171 if (!rest.containsKey(first.first)) rest[first.first] = first.last; | |
| 1172 | |
| 1173 return rest; | |
| 1174 } | |
| 1175 | |
| 1176 // 142 | |
| 1177 _Pair<_Node, _Node> ns_flowMapEntry(int indent, int ctx) => or([ | |
| 1178 () => transaction(() { | |
| 1179 if (!truth(c_indicator(C_MAPPING_KEY))) return false; | |
| 1180 if (!truth(s_separate(indent, ctx))) return false; | |
| 1181 return ns_flowMapExplicitEntry(indent, ctx); | |
| 1182 }), | |
| 1183 () => ns_flowMapImplicitEntry(indent, ctx) | |
| 1184 ]); | |
| 1185 | |
| 1186 // 143 | |
| 1187 _Pair<_Node, _Node> ns_flowMapExplicitEntry(int indent, int ctx) => or([ | |
| 1188 () => ns_flowMapImplicitEntry(indent, ctx), | |
| 1189 () => new _Pair<_Node, _Node>(e_node(), e_node()) | |
| 1190 ]); | |
| 1191 | |
| 1192 // 144 | |
| 1193 _Pair<_Node, _Node> ns_flowMapImplicitEntry(int indent, int ctx) => or([ | |
| 1194 () => ns_flowMapYamlKeyEntry(indent, ctx), | |
| 1195 () => c_ns_flowMapEmptyKeyEntry(indent, ctx), | |
| 1196 () => c_ns_flowMapJsonKeyEntry(indent, ctx) | |
| 1197 ]); | |
| 1198 | |
| 1199 // 145 | |
| 1200 _Pair<_Node, _Node> ns_flowMapYamlKeyEntry(int indent, int ctx) { | |
| 1201 var key = ns_flowYamlNode(indent, ctx); | |
| 1202 if (!truth(key)) return null; | |
| 1203 var value = or([ | |
| 1204 () => transaction(() { | |
| 1205 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1206 return c_ns_flowMapSeparateValue(indent, ctx); | |
| 1207 }), | |
| 1208 e_node | |
| 1209 ]); | |
| 1210 return new _Pair<_Node, _Node>(key, value); | |
| 1211 } | |
| 1212 | |
| 1213 // 146 | |
| 1214 _Pair<_Node, _Node> c_ns_flowMapEmptyKeyEntry(int indent, int ctx) { | |
| 1215 var value = c_ns_flowMapSeparateValue(indent, ctx); | |
| 1216 if (!truth(value)) return null; | |
| 1217 return new _Pair<_Node, _Node>(e_node(), value); | |
| 1218 } | |
| 1219 | |
| 1220 // 147 | |
| 1221 _Node c_ns_flowMapSeparateValue(int indent, int ctx) => transaction(() { | |
| 1222 if (!truth(c_indicator(C_MAPPING_VALUE))) return null; | |
| 1223 if (isPlainSafe(ctx, peek())) return null; | |
| 1224 | |
| 1225 return or([ | |
| 1226 () => transaction(() { | |
| 1227 if (!s_separate(indent, ctx)) return null; | |
| 1228 return ns_flowNode(indent, ctx); | |
| 1229 }), | |
| 1230 e_node | |
| 1231 ]); | |
| 1232 }); | |
| 1233 | |
| 1234 // 148 | |
| 1235 _Pair<_Node, _Node> c_ns_flowMapJsonKeyEntry(int indent, int ctx) { | |
| 1236 var key = c_flowJsonNode(indent, ctx); | |
| 1237 if (!truth(key)) return null; | |
| 1238 var value = or([ | |
| 1239 () => transaction(() { | |
| 1240 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1241 return c_ns_flowMapAdjacentValue(indent, ctx); | |
| 1242 }), | |
| 1243 e_node | |
| 1244 ]); | |
| 1245 return new _Pair<_Node, _Node>(key, value); | |
| 1246 } | |
| 1247 | |
| 1248 // 149 | |
| 1249 _Node c_ns_flowMapAdjacentValue(int indent, int ctx) { | |
| 1250 if (!truth(c_indicator(C_MAPPING_VALUE))) return null; | |
| 1251 return or([ | |
| 1252 () => transaction(() { | |
| 1253 zeroOrOne(() => s_separate(indent, ctx)); | |
| 1254 return ns_flowNode(indent, ctx); | |
| 1255 }), | |
| 1256 e_node | |
| 1257 ]); | |
| 1258 } | |
| 1259 | |
| 1260 // 150 | |
| 1261 _Node ns_flowPair(int indent, int ctx) { | |
| 1262 var pair = or([ | |
| 1263 () => transaction(() { | |
| 1264 if (!truth(c_indicator(C_MAPPING_KEY))) return null; | |
| 1265 if (!truth(s_separate(indent, ctx))) return null; | |
| 1266 return ns_flowMapExplicitEntry(indent, ctx); | |
| 1267 }), | |
| 1268 () => ns_flowPairEntry(indent, ctx) | |
| 1269 ]); | |
| 1270 if (!truth(pair)) return null; | |
| 1271 | |
| 1272 return map([pair]); | |
| 1273 } | |
| 1274 | |
| 1275 // 151 | |
| 1276 _Pair<_Node, _Node> ns_flowPairEntry(int indent, int ctx) => or([ | |
| 1277 () => ns_flowPairYamlKeyEntry(indent, ctx), | |
| 1278 () => c_ns_flowMapEmptyKeyEntry(indent, ctx), | |
| 1279 () => c_ns_flowPairJsonKeyEntry(indent, ctx) | |
| 1280 ]); | |
| 1281 | |
| 1282 // 152 | |
| 1283 _Pair<_Node, _Node> ns_flowPairYamlKeyEntry(int indent, int ctx) => | |
| 1284 transaction(() { | |
| 1285 var key = ns_s_implicitYamlKey(FLOW_KEY); | |
| 1286 if (!truth(key)) return null; | |
| 1287 var value = c_ns_flowMapSeparateValue(indent, ctx); | |
| 1288 if (!truth(value)) return null; | |
| 1289 return new _Pair<_Node, _Node>(key, value); | |
| 1290 }); | |
| 1291 | |
| 1292 // 153 | |
| 1293 _Pair<_Node, _Node> c_ns_flowPairJsonKeyEntry(int indent, int ctx) => | |
| 1294 transaction(() { | |
| 1295 var key = c_s_implicitJsonKey(FLOW_KEY); | |
| 1296 if (!truth(key)) return null; | |
| 1297 var value = c_ns_flowMapAdjacentValue(indent, ctx); | |
| 1298 if (!truth(value)) return null; | |
| 1299 return new _Pair<_Node, _Node>(key, value); | |
| 1300 }); | |
| 1301 | |
| 646 // 154 | 1302 // 154 |
| 647 _Node c_s_implicitYamlKey(int ctx) => transaction(() { | 1303 _Node ns_s_implicitYamlKey(int ctx) => transaction(() { |
| 1304 // TODO(nweiz): this is supposed to be limited to 1024 characters. | |
| 1305 | |
| 648 // The indentation parameter is "null" since it's unused in this path | 1306 // The indentation parameter is "null" since it's unused in this path |
| 649 var node = ns_flowYamlNode(null, ctx); | 1307 var node = ns_flowYamlNode(null, ctx); |
| 650 if (!truth(node)) return null; | 1308 if (!truth(node)) return null; |
| 651 zeroOrOne(s_separateInLine); | 1309 zeroOrOne(s_separateInLine); |
| 652 return node; | 1310 return node; |
| 653 }); | 1311 }); |
| 654 | 1312 |
| 655 // 155 | 1313 // 155 |
| 656 _Node c_s_implicitJsonKey(int ctx) => null; // TODO(nweiz): implement | 1314 _Node c_s_implicitJsonKey(int ctx) => transaction(() { |
| 1315 // TODO(nweiz): this is supposed to be limited to 1024 characters. | |
| 1316 | |
| 1317 // The indentation parameter is "null" since it's unused in this path | |
| 1318 var node = c_flowJsonNode(null, ctx); | |
| 1319 if (!truth(node)) return null; | |
| 1320 zeroOrOne(s_separateInLine); | |
| 1321 return node; | |
| 1322 }); | |
| 657 | 1323 |
| 658 // 156 | 1324 // 156 |
| 659 _Node ns_flowYamlContent(int indent, int ctx) { | 1325 _Node ns_flowYamlContent(int indent, int ctx) { |
| 660 var str = ns_plain(indent, ctx); | 1326 var str = ns_plain(indent, ctx); |
| 661 if (!truth(str)) return null; | 1327 if (!truth(str)) return null; |
| 662 return new _ScalarNode("?", content: str); | 1328 return new _ScalarNode("?", content: str); |
| 663 } | 1329 } |
| 664 | 1330 |
| 665 // 157 | 1331 // 157 |
| 666 // TODO(nweiz): implement | 1332 _Node c_flowJsonContent(int indent, int ctx) => or([ |
| 667 _Node ns_flowJsonContent(int indent, int ctx) => null; | 1333 () => c_flowSequence(indent, ctx), |
| 1334 () => c_flowMapping(indent, ctx), | |
| 1335 () => c_singleQuoted(indent, ctx), | |
| 1336 () => c_doubleQuoted(indent, ctx) | |
| 1337 ]); | |
| 668 | 1338 |
| 669 // 158 | 1339 // 158 |
| 670 _Node ns_flowContent(int indent, int ctx) => or([ | 1340 _Node ns_flowContent(int indent, int ctx) => or([ |
| 671 () => ns_flowYamlContent(indent, ctx), | 1341 () => ns_flowYamlContent(indent, ctx), |
| 672 () => ns_flowJsonContent(indent, ctx) | 1342 () => c_flowJsonContent(indent, ctx) |
| 673 ]); | 1343 ]); |
| 674 | 1344 |
| 675 // 159 | 1345 // 159 |
| 676 _Node ns_flowYamlNode(int indent, int ctx) => or([ | 1346 _Node ns_flowYamlNode(int indent, int ctx) => or([ |
| 677 c_ns_aliasNode, | 1347 c_ns_aliasNode, |
| 678 () => ns_flowYamlContent(indent, ctx), | 1348 () => ns_flowYamlContent(indent, ctx), |
| 679 () { | 1349 () { |
| 680 var props = c_ns_properties(indent, ctx); | 1350 var props = c_ns_properties(indent, ctx); |
| 681 if (!truth(props)) return null; | 1351 if (!truth(props)) return null; |
| 682 var node = or([ | 1352 var node = or([ |
| 683 () => transaction(() { | 1353 () => transaction(() { |
| 684 if (!s_separate(indent, ctx)) return null; | 1354 if (!truth(s_separate(indent, ctx))) return null; |
| 685 return ns_flowYamlContent(indent, ctx); | 1355 return ns_flowYamlContent(indent, ctx); |
| 686 }), | 1356 }), |
| 687 e_scalar | 1357 e_scalar |
| 688 ]); | 1358 ]); |
| 689 return addProps(node, props); | 1359 return addProps(node, props); |
| 690 } | 1360 } |
| 691 ]); | 1361 ]); |
| 692 | 1362 |
| 1363 // 160 | |
| 1364 _Node c_flowJsonNode(int indent, int ctx) => transaction(() { | |
| 1365 var props; | |
| 1366 zeroOrOne(() => transaction(() { | |
| 1367 props = c_ns_properties(indent, ctx); | |
| 1368 if (!truth(props)) return null; | |
| 1369 return s_separate(indent, ctx); | |
| 1370 })); | |
| 1371 | |
| 1372 return addProps(c_flowJsonContent(indent, ctx), props); | |
| 1373 }); | |
| 1374 | |
| 693 // 161 | 1375 // 161 |
| 694 _Node ns_flowNode(int indent, int ctx) => or([ | 1376 _Node ns_flowNode(int indent, int ctx) => or([ |
| 695 c_ns_aliasNode, | 1377 c_ns_aliasNode, |
| 696 () => ns_flowContent(indent, ctx), | 1378 () => ns_flowContent(indent, ctx), |
| 697 () => transaction(() { | 1379 () => transaction(() { |
| 698 var props = c_ns_properties(indent, ctx); | 1380 var props = c_ns_properties(indent, ctx); |
| 699 if (!truth(props)) return null; | 1381 if (!truth(props)) return null; |
| 700 var node = or([ | 1382 var node = or([ |
| 701 () => transaction(() => s_separate(indent, ctx) ? | 1383 () => transaction(() => s_separate(indent, ctx) ? |
| 702 ns_flowContent(indent, ctx) : null), | 1384 ns_flowContent(indent, ctx) : null), |
| 703 e_scalar]); | 1385 e_scalar]); |
| 704 return addProps(node, props); | 1386 return addProps(node, props); |
| 705 }) | 1387 }) |
| 706 ]); | 1388 ]); |
| 707 | 1389 |
| 1390 // 162 | |
| 1391 _BlockHeader c_b_blockHeader() => transaction(() { | |
| 1392 var indentation = c_indentationIndicator(); | |
| 1393 var chomping = c_chompingIndicator(); | |
| 1394 if (!truth(indentation)) indentation = c_indentationIndicator(); | |
| 1395 if (!truth(s_b_comment())) return null; | |
| 1396 | |
| 1397 return new _BlockHeader(indentation, chomping); | |
| 1398 }); | |
| 1399 | |
| 1400 // 163 | |
| 1401 int c_indentationIndicator() { | |
| 1402 if (!isDecDigit(peek())) return null; | |
| 1403 return next() - NUMBER_0; | |
| 1404 } | |
| 1405 | |
| 1406 // 164 | |
| 1407 int c_chompingIndicator() { | |
| 1408 switch (peek()) { | |
| 1409 case HYPHEN: | |
| 1410 next(); | |
| 1411 return CHOMPING_STRIP; | |
| 1412 case PLUS: | |
| 1413 next(); | |
| 1414 return CHOMPING_KEEP; | |
| 1415 default: | |
| 1416 return CHOMPING_CLIP; | |
| 1417 } | |
| 1418 } | |
| 1419 | |
| 1420 // 165 | |
| 1421 bool b_chompedLast(int chomping) { | |
| 1422 if (atEndOfFile) return true; | |
| 1423 switch (chomping) { | |
| 1424 case CHOMPING_STRIP: | |
| 1425 return b_nonContent(); | |
| 1426 case CHOMPING_CLIP: | |
| 1427 case CHOMPING_KEEP: | |
| 1428 return b_asLineFeed(); | |
| 1429 } | |
| 1430 } | |
| 1431 | |
| 1432 // 166 | |
| 1433 void l_chompedEmpty(int indent, int chomping) { | |
| 1434 switch (chomping) { | |
| 1435 case CHOMPING_STRIP: | |
| 1436 case CHOMPING_CLIP: | |
| 1437 l_stripEmpty(indent); | |
| 1438 break; | |
| 1439 case CHOMPING_KEEP: | |
| 1440 l_keepEmpty(indent); | |
| 1441 break; | |
| 1442 } | |
| 1443 } | |
| 1444 | |
| 1445 // 167 | |
| 1446 void l_stripEmpty(int indent) => captureAs('', () { | |
| 1447 zeroOrMore(() => transaction(() { | |
| 1448 if (!truth(s_indentLessThanOrEqualTo(indent))) return false; | |
| 1449 return b_nonContent(); | |
| 1450 })); | |
| 1451 zeroOrOne(() => l_trailComments(indent)); | |
| 1452 return true; | |
| 1453 }); | |
| 1454 | |
| 1455 // 168 | |
| 1456 void l_keepEmpty(int indent) { | |
| 1457 zeroOrMore(() => captureAs('\n', () => l_empty(indent, BLOCK_IN))); | |
| 1458 zeroOrOne(() => captureAs('', () => l_trailComments(indent))); | |
| 1459 } | |
| 1460 | |
| 1461 // 169 | |
| 1462 bool l_trailComments(int indent) => transaction(() { | |
| 1463 if (!truth(s_indentLessThanOrEqualTo(indent))) return false; | |
| 1464 if (!truth(c_nb_commentText())) return false; | |
| 1465 if (!truth(b_comment())) return false; | |
| 1466 zeroOrMore(l_comment); | |
| 1467 return true; | |
| 1468 }); | |
| 1469 | |
| 708 // 170 | 1470 // 170 |
| 709 _Node c_l_literal(int indent) => null; // TODO(nweiz); implement | 1471 _Node c_l_literal(int indent) => transaction(() { |
| 1472 if (!truth(c_indicator(C_LITERAL))) return null; | |
| 1473 var header = c_b_blockHeader(); | |
| 1474 if (!truth(header)) return null; | |
| 1475 | |
| 1476 var additionalIndent = blockScalarAdditionalIndentation(header, indent); | |
| 1477 var content = l_literalContent(indent + additionalIndent, header.chomping); | |
| 1478 if (!truth(content)) return null; | |
| 1479 | |
| 1480 return new _ScalarNode("!", content); | |
| 1481 }); | |
| 1482 | |
| 1483 // 171 | |
| 1484 bool l_nb_literalText(int indent) => transaction(() { | |
| 1485 zeroOrMore(() => captureAs("\n", () => l_empty(indent, BLOCK_IN))); | |
| 1486 if (!truth(captureAs("", () => s_indent(indent)))) return false; | |
| 1487 return truth(oneOrMore(() => consume(isNonBreak))); | |
| 1488 }); | |
| 1489 | |
| 1490 // 172 | |
| 1491 bool b_nb_literalNext(int indent) => transaction(() { | |
| 1492 if (!truth(b_asLineFeed())) return false; | |
| 1493 return l_nb_literalText(indent); | |
| 1494 }); | |
| 1495 | |
| 1496 // 173 | |
| 1497 String l_literalContent(int indent, int chomping) => captureString(() { | |
| 1498 transaction(() { | |
| 1499 if (!truth(l_nb_literalText(indent))) return false; | |
| 1500 zeroOrMore(() => b_nb_literalNext(indent)); | |
| 1501 return b_chompedLast(chomping); | |
| 1502 }); | |
| 1503 l_chompedEmpty(indent, chomping); | |
| 1504 return true; | |
| 1505 }); | |
| 710 | 1506 |
| 711 // 174 | 1507 // 174 |
| 712 _Node c_l_folded(int indent) => null; // TODO(nweiz); implement | 1508 _Node c_l_folded(int indent) => transaction(() { |
| 1509 if (!truth(c_indicator(C_FOLDED))) return null; | |
| 1510 var header = c_b_blockHeader(); | |
| 1511 if (!truth(header)) return null; | |
| 1512 | |
| 1513 var additionalIndent = blockScalarAdditionalIndentation(header, indent); | |
| 1514 var content = l_foldedContent(indent + additionalIndent, header.chomping); | |
| 1515 if (!truth(content)) return null; | |
| 1516 | |
| 1517 return new _ScalarNode("!", content); | |
| 1518 }); | |
| 1519 | |
| 1520 // 175 | |
| 1521 bool s_nb_foldedText(int indent) => transaction(() { | |
| 1522 if (!truth(captureAs('', () => s_indent(indent)))) return false; | |
| 1523 if (!truth(consume(isNonSpace))) return false; | |
| 1524 zeroOrMore(() => consume(isNonBreak)); | |
| 1525 return true; | |
| 1526 }); | |
| 1527 | |
| 1528 // 176 | |
| 1529 bool l_nb_foldedLines(int indent) { | |
| 1530 if (!truth(s_nb_foldedText(indent))) return false; | |
| 1531 zeroOrMore(() => transaction(() { | |
| 1532 if (!truth(b_l_folded(indent, BLOCK_IN))) return false; | |
| 1533 return s_nb_foldedText(indent); | |
| 1534 })); | |
| 1535 return true; | |
| 1536 } | |
| 1537 | |
| 1538 // 177 | |
| 1539 bool s_nb_spacedText(int indent) => transaction(() { | |
| 1540 if (!truth(captureAs('', () => s_indent(indent)))) return false; | |
| 1541 if (!truth(consume(isSpace))) return false; | |
| 1542 zeroOrMore(() => consume(isNonBreak)); | |
| 1543 return true; | |
| 1544 }); | |
| 1545 | |
| 1546 // 178 | |
| 1547 bool b_l_spaced(int indent) { | |
| 1548 if (!truth(b_asLineFeed())) return false; | |
| 1549 zeroOrMore(() => captureAs("\n", () => l_empty(indent, BLOCK_IN))); | |
| 1550 return true; | |
| 1551 } | |
| 1552 | |
| 1553 // 179 | |
| 1554 bool l_nb_spacedLines(int indent) { | |
| 1555 if (!truth(s_nb_spacedText(indent))) return false; | |
| 1556 zeroOrMore(() => transaction(() { | |
| 1557 if (!truth(b_l_spaced(indent))) return false; | |
| 1558 return s_nb_spacedText(indent); | |
| 1559 })); | |
| 1560 return true; | |
| 1561 } | |
| 1562 | |
| 1563 // 180 | |
| 1564 bool l_nb_sameLines(int indent) => transaction(() { | |
| 1565 zeroOrMore(() => captureAs('\n', () => l_empty(indent, BLOCK_IN))); | |
| 1566 return or([ | |
| 1567 () => l_nb_foldedLines(indent), | |
| 1568 () => l_nb_spacedLines(indent) | |
| 1569 ]); | |
| 1570 }); | |
| 1571 | |
| 1572 // 181 | |
| 1573 bool l_nb_diffLines(int indent) { | |
| 1574 if (!truth(l_nb_sameLines(indent))) return false; | |
| 1575 zeroOrMore(() => transaction(() { | |
| 1576 if (!truth(b_asLineFeed())) return false; | |
| 1577 return l_nb_sameLines(indent); | |
| 1578 })); | |
| 1579 return true; | |
| 1580 } | |
| 1581 | |
| 1582 // 182 | |
| 1583 String l_foldedContent(int indent, int chomping) => captureString(() { | |
| 1584 transaction(() { | |
| 1585 if (!truth(l_nb_diffLines(indent))) return false; | |
| 1586 return b_chompedLast(chomping); | |
| 1587 }); | |
| 1588 l_chompedEmpty(indent, chomping); | |
| 1589 return true; | |
| 1590 }); | |
| 713 | 1591 |
| 714 // 183 | 1592 // 183 |
| 715 _SequenceNode l_blockSequence(int indent) => context('sequence', () { | 1593 _SequenceNode l_blockSequence(int indent) => context('sequence', () { |
| 716 var additionalIndent = countIndentation() - indent; | 1594 var additionalIndent = countIndentation() - indent; |
| 717 if (additionalIndent <= 0) return null; | 1595 if (additionalIndent <= 0) return null; |
| 718 | 1596 |
| 719 var content = oneOrMore(() => transaction(() { | 1597 var content = oneOrMore(() => transaction(() { |
| 720 if (!s_indent(indent + additionalIndent)) return null; | 1598 if (!truth(s_indent(indent + additionalIndent))) return null; |
| 721 return c_l_blockSeqEntry(indent + additionalIndent); | 1599 return c_l_blockSeqEntry(indent + additionalIndent); |
| 722 })); | 1600 })); |
| 723 if (!truth(content)) return null; | 1601 if (!truth(content)) return null; |
| 724 | 1602 |
| 725 return new _SequenceNode("?", content); | 1603 return new _SequenceNode("?", content); |
| 726 }); | 1604 }); |
| 727 | 1605 |
| 728 // 184 | 1606 // 184 |
| 729 _Node c_l_blockSeqEntry(int indent) => transaction(() { | 1607 _Node c_l_blockSeqEntry(int indent) => transaction(() { |
| 730 if (!c_indicator(C_SEQUENCE_ENTRY)) return null; | 1608 if (!truth(c_indicator(C_SEQUENCE_ENTRY))) return null; |
| 731 if (isNonSpace(peek())) return null; | 1609 if (isNonSpace(peek())) return null; |
| 732 | 1610 |
| 733 return s_l_blockIndented(indent, BLOCK_IN); | 1611 return s_l_blockIndented(indent, BLOCK_IN); |
| 734 }); | 1612 }); |
| 735 | 1613 |
| 736 // 185 | 1614 // 185 |
| 737 _Node s_l_blockIndented(int indent, int ctx) { | 1615 _Node s_l_blockIndented(int indent, int ctx) { |
| 738 var additionalIndent = countIndentation(); | 1616 var additionalIndent = countIndentation(); |
| 739 return or([ | 1617 return or([ |
| 740 () => transaction(() { | 1618 () => transaction(() { |
| 741 if (!s_indent(additionalIndent)) return null; | 1619 if (!truth(s_indent(additionalIndent))) return null; |
| 742 return or([ | 1620 return or([ |
| 743 () => ns_l_compactSequence(indent + 1 + additionalIndent), | 1621 () => ns_l_compactSequence(indent + 1 + additionalIndent), |
| 744 () => ns_l_compactMapping(indent + 1 + additionalIndent)]); | 1622 () => ns_l_compactMapping(indent + 1 + additionalIndent)]); |
| 745 }), | 1623 }), |
| 746 () => s_l_blockNode(indent, ctx), | 1624 () => s_l_blockNode(indent, ctx), |
| 747 () => s_l_comments() ? e_node() : null]); | 1625 () => s_l_comments() ? e_node() : null]); |
| 748 } | 1626 } |
| 749 | 1627 |
| 750 // 186 | 1628 // 186 |
| 751 _Node ns_l_compactSequence(int indent) => context('sequence', () { | 1629 _Node ns_l_compactSequence(int indent) => context('sequence', () { |
| 752 var first = c_l_blockSeqEntry(indent); | 1630 var first = c_l_blockSeqEntry(indent); |
| 753 if (!truth(first)) return null; | 1631 if (!truth(first)) return null; |
| 754 | 1632 |
| 755 var content = zeroOrMore(() => transaction(() { | 1633 var content = zeroOrMore(() => transaction(() { |
| 756 if (!s_indent(indent)) return null; | 1634 if (!truth(s_indent(indent))) return null; |
| 757 return c_l_blockSeqEntry(indent); | 1635 return c_l_blockSeqEntry(indent); |
| 758 })); | 1636 })); |
| 759 content.insertRange(0, 1, first); | 1637 content.insertRange(0, 1, first); |
| 760 | 1638 |
| 761 return new _SequenceNode("?", content); | 1639 return new _SequenceNode("?", content); |
| 762 }); | 1640 }); |
| 763 | 1641 |
| 764 // 187 | 1642 // 187 |
| 765 _Node l_blockMapping(int indent) => context('mapping', () { | 1643 _Node l_blockMapping(int indent) => context('mapping', () { |
| 766 var additionalIndent = countIndentation() - indent; | 1644 var additionalIndent = countIndentation() - indent; |
| 767 if (additionalIndent <= 0) return null; | 1645 if (additionalIndent <= 0) return null; |
| 768 | 1646 |
| 769 var pairs = oneOrMore(() => transaction(() { | 1647 var pairs = oneOrMore(() => transaction(() { |
| 770 if (!s_indent(indent + additionalIndent)) return null; | 1648 if (!truth(s_indent(indent + additionalIndent))) return null; |
| 771 return ns_l_blockMapEntry(indent + additionalIndent); | 1649 return ns_l_blockMapEntry(indent + additionalIndent); |
| 772 })); | 1650 })); |
| 773 if (!truth(pairs)) return null; | 1651 if (!truth(pairs)) return null; |
| 774 | 1652 |
| 775 return map(pairs); | 1653 return map(pairs); |
| 776 }); | 1654 }); |
| 777 | 1655 |
| 778 // 188 | 1656 // 188 |
| 779 _Pair<_Node, _Node> ns_l_blockMapEntry(int indent) => or([ | 1657 _Pair<_Node, _Node> ns_l_blockMapEntry(int indent) => or([ |
| 780 () => c_l_blockMapExplicitEntry(indent), | 1658 () => c_l_blockMapExplicitEntry(indent), |
| 781 () => ns_l_blockMapImplicitEntry(indent) | 1659 () => ns_l_blockMapImplicitEntry(indent) |
| 782 ]); | 1660 ]); |
| 783 | 1661 |
| 784 // 189 | 1662 // 189 |
| 785 // TODO(nweiz): implement | 1663 _Pair<_Node, _Node> c_l_blockMapExplicitEntry(int indent) { |
| 786 _Pair<_Node, _Node> c_l_blockMapExplicitEntry(int indent) => null; | 1664 var key = c_l_blockMapExplicitKey(indent); |
| 1665 if (!truth(key)) return null; | |
| 1666 | |
| 1667 var value = or([ | |
| 1668 () => l_blockMapExplicitValue(indent), | |
| 1669 e_node | |
| 1670 ]); | |
| 1671 | |
| 1672 return new _Pair<_Node, _Node>(key, value); | |
| 1673 } | |
| 1674 | |
| 1675 // 190 | |
| 1676 _Node c_l_blockMapExplicitKey(int indent) => transaction(() { | |
| 1677 if (!truth(c_indicator(C_MAPPING_KEY))) return null; | |
| 1678 return s_l_blockIndented(indent, BLOCK_OUT); | |
| 1679 }); | |
| 1680 | |
| 1681 // 191 | |
| 1682 _Node l_blockMapExplicitValue(int indent) => transaction(() { | |
| 1683 if (!truth(s_indent(indent))) return null; | |
| 1684 if (!truth(c_indicator(C_MAPPING_VALUE))) return null; | |
| 1685 return s_l_blockIndented(indent, BLOCK_OUT); | |
| 1686 }); | |
| 787 | 1687 |
| 788 // 192 | 1688 // 192 |
| 789 _Pair<_Node, _Node> ns_l_blockMapImplicitEntry(int indent) => transaction(() { | 1689 _Pair<_Node, _Node> ns_l_blockMapImplicitEntry(int indent) => transaction(() { |
| 790 var key = or([ns_s_blockMapImplicitKey, e_node]); | 1690 var key = or([ns_s_blockMapImplicitKey, e_node]); |
| 791 var value = c_l_blockMapImplicitValue(indent); | 1691 var value = c_l_blockMapImplicitValue(indent); |
| 792 return truth(value) ? new _Pair<_Node, _Node>(key, value) : null; | 1692 return truth(value) ? new _Pair<_Node, _Node>(key, value) : null; |
| 793 }); | 1693 }); |
| 794 | 1694 |
| 795 // 193 | 1695 // 193 |
| 796 _Node ns_s_blockMapImplicitKey() => context('mapping key', () => or([ | 1696 _Node ns_s_blockMapImplicitKey() => context('mapping key', () => or([ |
| 797 () => c_s_implicitJsonKey(BLOCK_KEY), | 1697 () => c_s_implicitJsonKey(BLOCK_KEY), |
| 798 () => c_s_implicitYamlKey(BLOCK_KEY) | 1698 () => ns_s_implicitYamlKey(BLOCK_KEY) |
| 799 ])); | 1699 ])); |
| 800 | 1700 |
| 801 // 194 | 1701 // 194 |
| 802 _Node c_l_blockMapImplicitValue(int indent) => context('mapping value', () => | 1702 _Node c_l_blockMapImplicitValue(int indent) => context('mapping value', () => |
| 803 transaction(() { | 1703 transaction(() { |
| 804 if (!c_indicator(C_MAPPING_VALUE)) return null; | 1704 if (!truth(c_indicator(C_MAPPING_VALUE))) return null; |
| 805 return or([ | 1705 return or([ |
| 806 () => s_l_blockNode(indent, BLOCK_OUT), | 1706 () => s_l_blockNode(indent, BLOCK_OUT), |
| 807 () => s_l_comments() ? e_node() : null | 1707 () => s_l_comments() ? e_node() : null |
| 808 ]); | 1708 ]); |
| 809 })); | 1709 })); |
| 810 | 1710 |
| 811 // 195 | 1711 // 195 |
| 812 _Node ns_l_compactMapping(int indent) => context('mapping', () { | 1712 _Node ns_l_compactMapping(int indent) => context('mapping', () { |
| 813 var first = ns_l_blockMapEntry(indent); | 1713 var first = ns_l_blockMapEntry(indent); |
| 814 if (!truth(first)) return null; | 1714 if (!truth(first)) return null; |
| 815 | 1715 |
| 816 var pairs = zeroOrMore(() => transaction(() { | 1716 var pairs = zeroOrMore(() => transaction(() { |
| 817 if (!s_indent(indent)) return null; | 1717 if (!truth(s_indent(indent))) return null; |
| 818 return ns_l_blockMapEntry(indent); | 1718 return ns_l_blockMapEntry(indent); |
| 819 })); | 1719 })); |
| 820 pairs.insertRange(0, 1, first); | 1720 pairs.insertRange(0, 1, first); |
| 821 | 1721 |
| 822 return map(pairs); | 1722 return map(pairs); |
| 823 }); | 1723 }); |
| 824 | 1724 |
| 825 // 196 | 1725 // 196 |
| 826 _Node s_l_blockNode(int indent, int ctx) => or([ | 1726 _Node s_l_blockNode(int indent, int ctx) => or([ |
| 827 () => s_l_blockInBlock(indent, ctx), | 1727 () => s_l_blockInBlock(indent, ctx), |
| 828 () => s_l_flowInBlock(indent) | 1728 () => s_l_flowInBlock(indent) |
| 829 ]); | 1729 ]); |
| 830 | 1730 |
| 831 // 197 | 1731 // 197 |
| 832 _Node s_l_flowInBlock(int indent) => transaction(() { | 1732 _Node s_l_flowInBlock(int indent) => transaction(() { |
| 833 if (!s_separate(indent + 1, FLOW_OUT)) return null; | 1733 if (!truth(s_separate(indent + 1, FLOW_OUT))) return null; |
| 834 var node = ns_flowNode(indent + 1, FLOW_OUT); | 1734 var node = ns_flowNode(indent + 1, FLOW_OUT); |
| 835 if (!truth(node)) return null; | 1735 if (!truth(node)) return null; |
| 836 if (!s_l_comments()) return null; | 1736 if (!truth(s_l_comments())) return null; |
| 837 return node; | 1737 return node; |
| 838 }); | 1738 }); |
| 839 | 1739 |
| 840 // 198 | 1740 // 198 |
| 841 _Node s_l_blockInBlock(int indent, int ctx) => or([ | 1741 _Node s_l_blockInBlock(int indent, int ctx) => or([ |
| 842 () => s_l_blockScalar(indent, ctx), | 1742 () => s_l_blockScalar(indent, ctx), |
| 843 () => s_l_blockCollection(indent, ctx) | 1743 () => s_l_blockCollection(indent, ctx) |
| 844 ]); | 1744 ]); |
| 845 | 1745 |
| 846 // 199 | 1746 // 199 |
| 847 _Node s_l_blockScalar(int indent, int ctx) => transaction(() { | 1747 _Node s_l_blockScalar(int indent, int ctx) => transaction(() { |
| 848 if (!s_separate(indent + 1, ctx)) return null; | 1748 if (!truth(s_separate(indent + 1, ctx))) return null; |
| 849 var props = transaction(() { | 1749 var props = transaction(() { |
| 850 var props = c_ns_properties(indent + 1, ctx); | 1750 var props = c_ns_properties(indent + 1, ctx); |
| 851 if (!truth(props)) return null; | 1751 if (!truth(props)) return null; |
| 852 if (!s_separate(indent + 1, ctx)) return null; | 1752 if (!truth(s_separate(indent + 1, ctx))) return null; |
| 853 return props; | 1753 return props; |
| 854 }); | 1754 }); |
| 855 if (!truth(props)) props = new _Pair<_Tag, String>(null, null); | |
| 856 | 1755 |
| 857 var node = or([() => c_l_literal(indent), () => c_l_folded(indent)]); | 1756 var node = or([() => c_l_literal(indent), () => c_l_folded(indent)]); |
| 858 if (!truth(node)) return null; | 1757 if (!truth(node)) return null; |
| 859 return addProps(node, props); | 1758 return addProps(node, props); |
| 860 }); | 1759 }); |
| 861 | 1760 |
| 862 // 200 | 1761 // 200 |
| 863 _Node s_l_blockCollection(int indent, int ctx) => transaction(() { | 1762 _Node s_l_blockCollection(int indent, int ctx) => transaction(() { |
| 864 var props = transaction(() { | 1763 var props = transaction(() { |
| 865 if (!s_separate(indent + 1, ctx)) return null; | 1764 if (!truth(s_separate(indent + 1, ctx))) return null; |
| 866 return c_ns_properties(indent + 1, ctx); | 1765 return c_ns_properties(indent + 1, ctx); |
| 867 }); | 1766 }); |
| 868 if (!truth(props)) props = new _Pair<_Tag, String>(null, null); | |
| 869 | 1767 |
| 870 if (!s_l_comments()) return null; | 1768 if (!truth(s_l_comments())) return null; |
| 871 return or([ | 1769 return or([ |
| 872 () => l_blockSequence(seqSpaces(indent, ctx)), | 1770 () => l_blockSequence(seqSpaces(indent, ctx)), |
| 873 () => l_blockMapping(indent)]); | 1771 () => l_blockMapping(indent)]); |
| 874 }); | 1772 }); |
| 875 | 1773 |
| 876 // 201 | 1774 // 201 |
| 877 int seqSpaces(int indent, int ctx) => ctx == BLOCK_OUT ? indent - 1 : indent; | 1775 int seqSpaces(int indent, int ctx) => ctx == BLOCK_OUT ? indent - 1 : indent; |
| 878 | 1776 |
| 879 // 202 | 1777 // 202 |
| 880 void l_documentPrefix() { | 1778 void l_documentPrefix() { |
| 881 zeroOrMore(l_comment); | 1779 zeroOrMore(l_comment); |
| 882 } | 1780 } |
| 883 | 1781 |
| 884 // 203 | 1782 // 203 |
| 885 bool c_directivesEnd() => rawString("---"); | 1783 bool c_directivesEnd() => rawString("---"); |
| 886 | 1784 |
| 887 // 204 | 1785 // 204 |
| 888 bool c_documentEnd() => rawString("..."); | 1786 bool c_documentEnd() => rawString("..."); |
| 889 | 1787 |
| 890 // 205 | 1788 // 205 |
| 891 bool l_documentSuffix() => transaction(() { | 1789 bool l_documentSuffix() => transaction(() { |
| 892 if (!c_documentEnd()) return false; | 1790 if (!truth(c_documentEnd())) return false; |
| 893 return s_l_comments(); | 1791 return s_l_comments(); |
| 894 }); | 1792 }); |
| 895 | 1793 |
| 896 // 206 | 1794 // 206 |
| 897 bool c_forbidden() { | 1795 bool c_forbidden() { |
| 898 if (!inBareDocument || !atStartOfLine) return false; | 1796 if (!inBareDocument || !atStartOfLine) return false; |
| 899 var forbidden = false; | 1797 var forbidden = false; |
| 900 transaction(() { | 1798 transaction(() { |
| 901 if (!truth(or([c_directivesEnd, c_documentEnd]))) return; | 1799 if (!truth(or([c_directivesEnd, c_documentEnd]))) return; |
| 902 var char = peek(); | 1800 var char = peek(); |
| 903 forbidden = isBreak(char) || isSpace(char) || atEndOfFile; | 1801 forbidden = isBreak(char) || isSpace(char) || atEndOfFile; |
| 904 return; | 1802 return; |
| 905 }); | 1803 }); |
| 906 return forbidden; | 1804 return forbidden; |
| 907 } | 1805 } |
| 908 | 1806 |
| 909 // 207 | 1807 // 207 |
| 910 _Node l_bareDocument() { | 1808 _Node l_bareDocument() { |
| 911 try { | 1809 try { |
| 912 inBareDocument = true; | 1810 inBareDocument = true; |
| 913 return s_l_blockNode(-1, BLOCK_IN); | 1811 return s_l_blockNode(-1, BLOCK_IN); |
| 914 } finally { | 1812 } finally { |
| 915 inBareDocument = false; | 1813 inBareDocument = false; |
| 916 } | 1814 } |
| 917 } | 1815 } |
| 918 | 1816 |
| 919 // 208 | 1817 // 208 |
| 920 _Node l_explicitDocument() { | 1818 _Node l_explicitDocument() { |
| 921 if (!c_directivesEnd()) return null; | 1819 if (!truth(c_directivesEnd())) return null; |
| 922 var doc = l_bareDocument(); | 1820 var doc = l_bareDocument(); |
| 923 if (truth(doc)) return doc; | 1821 if (truth(doc)) return doc; |
| 924 | 1822 |
| 925 doc = e_node(); | 1823 doc = e_node(); |
| 926 s_l_comments(); | 1824 s_l_comments(); |
| 927 return doc; | 1825 return doc; |
| 928 } | 1826 } |
| 929 | 1827 |
| 930 // 209 | 1828 // 209 |
| 931 _Node l_directiveDocument() { | 1829 _Node l_directiveDocument() { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 976 | 1874 |
| 977 /** A pair of values. */ | 1875 /** A pair of values. */ |
| 978 class _Pair<E, F> { | 1876 class _Pair<E, F> { |
| 979 E first; | 1877 E first; |
| 980 F last; | 1878 F last; |
| 981 | 1879 |
| 982 _Pair(this.first, this.last); | 1880 _Pair(this.first, this.last); |
| 983 | 1881 |
| 984 String toString() => '($first, $last)'; | 1882 String toString() => '($first, $last)'; |
| 985 } | 1883 } |
| 1884 | |
| 1885 /** The information in the header for a block scalar. */ | |
| 1886 class _BlockHeader { | |
| 1887 final int additionalIndent; | |
| 1888 final int chomping; | |
| 1889 | |
| 1890 _BlockHeader(this.additionalIndent, this.chomping); | |
| 1891 | |
| 1892 bool get autoDetectIndent() => additionalIndent == null; | |
| 1893 } | |
| OLD | NEW |