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 library fasta.scanner.keywords; | |
6 | |
7 import '../../scanner/token.dart' as analyzer; | |
8 | |
9 import 'characters.dart' show $a, $z, $A, $Z; | |
10 | |
11 import 'precedence.dart' show PrecedenceInfo; | |
12 | |
13 import 'precedence.dart' show AS_INFO, IS_INFO, KEYWORD_INFO; | |
14 | |
15 /** | |
16 * A keyword in the Dart programming language. | |
17 */ | |
18 class Keyword extends analyzer.Keyword { | |
19 static const ASSERT = const Keyword("assert"); | |
20 static const BREAK = const Keyword("break"); | |
21 static const CASE = const Keyword("case"); | |
22 static const CATCH = const Keyword("catch"); | |
23 static const CLASS = const Keyword("class"); | |
24 static const CONST = const Keyword("const"); | |
25 static const CONTINUE = const Keyword("continue"); | |
26 static const DEFAULT = const Keyword("default"); | |
27 static const DO = const Keyword("do"); | |
28 static const ELSE = const Keyword("else"); | |
29 static const ENUM = const Keyword("enum"); | |
30 static const EXTENDS = const Keyword("extends"); | |
31 static const FALSE = const Keyword("false"); | |
32 static const FINAL = const Keyword("final"); | |
33 static const FINALLY = const Keyword("finally"); | |
34 static const FOR = const Keyword("for"); | |
35 static const IF = const Keyword("if"); | |
36 static const IN = const Keyword("in"); | |
37 static const NEW = const Keyword("new"); | |
38 static const NULL = const Keyword("null"); | |
39 static const RETHROW = const Keyword("rethrow"); | |
40 static const RETURN = const Keyword("return"); | |
41 static const SUPER = const Keyword("super"); | |
42 static const SWITCH = const Keyword("switch"); | |
43 static const THIS = const Keyword("this"); | |
44 static const THROW = const Keyword("throw"); | |
45 static const TRUE = const Keyword("true"); | |
46 static const TRY = const Keyword("try"); | |
47 static const VAR = const Keyword("var"); | |
48 static const VOID = const Keyword("void"); | |
49 static const WHILE = const Keyword("while"); | |
50 static const WITH = const Keyword("with"); | |
51 | |
52 // TODO(ahe): Don't think this is a reserved word. | |
53 // See: http://dartbug.com/5579 | |
54 static const IS = const Keyword("is", info: IS_INFO); | |
55 | |
56 static const ABSTRACT = const Keyword("abstract", isBuiltIn: true); | |
57 static const AS = const Keyword("as", info: AS_INFO, isBuiltIn: true); | |
58 static const COVARIANT = const Keyword("covariant", isBuiltIn: true); | |
59 static const DYNAMIC = const Keyword("dynamic", isBuiltIn: true); | |
60 static const EXPORT = const Keyword("export", isBuiltIn: true); | |
61 static const EXTERNAL = const Keyword("external", isBuiltIn: true); | |
62 static const FACTORY = const Keyword("factory", isBuiltIn: true); | |
63 static const GET = const Keyword("get", isBuiltIn: true); | |
64 static const IMPLEMENTS = const Keyword("implements", isBuiltIn: true); | |
65 static const IMPORT = const Keyword("import", isBuiltIn: true); | |
66 static const LIBRARY = const Keyword("library", isBuiltIn: true); | |
67 static const OPERATOR = const Keyword("operator", isBuiltIn: true); | |
68 static const PART = const Keyword("part", isBuiltIn: true); | |
69 static const SET = const Keyword("set", isBuiltIn: true); | |
70 static const STATIC = const Keyword("static", isBuiltIn: true); | |
71 static const TYPEDEF = const Keyword("typedef", isBuiltIn: true); | |
72 | |
73 static const ASYNC = const Keyword("async", isPseudo: true); | |
74 static const AWAIT = const Keyword("await", isPseudo: true); | |
75 static const DEFERRED = const Keyword("deferred", isBuiltIn: true); | |
76 static const FUNCTION = const Keyword("Function", isPseudo: true); | |
77 static const HIDE = const Keyword("hide", isPseudo: true); | |
78 static const NATIVE = const Keyword("native", isPseudo: true); | |
79 static const OF = const Keyword("of", isPseudo: true); | |
80 static const ON = const Keyword("on", isPseudo: true); | |
81 static const PATCH = const Keyword("patch", isPseudo: true); | |
82 static const SHOW = const Keyword("show", isPseudo: true); | |
83 static const SOURCE = const Keyword("source", isPseudo: true); | |
84 static const SYNC = const Keyword("sync", isPseudo: true); | |
85 static const YIELD = const Keyword("yield", isPseudo: true); | |
86 | |
87 static const List<Keyword> values = const <Keyword>[ | |
88 ASSERT, | |
89 BREAK, | |
90 CASE, | |
91 CATCH, | |
92 CLASS, | |
93 CONST, | |
94 CONTINUE, | |
95 DEFAULT, | |
96 DO, | |
97 ELSE, | |
98 ENUM, | |
99 EXTENDS, | |
100 FALSE, | |
101 FINAL, | |
102 FINALLY, | |
103 FOR, | |
104 IF, | |
105 IN, | |
106 NEW, | |
107 NULL, | |
108 RETHROW, | |
109 RETURN, | |
110 SUPER, | |
111 SWITCH, | |
112 THIS, | |
113 THROW, | |
114 TRUE, | |
115 TRY, | |
116 VAR, | |
117 VOID, | |
118 WHILE, | |
119 WITH, | |
120 // ==== | |
121 IS, | |
122 // ==== Built In | |
123 ABSTRACT, | |
124 AS, | |
125 COVARIANT, | |
126 DEFERRED, | |
127 DYNAMIC, | |
128 EXPORT, | |
129 EXTERNAL, | |
130 FACTORY, | |
131 GET, | |
132 IMPLEMENTS, | |
133 IMPORT, | |
134 LIBRARY, | |
135 OPERATOR, | |
136 PART, | |
137 SET, | |
138 STATIC, | |
139 TYPEDEF, | |
140 // ==== Pseudo | |
141 ASYNC, | |
142 AWAIT, | |
143 FUNCTION, | |
144 HIDE, | |
145 NATIVE, | |
146 OF, | |
147 ON, | |
148 PATCH, | |
149 SHOW, | |
150 SOURCE, | |
151 SYNC, | |
152 YIELD, | |
153 ]; | |
154 | |
155 static Map<String, Keyword> _keywords; | |
156 static Map<String, Keyword> get keywords { | |
157 if (_keywords == null) { | |
158 _keywords = computeKeywordMap(); | |
159 } | |
160 return _keywords; | |
161 } | |
162 | |
163 const Keyword(String syntax, | |
164 {bool isPseudo: false, | |
165 bool isBuiltIn: false, | |
166 PrecedenceInfo info: KEYWORD_INFO}) | |
167 : super(syntax, info: info, isBuiltIn: isBuiltIn, isPseudo: isPseudo); | |
168 | |
169 static Map<String, Keyword> computeKeywordMap() { | |
170 Map<String, Keyword> result = new Map<String, Keyword>(); | |
171 for (Keyword keyword in values) { | |
172 result[keyword.syntax] = keyword; | |
173 } | |
174 return result; | |
175 } | |
176 } | |
177 | |
178 /** | |
179 * Abstract state in a state machine for scanning keywords. | |
180 */ | |
181 abstract class KeywordState { | |
182 KeywordState next(int c); | |
183 KeywordState nextCapital(int c); | |
184 | |
185 Keyword get keyword; | |
186 | |
187 static KeywordState _KEYWORD_STATE; | |
188 static KeywordState get KEYWORD_STATE { | |
189 if (_KEYWORD_STATE == null) { | |
190 List<String> strings = new List<String>(Keyword.values.length); | |
191 for (int i = 0; i < Keyword.values.length; i++) { | |
192 strings[i] = Keyword.values[i].syntax; | |
193 } | |
194 strings.sort((a, b) => a.compareTo(b)); | |
195 _KEYWORD_STATE = computeKeywordStateTable(0, strings, 0, strings.length); | |
196 } | |
197 return _KEYWORD_STATE; | |
198 } | |
199 | |
200 static KeywordState computeKeywordStateTable( | |
201 int start, List<String> strings, int offset, int length) { | |
202 bool isLowercase = true; | |
203 | |
204 List<KeywordState> table = new List<KeywordState>($z - $A + 1); | |
205 assert(length != 0); | |
206 int chunk = 0; | |
207 int chunkStart = -1; | |
208 bool isLeaf = false; | |
209 for (int i = offset; i < offset + length; i++) { | |
210 if (strings[i].length == start) { | |
211 isLeaf = true; | |
212 } | |
213 if (strings[i].length > start) { | |
214 int c = strings[i].codeUnitAt(start); | |
215 if ($A <= c && c <= $Z) { | |
216 isLowercase = false; | |
217 } | |
218 if (chunk != c) { | |
219 if (chunkStart != -1) { | |
220 assert(table[chunk - $A] == null); | |
221 table[chunk - $A] = computeKeywordStateTable( | |
222 start + 1, strings, chunkStart, i - chunkStart); | |
223 } | |
224 chunkStart = i; | |
225 chunk = c; | |
226 } | |
227 } | |
228 } | |
229 if (chunkStart != -1) { | |
230 assert(table[chunk - $A] == null); | |
231 table[chunk - $A] = computeKeywordStateTable( | |
232 start + 1, strings, chunkStart, offset + length - chunkStart); | |
233 } else { | |
234 assert(length == 1); | |
235 return new LeafKeywordState(strings[offset]); | |
236 } | |
237 String syntax = isLeaf ? strings[offset] : null; | |
238 if (isLowercase) { | |
239 table = table.sublist($a - $A); | |
240 return new LowerCaseArrayKeywordState(table, syntax); | |
241 } else { | |
242 return new UpperCaseArrayKeywordState(table, syntax); | |
243 } | |
244 } | |
245 } | |
246 | |
247 /** | |
248 * A state with multiple outgoing transitions. | |
249 */ | |
250 abstract class ArrayKeywordState implements KeywordState { | |
251 final List<KeywordState> table; | |
252 final Keyword keyword; | |
253 | |
254 ArrayKeywordState(this.table, String syntax) | |
255 : keyword = ((syntax == null) ? null : Keyword.keywords[syntax]); | |
256 | |
257 KeywordState next(int c); | |
258 | |
259 KeywordState nextCapital(int c); | |
260 | |
261 String toString() { | |
262 StringBuffer sb = new StringBuffer(); | |
263 sb.write("["); | |
264 if (keyword != null) { | |
265 sb.write("*"); | |
266 sb.write(keyword); | |
267 sb.write(" "); | |
268 } | |
269 List<KeywordState> foo = table; | |
270 for (int i = 0; i < foo.length; i++) { | |
271 if (foo[i] != null) { | |
272 sb.write("${new String.fromCharCodes([i + $a])}: " | |
273 "${foo[i]}; "); | |
274 } | |
275 } | |
276 sb.write("]"); | |
277 return sb.toString(); | |
278 } | |
279 } | |
280 | |
281 class LowerCaseArrayKeywordState extends ArrayKeywordState { | |
282 LowerCaseArrayKeywordState(List<KeywordState> table, String syntax) | |
283 : super(table, syntax) { | |
284 assert(table.length == $z - $a + 1); | |
285 } | |
286 | |
287 KeywordState next(int c) => table[c - $a]; | |
288 | |
289 KeywordState nextCapital(int c) => null; | |
290 } | |
291 | |
292 class UpperCaseArrayKeywordState extends ArrayKeywordState { | |
293 UpperCaseArrayKeywordState(List<KeywordState> table, String syntax) | |
294 : super(table, syntax) { | |
295 assert(table.length == $z - $A + 1); | |
296 } | |
297 | |
298 KeywordState next(int c) => table[c - $A]; | |
299 | |
300 KeywordState nextCapital(int c) => table[c - $A]; | |
301 } | |
302 | |
303 /** | |
304 * A state that has no outgoing transitions. | |
305 */ | |
306 class LeafKeywordState implements KeywordState { | |
307 final Keyword keyword; | |
308 | |
309 LeafKeywordState(String syntax) : keyword = Keyword.keywords[syntax]; | |
310 | |
311 KeywordState next(int c) => null; | |
312 KeywordState nextCapital(int c) => null; | |
313 | |
314 String toString() => keyword.syntax; | |
315 } | |
OLD | NEW |