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 |