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