| Index: utils/pub/yaml/parser.dart
|
| diff --git a/utils/pub/yaml/parser.dart b/utils/pub/yaml/parser.dart
|
| deleted file mode 100644
|
| index f2f255e7652df22f79254adf898a5daea80e53a7..0000000000000000000000000000000000000000
|
| --- a/utils/pub/yaml/parser.dart
|
| +++ /dev/null
|
| @@ -1,1939 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -part of yaml;
|
| -
|
| -/// Translates a string of characters into a YAML serialization tree.
|
| -///
|
| -/// This parser is designed to closely follow the spec. All productions in the
|
| -/// spec are numbered, and the corresponding methods in the parser have the same
|
| -/// numbers. This is certainly not the most efficient way of parsing YAML, but
|
| -/// it is the easiest to write and read in the context of the spec.
|
| -///
|
| -/// Methods corresponding to productions are also named as in the spec,
|
| -/// translating the name of the method (although not the annotation characters)
|
| -/// into camel-case for dart style.. For example, the spec has a production
|
| -/// named `nb-ns-plain-in-line`, and the method implementing it is named
|
| -/// `nb_ns_plainInLine`. The exception to that rule is methods that just
|
| -/// recognize character classes; these are named `is*`.
|
| -class _Parser {
|
| - static const TAB = 0x9;
|
| - static const LF = 0xA;
|
| - static const CR = 0xD;
|
| - static const SP = 0x20;
|
| - static const TILDE = 0x7E;
|
| - static const NEL = 0x85;
|
| - static const PLUS = 0x2B;
|
| - static const HYPHEN = 0x2D;
|
| - static const QUESTION_MARK = 0x3F;
|
| - static const COLON = 0x3A;
|
| - static const COMMA = 0x2C;
|
| - static const LEFT_BRACKET = 0x5B;
|
| - static const RIGHT_BRACKET = 0x5D;
|
| - static const LEFT_BRACE = 0x7B;
|
| - static const RIGHT_BRACE = 0x7D;
|
| - static const HASH = 0x23;
|
| - static const AMPERSAND = 0x26;
|
| - static const ASTERISK = 0x2A;
|
| - static const EXCLAMATION = 0x21;
|
| - static const VERTICAL_BAR = 0x7C;
|
| - static const GREATER_THAN = 0x3E;
|
| - static const SINGLE_QUOTE = 0x27;
|
| - static const DOUBLE_QUOTE = 0x22;
|
| - static const PERCENT = 0x25;
|
| - static const AT = 0x40;
|
| - static const GRAVE_ACCENT = 0x60;
|
| -
|
| - static const NULL = 0x0;
|
| - static const BELL = 0x7;
|
| - static const BACKSPACE = 0x8;
|
| - static const VERTICAL_TAB = 0xB;
|
| - static const FORM_FEED = 0xC;
|
| - static const ESCAPE = 0x1B;
|
| - static const SLASH = 0x2F;
|
| - static const BACKSLASH = 0x5C;
|
| - static const UNDERSCORE = 0x5F;
|
| - static const NBSP = 0xA0;
|
| - static const LINE_SEPARATOR = 0x2028;
|
| - static const PARAGRAPH_SEPARATOR = 0x2029;
|
| -
|
| - static const NUMBER_0 = 0x30;
|
| - static const NUMBER_9 = 0x39;
|
| -
|
| - static const LETTER_A = 0x61;
|
| - static const LETTER_B = 0x62;
|
| - static const LETTER_E = 0x65;
|
| - static const LETTER_F = 0x66;
|
| - static const LETTER_N = 0x6E;
|
| - static const LETTER_R = 0x72;
|
| - static const LETTER_T = 0x74;
|
| - static const LETTER_U = 0x75;
|
| - static const LETTER_V = 0x76;
|
| - static const LETTER_X = 0x78;
|
| -
|
| - static const LETTER_CAP_A = 0x41;
|
| - static const LETTER_CAP_F = 0x46;
|
| - static const LETTER_CAP_L = 0x4C;
|
| - static const LETTER_CAP_N = 0x4E;
|
| - static const LETTER_CAP_P = 0x50;
|
| - static const LETTER_CAP_U = 0x55;
|
| - static const LETTER_CAP_X = 0x58;
|
| -
|
| - static const C_SEQUENCE_ENTRY = 4;
|
| - static const C_MAPPING_KEY = 5;
|
| - static const C_MAPPING_VALUE = 6;
|
| - static const C_COLLECT_ENTRY = 7;
|
| - static const C_SEQUENCE_START = 8;
|
| - static const C_SEQUENCE_END = 9;
|
| - static const C_MAPPING_START = 10;
|
| - static const C_MAPPING_END = 11;
|
| - static const C_COMMENT = 12;
|
| - static const C_ANCHOR = 13;
|
| - static const C_ALIAS = 14;
|
| - static const C_TAG = 15;
|
| - static const C_LITERAL = 16;
|
| - static const C_FOLDED = 17;
|
| - static const C_SINGLE_QUOTE = 18;
|
| - static const C_DOUBLE_QUOTE = 19;
|
| - static const C_DIRECTIVE = 20;
|
| - static const C_RESERVED = 21;
|
| -
|
| - static const BLOCK_OUT = 0;
|
| - static const BLOCK_IN = 1;
|
| - static const FLOW_OUT = 2;
|
| - static const FLOW_IN = 3;
|
| - static const BLOCK_KEY = 4;
|
| - static const FLOW_KEY = 5;
|
| -
|
| - static const CHOMPING_STRIP = 0;
|
| - static const CHOMPING_KEEP = 1;
|
| - static const CHOMPING_CLIP = 2;
|
| -
|
| - /// The source string being parsed.
|
| - final String s;
|
| -
|
| - /// The current position in the source string.
|
| - int pos = 0;
|
| -
|
| - /// The length of the string being parsed.
|
| - final int len;
|
| -
|
| - /// The current (0-based) line in the source string.
|
| - int line = 0;
|
| -
|
| - /// The current (0-based) column in the source string.
|
| - int column = 0;
|
| -
|
| - /// Whether we're parsing a bare document (that is, one that doesn't begin
|
| - /// with `---`). Bare documents don't allow `%` immediately following
|
| - /// newlines.
|
| - bool inBareDocument = false;
|
| -
|
| - /// The line number of the farthest position that has been parsed successfully
|
| - /// before backtracking. Used for error reporting.
|
| - int farthestLine = 0;
|
| -
|
| - /// The column number of the farthest position that has been parsed
|
| - /// successfully before backtracking. Used for error reporting.
|
| - int farthestColumn = 0;
|
| -
|
| - /// The farthest position in the source string that has been parsed
|
| - /// successfully before backtracking. Used for error reporting.
|
| - int farthestPos = 0;
|
| -
|
| - /// The name of the context of the farthest position that has been parsed
|
| - /// successfully before backtracking. Used for error reporting.
|
| - String farthestContext = "document";
|
| -
|
| - /// A stack of the names of parse contexts. Used for error reporting.
|
| - List<String> contextStack;
|
| -
|
| - /// Annotations attached to ranges of the source string that add extra
|
| - /// information to any errors that occur in the annotated range.
|
| - _RangeMap<String> errorAnnotations;
|
| -
|
| - /// The buffer containing the string currently being captured.
|
| - StringBuffer capturedString;
|
| -
|
| - /// The beginning of the current section of the captured string.
|
| - int captureStart;
|
| -
|
| - /// Whether the current string capture is being overridden.
|
| - bool capturingAs = false;
|
| -
|
| - _Parser(String s)
|
| - : this.s = s,
|
| - len = s.length,
|
| - contextStack = <String>["document"],
|
| - errorAnnotations = new _RangeMap();
|
| -
|
| - /// Return the character at the current position, then move that position
|
| - /// forward one character. Also updates the current line and column numbers.
|
| - int next() {
|
| - if (pos == len) return -1;
|
| - var char = s.charCodeAt(pos++);
|
| - if (isBreak(char)) {
|
| - line++;
|
| - column = 0;
|
| - } else {
|
| - column++;
|
| - }
|
| -
|
| - if (farthestLine < line) {
|
| - farthestLine = line;
|
| - farthestColumn = column;
|
| - farthestContext = contextStack.last;
|
| - } else if (farthestLine == line && farthestColumn < column) {
|
| - farthestColumn = column;
|
| - farthestContext = contextStack.last;
|
| - }
|
| - farthestPos = pos;
|
| -
|
| - return char;
|
| - }
|
| -
|
| - /// Returns the character at the current position, or the character [i]
|
| - /// characters after the current position.
|
| - ///
|
| - /// Returns -1 if this would return a character after the end or before the
|
| - /// beginning of the input string.
|
| - int peek([int i = 0]) {
|
| - var peekPos = pos + i;
|
| - return (peekPos >= len || peekPos < 0) ? -1 : s.charCodeAt(peekPos);
|
| - }
|
| -
|
| - /// The truthiness operator. Returns `false` if [obj] is `null` or `false`,
|
| - /// `true` otherwise.
|
| - bool truth(obj) => obj != null && obj != false;
|
| -
|
| - /// Consumes the current character if it matches [matcher]. Returns the result
|
| - /// of [matcher].
|
| - bool consume(bool matcher(int)) {
|
| - if (matcher(peek())) {
|
| - next();
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - /// Consumes the current character if it equals [char].
|
| - bool consumeChar(int char) => consume((c) => c == char);
|
| -
|
| - /// Calls [consumer] until it returns a falsey value. Returns a list of all
|
| - /// truthy return values of [consumer], or null if it didn't consume anything.
|
| - ///
|
| - /// Conceptually, repeats a production one or more times.
|
| - List oneOrMore(consumer()) {
|
| - var first = consumer();
|
| - if (!truth(first)) return null;
|
| - var out = [first];
|
| - while (true) {
|
| - var el = consumer();
|
| - if (!truth(el)) return out;
|
| - out.add(el);
|
| - }
|
| - return null; // Unreachable.
|
| - }
|
| -
|
| - /// Calls [consumer] until it returns a falsey value. Returns a list of all
|
| - /// truthy return values of [consumer], or the empty list if it didn't consume
|
| - /// anything.
|
| - ///
|
| - /// Conceptually, repeats a production any number of times.
|
| - List zeroOrMore(consumer()) {
|
| - var out = [];
|
| - var oldPos = pos;
|
| - while (true) {
|
| - var el = consumer();
|
| - if (!truth(el) || oldPos == pos) return out;
|
| - oldPos = pos;
|
| - out.add(el);
|
| - }
|
| - return null; // Unreachable.
|
| - }
|
| -
|
| - /// Just calls [consumer] and returns its result. Used to make it explicit
|
| - /// that a production is intended to be optional.
|
| - zeroOrOne(consumer()) => consumer();
|
| -
|
| - /// Calls each function in [consumers] until one returns a truthy value, then
|
| - /// returns that.
|
| - or(List<Function> consumers) {
|
| - for (var c in consumers) {
|
| - var res = c();
|
| - if (truth(res)) return res;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /// Calls [consumer] and returns its result, but rolls back the parser state
|
| - /// if [consumer] returns a falsey value.
|
| - transaction(consumer()) {
|
| - var oldPos = pos;
|
| - var oldLine = line;
|
| - var oldColumn = column;
|
| - var oldCaptureStart = captureStart;
|
| - String capturedSoFar = capturedString == null ? null :
|
| - capturedString.toString();
|
| - var res = consumer();
|
| - if (truth(res)) return res;
|
| -
|
| - pos = oldPos;
|
| - line = oldLine;
|
| - column = oldColumn;
|
| - captureStart = oldCaptureStart;
|
| - capturedString = capturedSoFar == null ? null :
|
| - new StringBuffer(capturedSoFar);
|
| - return res;
|
| - }
|
| -
|
| - /// Consumes [n] characters matching [matcher], or none if there isn't a
|
| - /// complete match. The first argument to [matcher] is the character code, the
|
| - /// second is the index (from 0 to [n] - 1).
|
| - ///
|
| - /// Returns whether or not the characters were consumed.
|
| - bool nAtOnce(int n, bool matcher(int c, int i)) => transaction(() {
|
| - for (int i = 0; i < n; i++) {
|
| - if (!consume((c) => matcher(c, i))) return false;
|
| - }
|
| - return true;
|
| - });
|
| -
|
| - /// Consumes the exact characters in [str], or nothing.
|
| - ///
|
| - /// Returns whether or not the string was consumed.
|
| - bool rawString(String str) =>
|
| - nAtOnce(str.length, (c, i) => str.charCodeAt(i) == c);
|
| -
|
| - /// Consumes and returns a string of characters matching [matcher], or null if
|
| - /// there are no such characters.
|
| - String stringOf(bool matcher(int)) =>
|
| - captureString(() => oneOrMore(() => consume(matcher)));
|
| -
|
| - /// Calls [consumer] and returns the string that was consumed while doing so,
|
| - /// or null if [consumer] returned a falsey value. Automatically wraps
|
| - /// [consumer] in `transaction`.
|
| - String captureString(consumer()) {
|
| - // captureString calls may not be nested
|
| - assert(capturedString == null);
|
| -
|
| - captureStart = pos;
|
| - capturedString = new StringBuffer();
|
| - var res = transaction(consumer);
|
| - if (!truth(res)) {
|
| - captureStart = null;
|
| - capturedString = null;
|
| - return null;
|
| - }
|
| -
|
| - flushCapture();
|
| - var result = capturedString.toString();
|
| - captureStart = null;
|
| - capturedString = null;
|
| - return result;
|
| - }
|
| -
|
| - captureAs(String replacement, consumer()) =>
|
| - captureAndTransform(consumer, (_) => replacement);
|
| -
|
| - captureAndTransform(consumer(), String transformation(String captured)) {
|
| - if (capturedString == null) return consumer();
|
| - if (capturingAs) return consumer();
|
| -
|
| - flushCapture();
|
| - capturingAs = true;
|
| - var res = consumer();
|
| - capturingAs = false;
|
| - if (!truth(res)) return res;
|
| -
|
| - capturedString.add(transformation(s.substring(captureStart, pos)));
|
| - captureStart = pos;
|
| - return res;
|
| - }
|
| -
|
| - void flushCapture() {
|
| - capturedString.add(s.substring(captureStart, pos));
|
| - captureStart = pos;
|
| - }
|
| -
|
| - /// Adds a tag and an anchor to [node], if they're defined.
|
| - _Node addProps(_Node node, _Pair<_Tag, String> props) {
|
| - if (props == null || node == null) return node;
|
| - if (truth(props.first)) node.tag = props.first;
|
| - if (truth(props.last)) node.anchor = props.last;
|
| - return node;
|
| - }
|
| -
|
| - /// Creates a MappingNode from [pairs].
|
| - _MappingNode map(List<_Pair<_Node, _Node>> pairs) {
|
| - var content = new Map<_Node, _Node>();
|
| - pairs.forEach((pair) => content[pair.first] = pair.last);
|
| - return new _MappingNode("?", content);
|
| - }
|
| -
|
| - /// Runs [fn] in a context named [name]. Used for error reporting.
|
| - context(String name, fn()) {
|
| - try {
|
| - contextStack.add(name);
|
| - return fn();
|
| - } finally {
|
| - var popped = contextStack.removeLast();
|
| - assert(popped == name);
|
| - }
|
| - }
|
| -
|
| - /// Adds [message] as extra information to any errors that occur between the
|
| - /// current position and the position of the cursor after running [fn]. The
|
| - /// cursor is reset after [fn] is run.
|
| - annotateError(String message, fn()) {
|
| - var start = pos;
|
| - var end;
|
| - transaction(() {
|
| - fn();
|
| - end = pos;
|
| - return false;
|
| - });
|
| - errorAnnotations[new _Range(start, end)] = message;
|
| - }
|
| -
|
| - /// Throws an error with additional context information.
|
| - error(String message) {
|
| - // Line and column should be one-based.
|
| - throw new SyntaxError(line + 1, column + 1,
|
| - "$message (in $farthestContext)");
|
| - }
|
| -
|
| - /// If [result] is falsey, throws an error saying that [expected] was
|
| - /// expected.
|
| - expect(result, String expected) {
|
| - if (truth(result)) return result;
|
| - error("expected $expected");
|
| - }
|
| -
|
| - /// Throws an error saying that the parse failed. Uses [farthestLine],
|
| - /// [farthestColumn], and [farthestContext] to provide additional information.
|
| - parseFailed() {
|
| - var message = "invalid YAML in $farthestContext";
|
| - var extraError = errorAnnotations[farthestPos];
|
| - if (extraError != null) message = "$message ($extraError)";
|
| - throw new SyntaxError(farthestLine + 1, farthestColumn + 1, message);
|
| - }
|
| -
|
| - /// Returns the number of spaces after the current position.
|
| - int countIndentation() {
|
| - var i = 0;
|
| - while (peek(i) == SP) i++;
|
| - return i;
|
| - }
|
| -
|
| - /// Returns the indentation for a block scalar.
|
| - int blockScalarAdditionalIndentation(_BlockHeader header, int indent) {
|
| - if (!header.autoDetectIndent) return header.additionalIndent;
|
| -
|
| - var maxSpaces = 0;
|
| - var maxSpacesLine = 0;
|
| - var spaces = 0;
|
| - transaction(() {
|
| - do {
|
| - spaces = captureString(() => zeroOrMore(() => consumeChar(SP))).length;
|
| - if (spaces > maxSpaces) {
|
| - maxSpaces = spaces;
|
| - maxSpacesLine = line;
|
| - }
|
| - } while (b_break());
|
| - return false;
|
| - });
|
| -
|
| - // If the next non-empty line isn't indented further than the start of the
|
| - // block scalar, that means the scalar is going to be empty. Returning any
|
| - // value > 0 will cause the parser not to consume any text.
|
| - if (spaces <= indent) return 1;
|
| -
|
| - // It's an error for a leading empty line to be indented more than the first
|
| - // non-empty line.
|
| - if (maxSpaces > spaces) {
|
| - throw new SyntaxError(maxSpacesLine + 1, maxSpaces,
|
| - "Leading empty lines may not be indented more than the first "
|
| - "non-empty line.");
|
| - }
|
| -
|
| - return spaces - indent;
|
| - }
|
| -
|
| - /// Returns whether the current position is at the beginning of a line.
|
| - bool get atStartOfLine => column == 0;
|
| -
|
| - /// Returns whether the current position is at the end of the input.
|
| - bool get atEndOfFile => pos == len;
|
| -
|
| - /// Given an indicator character, returns the type of that indicator (or null
|
| - /// if the indicator isn't found.
|
| - int indicatorType(int char) {
|
| - switch (char) {
|
| - case HYPHEN: return C_SEQUENCE_ENTRY;
|
| - case QUESTION_MARK: return C_MAPPING_KEY;
|
| - case COLON: return C_MAPPING_VALUE;
|
| - case COMMA: return C_COLLECT_ENTRY;
|
| - case LEFT_BRACKET: return C_SEQUENCE_START;
|
| - case RIGHT_BRACKET: return C_SEQUENCE_END;
|
| - case LEFT_BRACE: return C_MAPPING_START;
|
| - case RIGHT_BRACE: return C_MAPPING_END;
|
| - case HASH: return C_COMMENT;
|
| - case AMPERSAND: return C_ANCHOR;
|
| - case ASTERISK: return C_ALIAS;
|
| - case EXCLAMATION: return C_TAG;
|
| - case VERTICAL_BAR: return C_LITERAL;
|
| - case GREATER_THAN: return C_FOLDED;
|
| - case SINGLE_QUOTE: return C_SINGLE_QUOTE;
|
| - case DOUBLE_QUOTE: return C_DOUBLE_QUOTE;
|
| - case PERCENT: return C_DIRECTIVE;
|
| - case AT:
|
| - case GRAVE_ACCENT:
|
| - return C_RESERVED;
|
| - default: return null;
|
| - }
|
| - }
|
| -
|
| - // 1
|
| - bool isPrintable(int char) {
|
| - return char == TAB ||
|
| - char == LF ||
|
| - char == CR ||
|
| - (char >= SP && char <= TILDE) ||
|
| - char == NEL ||
|
| - (char >= 0xA0 && char <= 0xD7FF) ||
|
| - (char >= 0xE000 && char <= 0xFFFD) ||
|
| - (char >= 0x10000 && char <= 0x10FFFF);
|
| - }
|
| -
|
| - // 2
|
| - bool isJson(int char) => char == TAB || (char >= SP && char <= 0x10FFFF);
|
| -
|
| - // 22
|
| - bool c_indicator(int type) => consume((c) => indicatorType(c) == type);
|
| -
|
| - // 23
|
| - bool isFlowIndicator(int char) {
|
| - var indicator = indicatorType(char);
|
| - return indicator == C_COLLECT_ENTRY ||
|
| - indicator == C_SEQUENCE_START ||
|
| - indicator == C_SEQUENCE_END ||
|
| - indicator == C_MAPPING_START ||
|
| - indicator == C_MAPPING_END;
|
| - }
|
| -
|
| - // 26
|
| - bool isBreak(int char) => char == LF || char == CR;
|
| -
|
| - // 27
|
| - bool isNonBreak(int char) => isPrintable(char) && !isBreak(char);
|
| -
|
| - // 28
|
| - bool b_break() {
|
| - if (consumeChar(CR)) {
|
| - zeroOrOne(() => consumeChar(LF));
|
| - return true;
|
| - }
|
| - return consumeChar(LF);
|
| - }
|
| -
|
| - // 29
|
| - bool b_asLineFeed() => captureAs("\n", () => b_break());
|
| -
|
| - // 30
|
| - bool b_nonContent() => captureAs("", () => b_break());
|
| -
|
| - // 33
|
| - bool isSpace(int char) => char == SP || char == TAB;
|
| -
|
| - // 34
|
| - bool isNonSpace(int char) => isNonBreak(char) && !isSpace(char);
|
| -
|
| - // 35
|
| - bool isDecDigit(int char) => char >= NUMBER_0 && char <= NUMBER_9;
|
| -
|
| - // 36
|
| - bool isHexDigit(int char) {
|
| - return isDecDigit(char) ||
|
| - (char >= LETTER_A && char <= LETTER_F) ||
|
| - (char >= LETTER_CAP_A && char <= LETTER_CAP_F);
|
| - }
|
| -
|
| - // 41
|
| - bool c_escape() => captureAs("", () => consumeChar(BACKSLASH));
|
| -
|
| - // 42
|
| - bool ns_escNull() => captureAs("\x00", () => consumeChar(NUMBER_0));
|
| -
|
| - // 43
|
| - bool ns_escBell() => captureAs("\x07", () => consumeChar(LETTER_A));
|
| -
|
| - // 44
|
| - bool ns_escBackspace() => captureAs("\b", () => consumeChar(LETTER_B));
|
| -
|
| - // 45
|
| - bool ns_escHorizontalTab() => captureAs("\t", () {
|
| - return consume((c) => c == LETTER_T || c == TAB);
|
| - });
|
| -
|
| - // 46
|
| - bool ns_escLineFeed() => captureAs("\n", () => consumeChar(LETTER_N));
|
| -
|
| - // 47
|
| - bool ns_escVerticalTab() => captureAs("\v", () => consumeChar(LETTER_V));
|
| -
|
| - // 48
|
| - bool ns_escFormFeed() => captureAs("\f", () => consumeChar(LETTER_F));
|
| -
|
| - // 49
|
| - bool ns_escCarriageReturn() => captureAs("\r", () => consumeChar(LETTER_R));
|
| -
|
| - // 50
|
| - bool ns_escEscape() => captureAs("\x1B", () => consumeChar(LETTER_E));
|
| -
|
| - // 51
|
| - bool ns_escSpace() => consumeChar(SP);
|
| -
|
| - // 52
|
| - bool ns_escDoubleQuote() => consumeChar(DOUBLE_QUOTE);
|
| -
|
| - // 53
|
| - bool ns_escSlash() => consumeChar(SLASH);
|
| -
|
| - // 54
|
| - bool ns_escBackslash() => consumeChar(BACKSLASH);
|
| -
|
| - // 55
|
| - bool ns_escNextLine() => captureAs("\x85", () => consumeChar(LETTER_CAP_N));
|
| -
|
| - // 56
|
| - bool ns_escNonBreakingSpace() =>
|
| - captureAs("\xA0", () => consumeChar(UNDERSCORE));
|
| -
|
| - // 57
|
| - bool ns_escLineSeparator() =>
|
| - captureAs("\u2028", () => consumeChar(LETTER_CAP_L));
|
| -
|
| - // 58
|
| - bool ns_escParagraphSeparator() =>
|
| - captureAs("\u2029", () => consumeChar(LETTER_CAP_P));
|
| -
|
| - // 59
|
| - bool ns_esc8Bit() => ns_escNBit(LETTER_X, 2);
|
| -
|
| - // 60
|
| - bool ns_esc16Bit() => ns_escNBit(LETTER_U, 4);
|
| -
|
| - // 61
|
| - bool ns_esc32Bit() => ns_escNBit(LETTER_CAP_U, 8);
|
| -
|
| - // Helper method for 59 - 61
|
| - bool ns_escNBit(int char, int digits) {
|
| - if (!captureAs('', () => consumeChar(char))) return false;
|
| - var captured = captureAndTransform(
|
| - () => nAtOnce(digits, (c, _) => isHexDigit(c)),
|
| - (hex) => new String.fromCharCodes([int.parse("0x$hex")]));
|
| - return expect(captured, "$digits hexidecimal digits");
|
| - }
|
| -
|
| - // 62
|
| - bool c_ns_escChar() => context('escape sequence', () => transaction(() {
|
| - if (!truth(c_escape())) return false;
|
| - return truth(or([
|
| - ns_escNull, ns_escBell, ns_escBackspace, ns_escHorizontalTab,
|
| - ns_escLineFeed, ns_escVerticalTab, ns_escFormFeed, ns_escCarriageReturn,
|
| - ns_escEscape, ns_escSpace, ns_escDoubleQuote, ns_escSlash,
|
| - ns_escBackslash, ns_escNextLine, ns_escNonBreakingSpace,
|
| - ns_escLineSeparator, ns_escParagraphSeparator, ns_esc8Bit, ns_esc16Bit,
|
| - ns_esc32Bit
|
| - ]));
|
| - }));
|
| -
|
| - // 63
|
| - bool s_indent(int indent) {
|
| - var result = nAtOnce(indent, (c, i) => c == SP);
|
| - if (peek() == TAB) {
|
| - annotateError("tab characters are not allowed as indentation in YAML",
|
| - () => zeroOrMore(() => consume(isSpace)));
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - // 64
|
| - bool s_indentLessThan(int indent) {
|
| - for (int i = 0; i < indent - 1; i++) {
|
| - if (!consumeChar(SP)) {
|
| - if (peek() == TAB) {
|
| - annotateError("tab characters are not allowed as indentation in YAML",
|
| - () {
|
| - for (; i < indent - 1; i++) {
|
| - if (!consume(isSpace)) break;
|
| - }
|
| - });
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - // 65
|
| - bool s_indentLessThanOrEqualTo(int indent) => s_indentLessThan(indent + 1);
|
| -
|
| - // 66
|
| - bool s_separateInLine() => transaction(() {
|
| - return captureAs('', () =>
|
| - truth(oneOrMore(() => consume(isSpace))) || atStartOfLine);
|
| - });
|
| -
|
| - // 67
|
| - bool s_linePrefix(int indent, int ctx) => captureAs("", () {
|
| - switch (ctx) {
|
| - case BLOCK_OUT:
|
| - case BLOCK_IN:
|
| - return s_blockLinePrefix(indent);
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - return s_flowLinePrefix(indent);
|
| - }
|
| - });
|
| -
|
| - // 68
|
| - bool s_blockLinePrefix(int indent) => s_indent(indent);
|
| -
|
| - // 69
|
| - bool s_flowLinePrefix(int indent) => captureAs('', () {
|
| - if (!truth(s_indent(indent))) return false;
|
| - zeroOrOne(s_separateInLine);
|
| - return true;
|
| - });
|
| -
|
| - // 70
|
| - bool l_empty(int indent, int ctx) => transaction(() {
|
| - var start = or([
|
| - () => s_linePrefix(indent, ctx),
|
| - () => s_indentLessThan(indent)
|
| - ]);
|
| - if (!truth(start)) return false;
|
| - return b_asLineFeed();
|
| - });
|
| -
|
| - // 71
|
| - bool b_asSpace() => captureAs(" ", () => consume(isBreak));
|
| -
|
| - // 72
|
| - bool b_l_trimmed(int indent, int ctx) => transaction(() {
|
| - if (!truth(b_nonContent())) return false;
|
| - return truth(oneOrMore(() => captureAs("\n", () => l_empty(indent, ctx))));
|
| - });
|
| -
|
| - // 73
|
| - bool b_l_folded(int indent, int ctx) =>
|
| - or([() => b_l_trimmed(indent, ctx), b_asSpace]);
|
| -
|
| - // 74
|
| - bool s_flowFolded(int indent) => transaction(() {
|
| - zeroOrOne(s_separateInLine);
|
| - if (!truth(b_l_folded(indent, FLOW_IN))) return false;
|
| - return s_flowLinePrefix(indent);
|
| - });
|
| -
|
| - // 75
|
| - bool c_nb_commentText() {
|
| - if (!truth(c_indicator(C_COMMENT))) return false;
|
| - zeroOrMore(() => consume(isNonBreak));
|
| - return true;
|
| - }
|
| -
|
| - // 76
|
| - bool b_comment() => atEndOfFile || b_nonContent();
|
| -
|
| - // 77
|
| - bool s_b_comment() {
|
| - if (truth(s_separateInLine())) {
|
| - zeroOrOne(c_nb_commentText);
|
| - }
|
| - return b_comment();
|
| - }
|
| -
|
| - // 78
|
| - bool l_comment() => transaction(() {
|
| - if (!truth(s_separateInLine())) return false;
|
| - zeroOrOne(c_nb_commentText);
|
| - return b_comment();
|
| - });
|
| -
|
| - // 79
|
| - bool s_l_comments() {
|
| - if (!truth(s_b_comment()) && !atStartOfLine) return false;
|
| - zeroOrMore(l_comment);
|
| - return true;
|
| - }
|
| -
|
| - // 80
|
| - bool s_separate(int indent, int ctx) {
|
| - switch (ctx) {
|
| - case BLOCK_OUT:
|
| - case BLOCK_IN:
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - return s_separateLines(indent);
|
| - case BLOCK_KEY:
|
| - case FLOW_KEY:
|
| - return s_separateInLine();
|
| - default: throw 'invalid context "$ctx"';
|
| - }
|
| - }
|
| -
|
| - // 81
|
| - bool s_separateLines(int indent) {
|
| - return transaction(() => s_l_comments() && s_flowLinePrefix(indent)) ||
|
| - s_separateInLine();
|
| - }
|
| -
|
| - // 82
|
| - bool l_directive() => false; // TODO(nweiz): implement
|
| -
|
| - // 96
|
| - _Pair<_Tag, String> c_ns_properties(int indent, int ctx) {
|
| - var tag, anchor;
|
| - tag = c_ns_tagProperty();
|
| - if (truth(tag)) {
|
| - anchor = transaction(() {
|
| - if (!truth(s_separate(indent, ctx))) return null;
|
| - return c_ns_anchorProperty();
|
| - });
|
| - return new _Pair<_Tag, String>(tag, anchor);
|
| - }
|
| -
|
| - anchor = c_ns_anchorProperty();
|
| - if (truth(anchor)) {
|
| - tag = transaction(() {
|
| - if (!truth(s_separate(indent, ctx))) return null;
|
| - return c_ns_tagProperty();
|
| - });
|
| - return new _Pair<_Tag, String>(tag, anchor);
|
| - }
|
| -
|
| - return null;
|
| - }
|
| -
|
| - // 97
|
| - _Tag c_ns_tagProperty() => null; // TODO(nweiz): implement
|
| -
|
| - // 101
|
| - String c_ns_anchorProperty() => null; // TODO(nweiz): implement
|
| -
|
| - // 102
|
| - bool isAnchorChar(int char) => isNonSpace(char) && !isFlowIndicator(char);
|
| -
|
| - // 103
|
| - String ns_anchorName() =>
|
| - captureString(() => oneOrMore(() => consume(isAnchorChar)));
|
| -
|
| - // 104
|
| - _Node c_ns_aliasNode() {
|
| - if (!truth(c_indicator(C_ALIAS))) return null;
|
| - var name = expect(ns_anchorName(), 'anchor name');
|
| - return new _AliasNode(name);
|
| - }
|
| -
|
| - // 105
|
| - _ScalarNode e_scalar() => new _ScalarNode("?", content: "");
|
| -
|
| - // 106
|
| - _ScalarNode e_node() => e_scalar();
|
| -
|
| - // 107
|
| - bool nb_doubleChar() => or([
|
| - c_ns_escChar,
|
| - () => consume((c) => isJson(c) && c != BACKSLASH && c != DOUBLE_QUOTE)
|
| - ]);
|
| -
|
| - // 108
|
| - bool ns_doubleChar() => !isSpace(peek()) && truth(nb_doubleChar());
|
| -
|
| - // 109
|
| - _Node c_doubleQuoted(int indent, int ctx) => context('string', () {
|
| - return transaction(() {
|
| - if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null;
|
| - var contents = nb_doubleText(indent, ctx);
|
| - if (!truth(c_indicator(C_DOUBLE_QUOTE))) return null;
|
| - return new _ScalarNode("!", content: contents);
|
| - });
|
| - });
|
| -
|
| - // 110
|
| - String nb_doubleText(int indent, int ctx) => captureString(() {
|
| - switch (ctx) {
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - nb_doubleMultiLine(indent);
|
| - break;
|
| - case BLOCK_KEY:
|
| - case FLOW_KEY:
|
| - nb_doubleOneLine();
|
| - break;
|
| - }
|
| - return true;
|
| - });
|
| -
|
| - // 111
|
| - void nb_doubleOneLine() {
|
| - zeroOrMore(nb_doubleChar);
|
| - }
|
| -
|
| - // 112
|
| - bool s_doubleEscaped(int indent) => transaction(() {
|
| - zeroOrMore(() => consume(isSpace));
|
| - if (!captureAs("", () => consumeChar(BACKSLASH))) return false;
|
| - if (!truth(b_nonContent())) return false;
|
| - zeroOrMore(() => captureAs("\n", () => l_empty(indent, FLOW_IN)));
|
| - return s_flowLinePrefix(indent);
|
| - });
|
| -
|
| - // 113
|
| - bool s_doubleBreak(int indent) => or([
|
| - () => s_doubleEscaped(indent),
|
| - () => s_flowFolded(indent)
|
| - ]);
|
| -
|
| - // 114
|
| - void nb_ns_doubleInLine() {
|
| - zeroOrMore(() => transaction(() {
|
| - zeroOrMore(() => consume(isSpace));
|
| - return ns_doubleChar();
|
| - }));
|
| - }
|
| -
|
| - // 115
|
| - bool s_doubleNextLine(int indent) {
|
| - if (!truth(s_doubleBreak(indent))) return false;
|
| - zeroOrOne(() {
|
| - if (!truth(ns_doubleChar())) return;
|
| - nb_ns_doubleInLine();
|
| - or([
|
| - () => s_doubleNextLine(indent),
|
| - () => zeroOrMore(() => consume(isSpace))
|
| - ]);
|
| - });
|
| - return true;
|
| - }
|
| -
|
| - // 116
|
| - void nb_doubleMultiLine(int indent) {
|
| - nb_ns_doubleInLine();
|
| - or([
|
| - () => s_doubleNextLine(indent),
|
| - () => zeroOrMore(() => consume(isSpace))
|
| - ]);
|
| - }
|
| -
|
| - // 117
|
| - bool c_quotedQuote() => captureAs("'", () => rawString("''"));
|
| -
|
| - // 118
|
| - bool nb_singleChar() => or([
|
| - c_quotedQuote,
|
| - () => consume((c) => isJson(c) && c != SINGLE_QUOTE)
|
| - ]);
|
| -
|
| - // 119
|
| - bool ns_singleChar() => !isSpace(peek()) && truth(nb_singleChar());
|
| -
|
| - // 120
|
| - _Node c_singleQuoted(int indent, int ctx) => context('string', () {
|
| - return transaction(() {
|
| - if (!truth(c_indicator(C_SINGLE_QUOTE))) return null;
|
| - var contents = nb_singleText(indent, ctx);
|
| - if (!truth(c_indicator(C_SINGLE_QUOTE))) return null;
|
| - return new _ScalarNode("!", content: contents);
|
| - });
|
| - });
|
| -
|
| - // 121
|
| - String nb_singleText(int indent, int ctx) => captureString(() {
|
| - switch (ctx) {
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - nb_singleMultiLine(indent);
|
| - break;
|
| - case BLOCK_KEY:
|
| - case FLOW_KEY:
|
| - nb_singleOneLine(indent);
|
| - break;
|
| - }
|
| - return true;
|
| - });
|
| -
|
| - // 122
|
| - void nb_singleOneLine(int indent) {
|
| - zeroOrMore(nb_singleChar);
|
| - }
|
| -
|
| - // 123
|
| - void nb_ns_singleInLine() {
|
| - zeroOrMore(() => transaction(() {
|
| - zeroOrMore(() => consume(isSpace));
|
| - return ns_singleChar();
|
| - }));
|
| - }
|
| -
|
| - // 124
|
| - bool s_singleNextLine(int indent) {
|
| - if (!truth(s_flowFolded(indent))) return false;
|
| - zeroOrOne(() {
|
| - if (!truth(ns_singleChar())) return;
|
| - nb_ns_singleInLine();
|
| - or([
|
| - () => s_singleNextLine(indent),
|
| - () => zeroOrMore(() => consume(isSpace))
|
| - ]);
|
| - });
|
| - return true;
|
| - }
|
| -
|
| - // 125
|
| - void nb_singleMultiLine(int indent) {
|
| - nb_ns_singleInLine();
|
| - or([
|
| - () => s_singleNextLine(indent),
|
| - () => zeroOrMore(() => consume(isSpace))
|
| - ]);
|
| - }
|
| -
|
| - // 126
|
| - bool ns_plainFirst(int ctx) {
|
| - var char = peek();
|
| - var indicator = indicatorType(char);
|
| - if (indicator == C_RESERVED) {
|
| - error("reserved indicators can't start a plain scalar");
|
| - }
|
| - var match = (isNonSpace(char) && indicator == null) ||
|
| - ((indicator == C_MAPPING_KEY ||
|
| - indicator == C_MAPPING_VALUE ||
|
| - indicator == C_SEQUENCE_ENTRY) &&
|
| - isPlainSafe(ctx, peek(1)));
|
| -
|
| - if (match) next();
|
| - return match;
|
| - }
|
| -
|
| - // 127
|
| - bool isPlainSafe(int ctx, int char) {
|
| - switch (ctx) {
|
| - case FLOW_OUT:
|
| - case BLOCK_KEY:
|
| - // 128
|
| - return isNonSpace(char);
|
| - case FLOW_IN:
|
| - case FLOW_KEY:
|
| - // 129
|
| - return isNonSpace(char) && !isFlowIndicator(char);
|
| - default: throw 'invalid context "$ctx"';
|
| - }
|
| - }
|
| -
|
| - // 130
|
| - bool ns_plainChar(int ctx) {
|
| - var char = peek();
|
| - var indicator = indicatorType(char);
|
| - var safeChar = isPlainSafe(ctx, char) && indicator != C_MAPPING_VALUE &&
|
| - indicator != C_COMMENT;
|
| - var nonCommentHash = isNonSpace(peek(-1)) && indicator == C_COMMENT;
|
| - var nonMappingColon = indicator == C_MAPPING_VALUE &&
|
| - isPlainSafe(ctx, peek(1));
|
| - var match = safeChar || nonCommentHash || nonMappingColon;
|
| -
|
| - if (match) next();
|
| - return match;
|
| - }
|
| -
|
| - // 131
|
| - String ns_plain(int indent, int ctx) => context('plain scalar', () {
|
| - return captureString(() {
|
| - switch (ctx) {
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - return ns_plainMultiLine(indent, ctx);
|
| - case BLOCK_KEY:
|
| - case FLOW_KEY:
|
| - return ns_plainOneLine(ctx);
|
| - default: throw 'invalid context "$ctx"';
|
| - }
|
| - });
|
| - });
|
| -
|
| - // 132
|
| - void nb_ns_plainInLine(int ctx) {
|
| - zeroOrMore(() => transaction(() {
|
| - zeroOrMore(() => consume(isSpace));
|
| - return ns_plainChar(ctx);
|
| - }));
|
| - }
|
| -
|
| - // 133
|
| - bool ns_plainOneLine(int ctx) {
|
| - if (truth(c_forbidden())) return false;
|
| - if (!truth(ns_plainFirst(ctx))) return false;
|
| - nb_ns_plainInLine(ctx);
|
| - return true;
|
| - }
|
| -
|
| - // 134
|
| - bool s_ns_plainNextLine(int indent, int ctx) => transaction(() {
|
| - if (!truth(s_flowFolded(indent))) return false;
|
| - if (truth(c_forbidden())) return false;
|
| - if (!truth(ns_plainChar(ctx))) return false;
|
| - nb_ns_plainInLine(ctx);
|
| - return true;
|
| - });
|
| -
|
| - // 135
|
| - bool ns_plainMultiLine(int indent, int ctx) {
|
| - if (!truth(ns_plainOneLine(ctx))) return false;
|
| - zeroOrMore(() => s_ns_plainNextLine(indent, ctx));
|
| - return true;
|
| - }
|
| -
|
| - // 136
|
| - int inFlow(int ctx) {
|
| - switch (ctx) {
|
| - case FLOW_OUT:
|
| - case FLOW_IN:
|
| - return FLOW_IN;
|
| - case BLOCK_KEY:
|
| - case FLOW_KEY:
|
| - return FLOW_KEY;
|
| - }
|
| - }
|
| -
|
| - // 137
|
| - _SequenceNode c_flowSequence(int indent, int ctx) => transaction(() {
|
| - if (!truth(c_indicator(C_SEQUENCE_START))) return null;
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - var content = zeroOrOne(() => ns_s_flowSeqEntries(indent, inFlow(ctx)));
|
| - if (!truth(c_indicator(C_SEQUENCE_END))) return null;
|
| - return new _SequenceNode("?", new List<_Node>.from(content));
|
| - });
|
| -
|
| - // 138
|
| - Collection<_Node> ns_s_flowSeqEntries(int indent, int ctx) {
|
| - var first = ns_flowSeqEntry(indent, ctx);
|
| - if (!truth(first)) return new Queue<_Node>();
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| -
|
| - var rest;
|
| - if (truth(c_indicator(C_COLLECT_ENTRY))) {
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - rest = zeroOrOne(() => ns_s_flowSeqEntries(indent, ctx));
|
| - }
|
| -
|
| - if (rest == null) rest = new Queue<_Node>();
|
| - rest.addFirst(first);
|
| -
|
| - return rest;
|
| - }
|
| -
|
| - // 139
|
| - _Node ns_flowSeqEntry(int indent, int ctx) => or([
|
| - () => ns_flowPair(indent, ctx),
|
| - () => ns_flowNode(indent, ctx)
|
| - ]);
|
| -
|
| - // 140
|
| - _Node c_flowMapping(int indent, int ctx) {
|
| - if (!truth(c_indicator(C_MAPPING_START))) return null;
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - var content = zeroOrOne(() => ns_s_flowMapEntries(indent, inFlow(ctx)));
|
| - if (!truth(c_indicator(C_MAPPING_END))) return null;
|
| - return new _MappingNode("?", content);
|
| - }
|
| -
|
| - // 141
|
| - YamlMap ns_s_flowMapEntries(int indent, int ctx) {
|
| - var first = ns_flowMapEntry(indent, ctx);
|
| - if (!truth(first)) return new YamlMap();
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| -
|
| - var rest;
|
| - if (truth(c_indicator(C_COLLECT_ENTRY))) {
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - rest = ns_s_flowMapEntries(indent, ctx);
|
| - }
|
| -
|
| - if (rest == null) rest = new YamlMap();
|
| -
|
| - // TODO(nweiz): Duplicate keys should be an error. This includes keys with
|
| - // different representations but the same value (e.g. 10 vs 0xa). To make
|
| - // this user-friendly we'll probably also want to associate nodes with a
|
| - // source range.
|
| - if (!rest.containsKey(first.first)) rest[first.first] = first.last;
|
| -
|
| - return rest;
|
| - }
|
| -
|
| - // 142
|
| - _Pair<_Node, _Node> ns_flowMapEntry(int indent, int ctx) => or([
|
| - () => transaction(() {
|
| - if (!truth(c_indicator(C_MAPPING_KEY))) return false;
|
| - if (!truth(s_separate(indent, ctx))) return false;
|
| - return ns_flowMapExplicitEntry(indent, ctx);
|
| - }),
|
| - () => ns_flowMapImplicitEntry(indent, ctx)
|
| - ]);
|
| -
|
| - // 143
|
| - _Pair<_Node, _Node> ns_flowMapExplicitEntry(int indent, int ctx) => or([
|
| - () => ns_flowMapImplicitEntry(indent, ctx),
|
| - () => new _Pair<_Node, _Node>(e_node(), e_node())
|
| - ]);
|
| -
|
| - // 144
|
| - _Pair<_Node, _Node> ns_flowMapImplicitEntry(int indent, int ctx) => or([
|
| - () => ns_flowMapYamlKeyEntry(indent, ctx),
|
| - () => c_ns_flowMapEmptyKeyEntry(indent, ctx),
|
| - () => c_ns_flowMapJsonKeyEntry(indent, ctx)
|
| - ]);
|
| -
|
| - // 145
|
| - _Pair<_Node, _Node> ns_flowMapYamlKeyEntry(int indent, int ctx) {
|
| - var key = ns_flowYamlNode(indent, ctx);
|
| - if (!truth(key)) return null;
|
| - var value = or([
|
| - () => transaction(() {
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - return c_ns_flowMapSeparateValue(indent, ctx);
|
| - }),
|
| - e_node
|
| - ]);
|
| - return new _Pair<_Node, _Node>(key, value);
|
| - }
|
| -
|
| - // 146
|
| - _Pair<_Node, _Node> c_ns_flowMapEmptyKeyEntry(int indent, int ctx) {
|
| - var value = c_ns_flowMapSeparateValue(indent, ctx);
|
| - if (!truth(value)) return null;
|
| - return new _Pair<_Node, _Node>(e_node(), value);
|
| - }
|
| -
|
| - // 147
|
| - _Node c_ns_flowMapSeparateValue(int indent, int ctx) => transaction(() {
|
| - if (!truth(c_indicator(C_MAPPING_VALUE))) return null;
|
| - if (isPlainSafe(ctx, peek())) return null;
|
| -
|
| - return or([
|
| - () => transaction(() {
|
| - if (!s_separate(indent, ctx)) return null;
|
| - return ns_flowNode(indent, ctx);
|
| - }),
|
| - e_node
|
| - ]);
|
| - });
|
| -
|
| - // 148
|
| - _Pair<_Node, _Node> c_ns_flowMapJsonKeyEntry(int indent, int ctx) {
|
| - var key = c_flowJsonNode(indent, ctx);
|
| - if (!truth(key)) return null;
|
| - var value = or([
|
| - () => transaction(() {
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - return c_ns_flowMapAdjacentValue(indent, ctx);
|
| - }),
|
| - e_node
|
| - ]);
|
| - return new _Pair<_Node, _Node>(key, value);
|
| - }
|
| -
|
| - // 149
|
| - _Node c_ns_flowMapAdjacentValue(int indent, int ctx) {
|
| - if (!truth(c_indicator(C_MAPPING_VALUE))) return null;
|
| - return or([
|
| - () => transaction(() {
|
| - zeroOrOne(() => s_separate(indent, ctx));
|
| - return ns_flowNode(indent, ctx);
|
| - }),
|
| - e_node
|
| - ]);
|
| - }
|
| -
|
| - // 150
|
| - _Node ns_flowPair(int indent, int ctx) {
|
| - var pair = or([
|
| - () => transaction(() {
|
| - if (!truth(c_indicator(C_MAPPING_KEY))) return null;
|
| - if (!truth(s_separate(indent, ctx))) return null;
|
| - return ns_flowMapExplicitEntry(indent, ctx);
|
| - }),
|
| - () => ns_flowPairEntry(indent, ctx)
|
| - ]);
|
| - if (!truth(pair)) return null;
|
| -
|
| - return map([pair]);
|
| - }
|
| -
|
| - // 151
|
| - _Pair<_Node, _Node> ns_flowPairEntry(int indent, int ctx) => or([
|
| - () => ns_flowPairYamlKeyEntry(indent, ctx),
|
| - () => c_ns_flowMapEmptyKeyEntry(indent, ctx),
|
| - () => c_ns_flowPairJsonKeyEntry(indent, ctx)
|
| - ]);
|
| -
|
| - // 152
|
| - _Pair<_Node, _Node> ns_flowPairYamlKeyEntry(int indent, int ctx) =>
|
| - transaction(() {
|
| - var key = ns_s_implicitYamlKey(FLOW_KEY);
|
| - if (!truth(key)) return null;
|
| - var value = c_ns_flowMapSeparateValue(indent, ctx);
|
| - if (!truth(value)) return null;
|
| - return new _Pair<_Node, _Node>(key, value);
|
| - });
|
| -
|
| - // 153
|
| - _Pair<_Node, _Node> c_ns_flowPairJsonKeyEntry(int indent, int ctx) =>
|
| - transaction(() {
|
| - var key = c_s_implicitJsonKey(FLOW_KEY);
|
| - if (!truth(key)) return null;
|
| - var value = c_ns_flowMapAdjacentValue(indent, ctx);
|
| - if (!truth(value)) return null;
|
| - return new _Pair<_Node, _Node>(key, value);
|
| - });
|
| -
|
| - // 154
|
| - _Node ns_s_implicitYamlKey(int ctx) => transaction(() {
|
| - // TODO(nweiz): this is supposed to be limited to 1024 characters.
|
| -
|
| - // The indentation parameter is "null" since it's unused in this path
|
| - var node = ns_flowYamlNode(null, ctx);
|
| - if (!truth(node)) return null;
|
| - zeroOrOne(s_separateInLine);
|
| - return node;
|
| - });
|
| -
|
| - // 155
|
| - _Node c_s_implicitJsonKey(int ctx) => transaction(() {
|
| - // TODO(nweiz): this is supposed to be limited to 1024 characters.
|
| -
|
| - // The indentation parameter is "null" since it's unused in this path
|
| - var node = c_flowJsonNode(null, ctx);
|
| - if (!truth(node)) return null;
|
| - zeroOrOne(s_separateInLine);
|
| - return node;
|
| - });
|
| -
|
| - // 156
|
| - _Node ns_flowYamlContent(int indent, int ctx) {
|
| - var str = ns_plain(indent, ctx);
|
| - if (!truth(str)) return null;
|
| - return new _ScalarNode("?", content: str);
|
| - }
|
| -
|
| - // 157
|
| - _Node c_flowJsonContent(int indent, int ctx) => or([
|
| - () => c_flowSequence(indent, ctx),
|
| - () => c_flowMapping(indent, ctx),
|
| - () => c_singleQuoted(indent, ctx),
|
| - () => c_doubleQuoted(indent, ctx)
|
| - ]);
|
| -
|
| - // 158
|
| - _Node ns_flowContent(int indent, int ctx) => or([
|
| - () => ns_flowYamlContent(indent, ctx),
|
| - () => c_flowJsonContent(indent, ctx)
|
| - ]);
|
| -
|
| - // 159
|
| - _Node ns_flowYamlNode(int indent, int ctx) => or([
|
| - c_ns_aliasNode,
|
| - () => ns_flowYamlContent(indent, ctx),
|
| - () {
|
| - var props = c_ns_properties(indent, ctx);
|
| - if (!truth(props)) return null;
|
| - var node = or([
|
| - () => transaction(() {
|
| - if (!truth(s_separate(indent, ctx))) return null;
|
| - return ns_flowYamlContent(indent, ctx);
|
| - }),
|
| - e_scalar
|
| - ]);
|
| - return addProps(node, props);
|
| - }
|
| - ]);
|
| -
|
| - // 160
|
| - _Node c_flowJsonNode(int indent, int ctx) => transaction(() {
|
| - var props;
|
| - zeroOrOne(() => transaction(() {
|
| - props = c_ns_properties(indent, ctx);
|
| - if (!truth(props)) return null;
|
| - return s_separate(indent, ctx);
|
| - }));
|
| -
|
| - return addProps(c_flowJsonContent(indent, ctx), props);
|
| - });
|
| -
|
| - // 161
|
| - _Node ns_flowNode(int indent, int ctx) => or([
|
| - c_ns_aliasNode,
|
| - () => ns_flowContent(indent, ctx),
|
| - () => transaction(() {
|
| - var props = c_ns_properties(indent, ctx);
|
| - if (!truth(props)) return null;
|
| - var node = or([
|
| - () => transaction(() => s_separate(indent, ctx) ?
|
| - ns_flowContent(indent, ctx) : null),
|
| - e_scalar]);
|
| - return addProps(node, props);
|
| - })
|
| - ]);
|
| -
|
| - // 162
|
| - _BlockHeader c_b_blockHeader() => transaction(() {
|
| - var indentation = c_indentationIndicator();
|
| - var chomping = c_chompingIndicator();
|
| - if (!truth(indentation)) indentation = c_indentationIndicator();
|
| - if (!truth(s_b_comment())) return null;
|
| -
|
| - return new _BlockHeader(indentation, chomping);
|
| - });
|
| -
|
| - // 163
|
| - int c_indentationIndicator() {
|
| - if (!isDecDigit(peek())) return null;
|
| - return next() - NUMBER_0;
|
| - }
|
| -
|
| - // 164
|
| - int c_chompingIndicator() {
|
| - switch (peek()) {
|
| - case HYPHEN:
|
| - next();
|
| - return CHOMPING_STRIP;
|
| - case PLUS:
|
| - next();
|
| - return CHOMPING_KEEP;
|
| - default:
|
| - return CHOMPING_CLIP;
|
| - }
|
| - }
|
| -
|
| - // 165
|
| - bool b_chompedLast(int chomping) {
|
| - if (atEndOfFile) return true;
|
| - switch (chomping) {
|
| - case CHOMPING_STRIP:
|
| - return b_nonContent();
|
| - case CHOMPING_CLIP:
|
| - case CHOMPING_KEEP:
|
| - return b_asLineFeed();
|
| - }
|
| - }
|
| -
|
| - // 166
|
| - void l_chompedEmpty(int indent, int chomping) {
|
| - switch (chomping) {
|
| - case CHOMPING_STRIP:
|
| - case CHOMPING_CLIP:
|
| - l_stripEmpty(indent);
|
| - break;
|
| - case CHOMPING_KEEP:
|
| - l_keepEmpty(indent);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // 167
|
| - void l_stripEmpty(int indent) {
|
| - captureAs('', () {
|
| - zeroOrMore(() => transaction(() {
|
| - if (!truth(s_indentLessThanOrEqualTo(indent))) return false;
|
| - return b_nonContent();
|
| - }));
|
| - zeroOrOne(() => l_trailComments(indent));
|
| - return true;
|
| - });
|
| - }
|
| -
|
| - // 168
|
| - void l_keepEmpty(int indent) {
|
| - zeroOrMore(() => captureAs('\n', () => l_empty(indent, BLOCK_IN)));
|
| - zeroOrOne(() => captureAs('', () => l_trailComments(indent)));
|
| - }
|
| -
|
| - // 169
|
| - bool l_trailComments(int indent) => transaction(() {
|
| - if (!truth(s_indentLessThanOrEqualTo(indent))) return false;
|
| - if (!truth(c_nb_commentText())) return false;
|
| - if (!truth(b_comment())) return false;
|
| - zeroOrMore(l_comment);
|
| - return true;
|
| - });
|
| -
|
| - // 170
|
| - _Node c_l_literal(int indent) => transaction(() {
|
| - if (!truth(c_indicator(C_LITERAL))) return null;
|
| - var header = c_b_blockHeader();
|
| - if (!truth(header)) return null;
|
| -
|
| - var additionalIndent = blockScalarAdditionalIndentation(header, indent);
|
| - var content = l_literalContent(indent + additionalIndent, header.chomping);
|
| - if (!truth(content)) return null;
|
| -
|
| - return new _ScalarNode("!", content: content);
|
| - });
|
| -
|
| - // 171
|
| - bool l_nb_literalText(int indent) => transaction(() {
|
| - zeroOrMore(() => captureAs("\n", () => l_empty(indent, BLOCK_IN)));
|
| - if (!truth(captureAs("", () => s_indent(indent)))) return false;
|
| - return truth(oneOrMore(() => consume(isNonBreak)));
|
| - });
|
| -
|
| - // 172
|
| - bool b_nb_literalNext(int indent) => transaction(() {
|
| - if (!truth(b_asLineFeed())) return false;
|
| - return l_nb_literalText(indent);
|
| - });
|
| -
|
| - // 173
|
| - String l_literalContent(int indent, int chomping) => captureString(() {
|
| - transaction(() {
|
| - if (!truth(l_nb_literalText(indent))) return false;
|
| - zeroOrMore(() => b_nb_literalNext(indent));
|
| - return b_chompedLast(chomping);
|
| - });
|
| - l_chompedEmpty(indent, chomping);
|
| - return true;
|
| - });
|
| -
|
| - // 174
|
| - _Node c_l_folded(int indent) => transaction(() {
|
| - if (!truth(c_indicator(C_FOLDED))) return null;
|
| - var header = c_b_blockHeader();
|
| - if (!truth(header)) return null;
|
| -
|
| - var additionalIndent = blockScalarAdditionalIndentation(header, indent);
|
| - var content = l_foldedContent(indent + additionalIndent, header.chomping);
|
| - if (!truth(content)) return null;
|
| -
|
| - return new _ScalarNode("!", content: content);
|
| - });
|
| -
|
| - // 175
|
| - bool s_nb_foldedText(int indent) => transaction(() {
|
| - if (!truth(captureAs('', () => s_indent(indent)))) return false;
|
| - if (!truth(consume(isNonSpace))) return false;
|
| - zeroOrMore(() => consume(isNonBreak));
|
| - return true;
|
| - });
|
| -
|
| - // 176
|
| - bool l_nb_foldedLines(int indent) {
|
| - if (!truth(s_nb_foldedText(indent))) return false;
|
| - zeroOrMore(() => transaction(() {
|
| - if (!truth(b_l_folded(indent, BLOCK_IN))) return false;
|
| - return s_nb_foldedText(indent);
|
| - }));
|
| - return true;
|
| - }
|
| -
|
| - // 177
|
| - bool s_nb_spacedText(int indent) => transaction(() {
|
| - if (!truth(captureAs('', () => s_indent(indent)))) return false;
|
| - if (!truth(consume(isSpace))) return false;
|
| - zeroOrMore(() => consume(isNonBreak));
|
| - return true;
|
| - });
|
| -
|
| - // 178
|
| - bool b_l_spaced(int indent) {
|
| - if (!truth(b_asLineFeed())) return false;
|
| - zeroOrMore(() => captureAs("\n", () => l_empty(indent, BLOCK_IN)));
|
| - return true;
|
| - }
|
| -
|
| - // 179
|
| - bool l_nb_spacedLines(int indent) {
|
| - if (!truth(s_nb_spacedText(indent))) return false;
|
| - zeroOrMore(() => transaction(() {
|
| - if (!truth(b_l_spaced(indent))) return false;
|
| - return s_nb_spacedText(indent);
|
| - }));
|
| - return true;
|
| - }
|
| -
|
| - // 180
|
| - bool l_nb_sameLines(int indent) => transaction(() {
|
| - zeroOrMore(() => captureAs('\n', () => l_empty(indent, BLOCK_IN)));
|
| - return or([
|
| - () => l_nb_foldedLines(indent),
|
| - () => l_nb_spacedLines(indent)
|
| - ]);
|
| - });
|
| -
|
| - // 181
|
| - bool l_nb_diffLines(int indent) {
|
| - if (!truth(l_nb_sameLines(indent))) return false;
|
| - zeroOrMore(() => transaction(() {
|
| - if (!truth(b_asLineFeed())) return false;
|
| - return l_nb_sameLines(indent);
|
| - }));
|
| - return true;
|
| - }
|
| -
|
| - // 182
|
| - String l_foldedContent(int indent, int chomping) => captureString(() {
|
| - transaction(() {
|
| - if (!truth(l_nb_diffLines(indent))) return false;
|
| - return b_chompedLast(chomping);
|
| - });
|
| - l_chompedEmpty(indent, chomping);
|
| - return true;
|
| - });
|
| -
|
| - // 183
|
| - _SequenceNode l_blockSequence(int indent) => context('sequence', () {
|
| - var additionalIndent = countIndentation() - indent;
|
| - if (additionalIndent <= 0) return null;
|
| -
|
| - var content = oneOrMore(() => transaction(() {
|
| - if (!truth(s_indent(indent + additionalIndent))) return null;
|
| - return c_l_blockSeqEntry(indent + additionalIndent);
|
| - }));
|
| - if (!truth(content)) return null;
|
| -
|
| - return new _SequenceNode("?", content);
|
| - });
|
| -
|
| - // 184
|
| - _Node c_l_blockSeqEntry(int indent) => transaction(() {
|
| - if (!truth(c_indicator(C_SEQUENCE_ENTRY))) return null;
|
| - if (isNonSpace(peek())) return null;
|
| -
|
| - return s_l_blockIndented(indent, BLOCK_IN);
|
| - });
|
| -
|
| - // 185
|
| - _Node s_l_blockIndented(int indent, int ctx) {
|
| - var additionalIndent = countIndentation();
|
| - return or([
|
| - () => transaction(() {
|
| - if (!truth(s_indent(additionalIndent))) return null;
|
| - return or([
|
| - () => ns_l_compactSequence(indent + 1 + additionalIndent),
|
| - () => ns_l_compactMapping(indent + 1 + additionalIndent)]);
|
| - }),
|
| - () => s_l_blockNode(indent, ctx),
|
| - () => s_l_comments() ? e_node() : null]);
|
| - }
|
| -
|
| - // 186
|
| - _Node ns_l_compactSequence(int indent) => context('sequence', () {
|
| - var first = c_l_blockSeqEntry(indent);
|
| - if (!truth(first)) return null;
|
| -
|
| - var content = zeroOrMore(() => transaction(() {
|
| - if (!truth(s_indent(indent))) return null;
|
| - return c_l_blockSeqEntry(indent);
|
| - }));
|
| - content.insertRange(0, 1, first);
|
| -
|
| - return new _SequenceNode("?", content);
|
| - });
|
| -
|
| - // 187
|
| - _Node l_blockMapping(int indent) => context('mapping', () {
|
| - var additionalIndent = countIndentation() - indent;
|
| - if (additionalIndent <= 0) return null;
|
| -
|
| - var pairs = oneOrMore(() => transaction(() {
|
| - if (!truth(s_indent(indent + additionalIndent))) return null;
|
| - return ns_l_blockMapEntry(indent + additionalIndent);
|
| - }));
|
| - if (!truth(pairs)) return null;
|
| -
|
| - return map(pairs);
|
| - });
|
| -
|
| - // 188
|
| - _Pair<_Node, _Node> ns_l_blockMapEntry(int indent) => or([
|
| - () => c_l_blockMapExplicitEntry(indent),
|
| - () => ns_l_blockMapImplicitEntry(indent)
|
| - ]);
|
| -
|
| - // 189
|
| - _Pair<_Node, _Node> c_l_blockMapExplicitEntry(int indent) {
|
| - var key = c_l_blockMapExplicitKey(indent);
|
| - if (!truth(key)) return null;
|
| -
|
| - var value = or([
|
| - () => l_blockMapExplicitValue(indent),
|
| - e_node
|
| - ]);
|
| -
|
| - return new _Pair<_Node, _Node>(key, value);
|
| - }
|
| -
|
| - // 190
|
| - _Node c_l_blockMapExplicitKey(int indent) => transaction(() {
|
| - if (!truth(c_indicator(C_MAPPING_KEY))) return null;
|
| - return s_l_blockIndented(indent, BLOCK_OUT);
|
| - });
|
| -
|
| - // 191
|
| - _Node l_blockMapExplicitValue(int indent) => transaction(() {
|
| - if (!truth(s_indent(indent))) return null;
|
| - if (!truth(c_indicator(C_MAPPING_VALUE))) return null;
|
| - return s_l_blockIndented(indent, BLOCK_OUT);
|
| - });
|
| -
|
| - // 192
|
| - _Pair<_Node, _Node> ns_l_blockMapImplicitEntry(int indent) => transaction(() {
|
| - var key = or([ns_s_blockMapImplicitKey, e_node]);
|
| - var value = c_l_blockMapImplicitValue(indent);
|
| - return truth(value) ? new _Pair<_Node, _Node>(key, value) : null;
|
| - });
|
| -
|
| - // 193
|
| - _Node ns_s_blockMapImplicitKey() => context('mapping key', () => or([
|
| - () => c_s_implicitJsonKey(BLOCK_KEY),
|
| - () => ns_s_implicitYamlKey(BLOCK_KEY)
|
| - ]));
|
| -
|
| - // 194
|
| - _Node c_l_blockMapImplicitValue(int indent) => context('mapping value', () =>
|
| - transaction(() {
|
| - if (!truth(c_indicator(C_MAPPING_VALUE))) return null;
|
| - return or([
|
| - () => s_l_blockNode(indent, BLOCK_OUT),
|
| - () => s_l_comments() ? e_node() : null
|
| - ]);
|
| - }));
|
| -
|
| - // 195
|
| - _Node ns_l_compactMapping(int indent) => context('mapping', () {
|
| - var first = ns_l_blockMapEntry(indent);
|
| - if (!truth(first)) return null;
|
| -
|
| - var pairs = zeroOrMore(() => transaction(() {
|
| - if (!truth(s_indent(indent))) return null;
|
| - return ns_l_blockMapEntry(indent);
|
| - }));
|
| - pairs.insertRange(0, 1, first);
|
| -
|
| - return map(pairs);
|
| - });
|
| -
|
| - // 196
|
| - _Node s_l_blockNode(int indent, int ctx) => or([
|
| - () => s_l_blockInBlock(indent, ctx),
|
| - () => s_l_flowInBlock(indent)
|
| - ]);
|
| -
|
| - // 197
|
| - _Node s_l_flowInBlock(int indent) => transaction(() {
|
| - if (!truth(s_separate(indent + 1, FLOW_OUT))) return null;
|
| - var node = ns_flowNode(indent + 1, FLOW_OUT);
|
| - if (!truth(node)) return null;
|
| - if (!truth(s_l_comments())) return null;
|
| - return node;
|
| - });
|
| -
|
| - // 198
|
| - _Node s_l_blockInBlock(int indent, int ctx) => or([
|
| - () => s_l_blockScalar(indent, ctx),
|
| - () => s_l_blockCollection(indent, ctx)
|
| - ]);
|
| -
|
| - // 199
|
| - _Node s_l_blockScalar(int indent, int ctx) => transaction(() {
|
| - if (!truth(s_separate(indent + 1, ctx))) return null;
|
| - var props = transaction(() {
|
| - var innerProps = c_ns_properties(indent + 1, ctx);
|
| - if (!truth(innerProps)) return null;
|
| - if (!truth(s_separate(indent + 1, ctx))) return null;
|
| - return innerProps;
|
| - });
|
| -
|
| - var node = or([() => c_l_literal(indent), () => c_l_folded(indent)]);
|
| - if (!truth(node)) return null;
|
| - return addProps(node, props);
|
| - });
|
| -
|
| - // 200
|
| - _Node s_l_blockCollection(int indent, int ctx) => transaction(() {
|
| - var props = transaction(() {
|
| - if (!truth(s_separate(indent + 1, ctx))) return null;
|
| - return c_ns_properties(indent + 1, ctx);
|
| - });
|
| -
|
| - if (!truth(s_l_comments())) return null;
|
| - return or([
|
| - () => l_blockSequence(seqSpaces(indent, ctx)),
|
| - () => l_blockMapping(indent)]);
|
| - });
|
| -
|
| - // 201
|
| - int seqSpaces(int indent, int ctx) => ctx == BLOCK_OUT ? indent - 1 : indent;
|
| -
|
| - // 202
|
| - void l_documentPrefix() {
|
| - zeroOrMore(l_comment);
|
| - }
|
| -
|
| - // 203
|
| - bool c_directivesEnd() => rawString("---");
|
| -
|
| - // 204
|
| - bool c_documentEnd() => rawString("...");
|
| -
|
| - // 205
|
| - bool l_documentSuffix() => transaction(() {
|
| - if (!truth(c_documentEnd())) return false;
|
| - return s_l_comments();
|
| - });
|
| -
|
| - // 206
|
| - bool c_forbidden() {
|
| - if (!inBareDocument || !atStartOfLine) return false;
|
| - var forbidden = false;
|
| - transaction(() {
|
| - if (!truth(or([c_directivesEnd, c_documentEnd]))) return;
|
| - var char = peek();
|
| - forbidden = isBreak(char) || isSpace(char) || atEndOfFile;
|
| - return;
|
| - });
|
| - return forbidden;
|
| - }
|
| -
|
| - // 207
|
| - _Node l_bareDocument() {
|
| - try {
|
| - inBareDocument = true;
|
| - return s_l_blockNode(-1, BLOCK_IN);
|
| - } finally {
|
| - inBareDocument = false;
|
| - }
|
| - }
|
| -
|
| - // 208
|
| - _Node l_explicitDocument() {
|
| - if (!truth(c_directivesEnd())) return null;
|
| - var doc = l_bareDocument();
|
| - if (truth(doc)) return doc;
|
| -
|
| - doc = e_node();
|
| - s_l_comments();
|
| - return doc;
|
| - }
|
| -
|
| - // 209
|
| - _Node l_directiveDocument() {
|
| - if (!truth(oneOrMore(l_directive))) return null;
|
| - var doc = l_explicitDocument();
|
| - if (doc != null) return doc;
|
| - parseFailed();
|
| - return null; // Unreachable.
|
| - }
|
| -
|
| - // 210
|
| - _Node l_anyDocument() =>
|
| - or([l_directiveDocument, l_explicitDocument, l_bareDocument]);
|
| -
|
| - // 211
|
| - List<_Node> l_yamlStream() {
|
| - var docs = [];
|
| - zeroOrMore(l_documentPrefix);
|
| - var first = zeroOrOne(l_anyDocument);
|
| - if (!truth(first)) first = e_node();
|
| - docs.add(first);
|
| -
|
| - zeroOrMore(() {
|
| - var doc;
|
| - if (truth(oneOrMore(l_documentSuffix))) {
|
| - zeroOrMore(l_documentPrefix);
|
| - doc = zeroOrOne(l_anyDocument);
|
| - } else {
|
| - zeroOrMore(l_documentPrefix);
|
| - doc = zeroOrOne(l_explicitDocument);
|
| - }
|
| - if (truth(doc)) docs.add(doc);
|
| - return doc;
|
| - });
|
| -
|
| - if (!atEndOfFile) parseFailed();
|
| - return docs;
|
| - }
|
| -}
|
| -
|
| -class SyntaxError extends YamlException {
|
| - final int line;
|
| - final int column;
|
| -
|
| - SyntaxError(this.line, this.column, String msg) : super(msg);
|
| -
|
| - String toString() => "Syntax error on line $line, column $column: $msg";
|
| -}
|
| -
|
| -/// A pair of values.
|
| -class _Pair<E, F> {
|
| - E first;
|
| - F last;
|
| -
|
| - _Pair(this.first, this.last);
|
| -
|
| - String toString() => '($first, $last)';
|
| -}
|
| -
|
| -/// The information in the header for a block scalar.
|
| -class _BlockHeader {
|
| - final int additionalIndent;
|
| - final int chomping;
|
| -
|
| - _BlockHeader(this.additionalIndent, this.chomping);
|
| -
|
| - bool get autoDetectIndent => additionalIndent == null;
|
| -}
|
| -
|
| -/// A range of characters in the YAML document, from [start] to [end]
|
| -/// (inclusive).
|
| -class _Range {
|
| - /// The first character in the range.
|
| - final int start;
|
| -
|
| - /// The last character in the range.
|
| - final int end;
|
| -
|
| - _Range(this.start, this.end);
|
| -
|
| - /// Returns whether or not [pos] lies within this range.
|
| - bool contains(int pos) => pos >= start && pos <= end;
|
| -}
|
| -
|
| -/// A map that associates [E] values with [_Range]s. It's efficient to create
|
| -/// new associations, but finding the value associated with a position is more
|
| -/// expensive.
|
| -class _RangeMap<E> {
|
| - /// The ranges and their associated elements.
|
| - final List<_Pair<_Range, E>> contents;
|
| -
|
| - _RangeMap() : this.contents = <_Pair<_Range, E>>[];
|
| -
|
| - /// Returns the value associated with the range in which [pos] lies, or null
|
| - /// if there is no such range. If there's more than one such range, the most
|
| - /// recently set one is used.
|
| - E operator[](int pos) {
|
| - // Iterate backwards through contents so the more recent range takes
|
| - // precedence. TODO(nweiz): clean this up when issue 2804 is fixed.
|
| - for (var i = contents.length - 1; i >= 0; i--) {
|
| - var pair = contents[i];
|
| - if (pair.first.contains(pos)) return pair.last;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /// Associates [value] with [range].
|
| - operator[]=(_Range range, E value) =>
|
| - contents.add(new _Pair<_Range, E>(range, value));
|
| -}
|
|
|