| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 class ArrayBasedScanner<S> extends AbstractScanner<S> { | |
| 6 int get charOffset() => byteOffset + extraCharOffset; | |
| 7 final Token tokens; | |
| 8 Token tail; | |
| 9 int tokenStart; | |
| 10 int byteOffset; | |
| 11 | |
| 12 /** Since the input is UTF8, some characters are represented by more | |
| 13 * than one byte. [extraCharOffset] tracks the difference. */ | |
| 14 int extraCharOffset; | |
| 15 Link<BeginGroupToken> groupingStack = const EmptyLink<BeginGroupToken>(); | |
| 16 | |
| 17 ArrayBasedScanner() | |
| 18 : this.extraCharOffset = 0, | |
| 19 this.tokenStart = -1, | |
| 20 this.byteOffset = -1, | |
| 21 this.tokens = new Token(EOF_INFO, -1) { | |
| 22 this.tail = this.tokens; | |
| 23 } | |
| 24 | |
| 25 int advance() { | |
| 26 int next = nextByte(); | |
| 27 return next; | |
| 28 } | |
| 29 | |
| 30 int select(int choice, PrecedenceInfo yes, PrecedenceInfo no) { | |
| 31 int next = advance(); | |
| 32 if (next === choice) { | |
| 33 appendPrecenceToken(yes); | |
| 34 return advance(); | |
| 35 } else { | |
| 36 appendPrecenceToken(no); | |
| 37 return next; | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 void appendPrecenceToken(PrecedenceInfo info) { | |
| 42 tail.next = new Token(info, tokenStart); | |
| 43 tail = tail.next; | |
| 44 } | |
| 45 | |
| 46 void appendStringToken(PrecedenceInfo info, String value) { | |
| 47 tail.next = new StringToken(info, value, tokenStart); | |
| 48 tail = tail.next; | |
| 49 } | |
| 50 | |
| 51 void appendKeywordToken(Keyword keyword) { | |
| 52 tail.next = new KeywordToken(keyword, tokenStart); | |
| 53 tail = tail.next; | |
| 54 } | |
| 55 | |
| 56 void appendEofToken() { | |
| 57 tail.next = new Token(EOF_INFO, charOffset); | |
| 58 tail = tail.next; | |
| 59 // EOF points to itself so there's always infinite look-ahead. | |
| 60 tail.next = tail; | |
| 61 discardOpenLt(); | |
| 62 if (!groupingStack.isEmpty()) { | |
| 63 BeginGroupToken begin = groupingStack.head; | |
| 64 throw new MalformedInputException('Unbalanced ${begin.stringValue}', | |
| 65 begin); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 void beginToken() { | |
| 70 tokenStart = charOffset; | |
| 71 } | |
| 72 | |
| 73 Token firstToken() { | |
| 74 return tokens.next; | |
| 75 } | |
| 76 | |
| 77 void addToCharOffset(int offset) { | |
| 78 extraCharOffset += offset; | |
| 79 } | |
| 80 | |
| 81 void appendWhiteSpace(int next) { | |
| 82 // Do nothing, we don't collect white space. | |
| 83 } | |
| 84 | |
| 85 void appendBeginGroup(PrecedenceInfo info, String value) { | |
| 86 Token token = new BeginGroupToken(info, value, tokenStart); | |
| 87 tail.next = token; | |
| 88 tail = tail.next; | |
| 89 while (info.kind !== LT_TOKEN && | |
| 90 !groupingStack.isEmpty() && | |
| 91 groupingStack.head.kind === LT_TOKEN) { | |
| 92 groupingStack = groupingStack.tail; | |
| 93 } | |
| 94 groupingStack = groupingStack.prepend(token); | |
| 95 } | |
| 96 | |
| 97 int appendEndGroup(PrecedenceInfo info, String value, int openKind) { | |
| 98 assert(openKind !== LT_TOKEN); | |
| 99 appendStringToken(info, value); | |
| 100 discardOpenLt(); | |
| 101 if (groupingStack.isEmpty()) { | |
| 102 return advance(); | |
| 103 } | |
| 104 BeginGroupToken begin = groupingStack.head; | |
| 105 if (begin.kind !== openKind) { | |
| 106 if (openKind !== OPEN_CURLY_BRACKET_TOKEN || | |
| 107 begin.kind !== STRING_INTERPOLATION_TOKEN) { | |
| 108 // Not ending string interpolation. | |
| 109 throw new MalformedInputException('Unmatched ${begin.stringValue}', | |
| 110 begin); | |
| 111 } | |
| 112 // We're ending an interpolated expression. | |
| 113 begin.endGroup = tail; | |
| 114 groupingStack = groupingStack.tail; | |
| 115 // Using "start-of-text" to signal that we're back in string | |
| 116 // scanning mode. | |
| 117 return $STX; | |
| 118 } | |
| 119 begin.endGroup = tail; | |
| 120 groupingStack = groupingStack.tail; | |
| 121 return advance(); | |
| 122 } | |
| 123 | |
| 124 void appendGt(PrecedenceInfo info, String value) { | |
| 125 appendStringToken(info, value); | |
| 126 if (groupingStack.isEmpty()) return; | |
| 127 if (groupingStack.head.kind === LT_TOKEN) { | |
| 128 groupingStack.head.endGroup = tail; | |
| 129 groupingStack = groupingStack.tail; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void appendGtGt(PrecedenceInfo info, String value) { | |
| 134 appendStringToken(info, value); | |
| 135 if (groupingStack.isEmpty()) return; | |
| 136 if (groupingStack.head.kind === LT_TOKEN) { | |
| 137 groupingStack = groupingStack.tail; | |
| 138 } | |
| 139 if (groupingStack.isEmpty()) return; | |
| 140 if (groupingStack.head.kind === LT_TOKEN) { | |
| 141 groupingStack.head.endGroup = tail; | |
| 142 groupingStack = groupingStack.tail; | |
| 143 } | |
| 144 } | |
| 145 | |
| 146 void appendGtGtGt(PrecedenceInfo info, String value) { | |
| 147 appendStringToken(info, value); | |
| 148 if (groupingStack.isEmpty()) return; | |
| 149 if (groupingStack.head.kind === LT_TOKEN) { | |
| 150 groupingStack = groupingStack.tail; | |
| 151 } | |
| 152 if (groupingStack.isEmpty()) return; | |
| 153 if (groupingStack.head.kind === LT_TOKEN) { | |
| 154 groupingStack = groupingStack.tail; | |
| 155 } | |
| 156 if (groupingStack.isEmpty()) return; | |
| 157 if (groupingStack.head.kind === LT_TOKEN) { | |
| 158 groupingStack.head.endGroup = tail; | |
| 159 groupingStack = groupingStack.tail; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 void discardOpenLt() { | |
| 164 while (!groupingStack.isEmpty() && groupingStack.head.kind === LT_TOKEN) { | |
| 165 groupingStack = groupingStack.tail; | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 // TODO(ahe): make class abstract instead of adding an abstract method. | |
| 170 abstract peek(); | |
| 171 } | |
| OLD | NEW |