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 #include "vm/scanner.h" | 5 #include "vm/scanner.h" |
6 | 6 |
7 #include "platform/assert.h" | 7 #include "platform/assert.h" |
8 #include "vm/dart.h" | 8 #include "vm/dart.h" |
9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
10 #include "vm/object.h" | 10 #include "vm/object.h" |
11 #include "vm/object_store.h" | 11 #include "vm/object_store.h" |
12 #include "vm/symbols.h" | 12 #include "vm/symbols.h" |
13 #include "vm/token.h" | 13 #include "vm/token.h" |
14 #include "vm/unicode.h" | 14 #include "vm/unicode.h" |
15 | 15 |
16 namespace dart { | 16 namespace dart { |
17 | 17 |
18 // Quick access to the locally defined zone() and thread() methods. | 18 // Quick access to the locally defined zone() and thread() methods. |
19 #define Z (zone()) | 19 #define Z (zone()) |
20 #define T (thread()) | 20 #define T (thread()) |
21 | 21 |
22 | |
23 class ScanContext : public ZoneAllocated { | 22 class ScanContext : public ZoneAllocated { |
24 public: | 23 public: |
25 explicit ScanContext(Scanner* scanner) | 24 explicit ScanContext(Scanner* scanner) |
26 : next_(scanner->saved_context_), | 25 : next_(scanner->saved_context_), |
27 string_delimiter_(scanner->string_delimiter_), | 26 string_delimiter_(scanner->string_delimiter_), |
28 string_is_multiline_(scanner->string_is_multiline_), | 27 string_is_multiline_(scanner->string_is_multiline_), |
29 brace_level_(scanner->brace_level_) {} | 28 brace_level_(scanner->brace_level_) {} |
30 | 29 |
31 void CopyTo(Scanner* scanner) { | 30 void CopyTo(Scanner* scanner) { |
32 scanner->string_delimiter_ = string_delimiter_; | 31 scanner->string_delimiter_ = string_delimiter_; |
33 scanner->string_is_multiline_ = string_is_multiline_; | 32 scanner->string_is_multiline_ = string_is_multiline_; |
34 scanner->brace_level_ = brace_level_; | 33 scanner->brace_level_ = brace_level_; |
35 } | 34 } |
36 | 35 |
37 ScanContext* next() const { return next_; } | 36 ScanContext* next() const { return next_; } |
38 | 37 |
39 private: | 38 private: |
40 ScanContext* next_; | 39 ScanContext* next_; |
41 const char string_delimiter_; | 40 const char string_delimiter_; |
42 const bool string_is_multiline_; | 41 const bool string_is_multiline_; |
43 const int brace_level_; | 42 const int brace_level_; |
44 }; | 43 }; |
45 | 44 |
46 | |
47 Scanner::KeywordTable Scanner::keywords_[Token::kNumKeywords]; | 45 Scanner::KeywordTable Scanner::keywords_[Token::kNumKeywords]; |
48 int Scanner::keywords_char_offset_[Scanner::kNumLowercaseChars]; | 46 int Scanner::keywords_char_offset_[Scanner::kNumLowercaseChars]; |
49 | 47 |
50 | |
51 void Scanner::Reset() { | 48 void Scanner::Reset() { |
52 // Non-changing newline properties. | 49 // Non-changing newline properties. |
53 newline_token_.kind = Token::kNEWLINE; | 50 newline_token_.kind = Token::kNEWLINE; |
54 newline_token_.literal = NULL; | 51 newline_token_.literal = NULL; |
55 // We don't preserve the column information. | 52 // We don't preserve the column information. |
56 newline_token_.position.column = 0; | 53 newline_token_.position.column = 0; |
57 | 54 |
58 // Non-changing empty string token properties. | 55 // Non-changing empty string token properties. |
59 empty_string_token_.kind = Token::kSTRING; | 56 empty_string_token_.kind = Token::kSTRING; |
60 empty_string_token_.literal = &Symbols::Empty(); | 57 empty_string_token_.literal = &Symbols::Empty(); |
61 empty_string_token_.position.column = 0; | 58 empty_string_token_.position.column = 0; |
62 | 59 |
63 lookahead_pos_ = -1; | 60 lookahead_pos_ = -1; |
64 token_start_ = 0; | 61 token_start_ = 0; |
65 c0_ = '\0'; | 62 c0_ = '\0'; |
66 newline_seen_ = false; | 63 newline_seen_ = false; |
67 prev_token_line_ = 1; | 64 prev_token_line_ = 1; |
68 saved_context_ = NULL; | 65 saved_context_ = NULL; |
69 string_delimiter_ = '\0'; | 66 string_delimiter_ = '\0'; |
70 string_is_multiline_ = false; | 67 string_is_multiline_ = false; |
71 brace_level_ = 0; | 68 brace_level_ = 0; |
72 c0_pos_.line = 1; | 69 c0_pos_.line = 1; |
73 c0_pos_.column = 0; | 70 c0_pos_.column = 0; |
74 ReadChar(); | 71 ReadChar(); |
75 } | 72 } |
76 | 73 |
77 | |
78 Scanner::Scanner(const String& src, const String& private_key) | 74 Scanner::Scanner(const String& src, const String& private_key) |
79 : source_(src), | 75 : source_(src), |
80 source_length_(src.Length()), | 76 source_length_(src.Length()), |
81 saved_context_(NULL), | 77 saved_context_(NULL), |
82 private_key_(String::ZoneHandle(private_key.raw())), | 78 private_key_(String::ZoneHandle(private_key.raw())), |
83 char_at_func_(src.CharAtFunc()), | 79 char_at_func_(src.CharAtFunc()), |
84 thread_(Thread::Current()), | 80 thread_(Thread::Current()), |
85 zone_(thread_->zone()) { | 81 zone_(thread_->zone()) { |
86 Reset(); | 82 Reset(); |
87 } | 83 } |
88 | 84 |
89 | |
90 Scanner::~Scanner() {} | 85 Scanner::~Scanner() {} |
91 | 86 |
92 | |
93 void Scanner::ErrorMsg(const char* msg) { | 87 void Scanner::ErrorMsg(const char* msg) { |
94 current_token_.kind = Token::kERROR; | 88 current_token_.kind = Token::kERROR; |
95 current_token_.literal = &String::ZoneHandle(Z, Symbols::New(T, msg)); | 89 current_token_.literal = &String::ZoneHandle(Z, Symbols::New(T, msg)); |
96 current_token_.position = c0_pos_; | 90 current_token_.position = c0_pos_; |
97 token_start_ = lookahead_pos_; | 91 token_start_ = lookahead_pos_; |
98 current_token_.offset = lookahead_pos_; | 92 current_token_.offset = lookahead_pos_; |
99 } | 93 } |
100 | 94 |
101 | |
102 void Scanner::PushContext() { | 95 void Scanner::PushContext() { |
103 ScanContext* ctx = new (Z) ScanContext(this); | 96 ScanContext* ctx = new (Z) ScanContext(this); |
104 saved_context_ = ctx; | 97 saved_context_ = ctx; |
105 string_delimiter_ = '\0'; | 98 string_delimiter_ = '\0'; |
106 string_is_multiline_ = false; | 99 string_is_multiline_ = false; |
107 brace_level_ = 1; // Account for the opening ${ token. | 100 brace_level_ = 1; // Account for the opening ${ token. |
108 } | 101 } |
109 | 102 |
110 | |
111 void Scanner::PopContext() { | 103 void Scanner::PopContext() { |
112 ASSERT(saved_context_ != NULL); | 104 ASSERT(saved_context_ != NULL); |
113 ASSERT(brace_level_ == 0); | 105 ASSERT(brace_level_ == 0); |
114 ASSERT(string_delimiter_ == '\0'); | 106 ASSERT(string_delimiter_ == '\0'); |
115 ScanContext* ctx = saved_context_; | 107 ScanContext* ctx = saved_context_; |
116 ctx->CopyTo(this); | 108 ctx->CopyTo(this); |
117 saved_context_ = ctx->next(); | 109 saved_context_ = ctx->next(); |
118 ASSERT(string_delimiter_ != '\0'); | 110 ASSERT(string_delimiter_ != '\0'); |
119 } | 111 } |
120 | 112 |
121 | |
122 void Scanner::BeginStringLiteral(const char delimiter) { | 113 void Scanner::BeginStringLiteral(const char delimiter) { |
123 string_delimiter_ = delimiter; | 114 string_delimiter_ = delimiter; |
124 } | 115 } |
125 | 116 |
126 | |
127 void Scanner::EndStringLiteral() { | 117 void Scanner::EndStringLiteral() { |
128 string_delimiter_ = '\0'; | 118 string_delimiter_ = '\0'; |
129 string_is_multiline_ = false; | 119 string_is_multiline_ = false; |
130 } | 120 } |
131 | 121 |
132 | |
133 bool Scanner::IsLetter(int32_t c) { | 122 bool Scanner::IsLetter(int32_t c) { |
134 return (('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z')); | 123 return (('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z')); |
135 } | 124 } |
136 | 125 |
137 | |
138 bool Scanner::IsDecimalDigit(int32_t c) { | 126 bool Scanner::IsDecimalDigit(int32_t c) { |
139 return '0' <= c && c <= '9'; | 127 return '0' <= c && c <= '9'; |
140 } | 128 } |
141 | 129 |
142 | |
143 bool Scanner::IsNumberStart(int32_t ch) { | 130 bool Scanner::IsNumberStart(int32_t ch) { |
144 return IsDecimalDigit(ch) || ch == '.'; | 131 return IsDecimalDigit(ch) || ch == '.'; |
145 } | 132 } |
146 | 133 |
147 | |
148 bool Scanner::IsHexDigit(int32_t c) { | 134 bool Scanner::IsHexDigit(int32_t c) { |
149 return IsDecimalDigit(c) || (('A' <= c) && (c <= 'F')) || | 135 return IsDecimalDigit(c) || (('A' <= c) && (c <= 'F')) || |
150 (('a' <= c) && (c <= 'f')); | 136 (('a' <= c) && (c <= 'f')); |
151 } | 137 } |
152 | 138 |
153 | |
154 bool Scanner::IsIdentStartChar(int32_t c) { | 139 bool Scanner::IsIdentStartChar(int32_t c) { |
155 return IsLetter(c) || (c == '_') || (c == '$'); | 140 return IsLetter(c) || (c == '_') || (c == '$'); |
156 } | 141 } |
157 | 142 |
158 | |
159 bool Scanner::IsIdentChar(int32_t c) { | 143 bool Scanner::IsIdentChar(int32_t c) { |
160 return IsLetter(c) || IsDecimalDigit(c) || (c == '_') || (c == '$'); | 144 return IsLetter(c) || IsDecimalDigit(c) || (c == '_') || (c == '$'); |
161 } | 145 } |
162 | 146 |
163 | |
164 bool Scanner::IsIdent(const String& str) { | 147 bool Scanner::IsIdent(const String& str) { |
165 if (!str.IsOneByteString()) { | 148 if (!str.IsOneByteString()) { |
166 return false; | 149 return false; |
167 } | 150 } |
168 if (str.Length() == 0 || !IsIdentStartChar(CallCharAt()(str, 0))) { | 151 if (str.Length() == 0 || !IsIdentStartChar(CallCharAt()(str, 0))) { |
169 return false; | 152 return false; |
170 } | 153 } |
171 for (int i = 1; i < str.Length(); i++) { | 154 for (int i = 1; i < str.Length(); i++) { |
172 if (!IsIdentChar(CallCharAt()(str, i))) { | 155 if (!IsIdentChar(CallCharAt()(str, i))) { |
173 return false; | 156 return false; |
174 } | 157 } |
175 } | 158 } |
176 return true; | 159 return true; |
177 } | 160 } |
178 | 161 |
179 | |
180 // This method is used when parsing integers in Dart code. We | 162 // This method is used when parsing integers in Dart code. We |
181 // are reusing the Scanner's handling of number literals in that situation. | 163 // are reusing the Scanner's handling of number literals in that situation. |
182 bool Scanner::IsValidInteger(const String& str, | 164 bool Scanner::IsValidInteger(const String& str, |
183 bool* is_positive, | 165 bool* is_positive, |
184 const String** value) { | 166 const String** value) { |
185 Scanner s(str, Symbols::Empty()); | 167 Scanner s(str, Symbols::Empty()); |
186 TokenDescriptor tokens[3]; | 168 TokenDescriptor tokens[3]; |
187 s.Scan(); | 169 s.Scan(); |
188 tokens[0] = s.current_token(); | 170 tokens[0] = s.current_token(); |
189 s.Scan(); | 171 s.Scan(); |
(...skipping 12 matching lines...) Expand all Loading... |
202 if ((tokens[0].offset + 1) != tokens[1].offset) { | 184 if ((tokens[0].offset + 1) != tokens[1].offset) { |
203 return false; | 185 return false; |
204 } | 186 } |
205 *is_positive = tokens[0].kind == Token::kADD; | 187 *is_positive = tokens[0].kind == Token::kADD; |
206 *value = tokens[1].literal; | 188 *value = tokens[1].literal; |
207 return true; | 189 return true; |
208 } | 190 } |
209 return false; | 191 return false; |
210 } | 192 } |
211 | 193 |
212 | |
213 void Scanner::ReadChar() { | 194 void Scanner::ReadChar() { |
214 if (lookahead_pos_ < source_length_) { | 195 if (lookahead_pos_ < source_length_) { |
215 if (c0_ == '\n') { | 196 if (c0_ == '\n') { |
216 newline_seen_ = true; | 197 newline_seen_ = true; |
217 c0_pos_.line++; | 198 c0_pos_.line++; |
218 c0_pos_.column = 0; | 199 c0_pos_.column = 0; |
219 if (CallCharAt()(source_, lookahead_pos_) == '\r') { | 200 if (CallCharAt()(source_, lookahead_pos_) == '\r') { |
220 // Replace a sequence of '\r' '\n' with a single '\n'. | 201 // Replace a sequence of '\r' '\n' with a single '\n'. |
221 if (LookaheadChar(1) == '\n') { | 202 if (LookaheadChar(1) == '\n') { |
222 lookahead_pos_++; | 203 lookahead_pos_++; |
223 } | 204 } |
224 } | 205 } |
225 } | 206 } |
226 lookahead_pos_++; | 207 lookahead_pos_++; |
227 c0_pos_.column++; | 208 c0_pos_.column++; |
228 c0_ = LookaheadChar(0); | 209 c0_ = LookaheadChar(0); |
229 // Replace '\r' with '\n'. | 210 // Replace '\r' with '\n'. |
230 if (c0_ == '\r') { | 211 if (c0_ == '\r') { |
231 c0_ = '\n'; | 212 c0_ = '\n'; |
232 } | 213 } |
233 } | 214 } |
234 } | 215 } |
235 | 216 |
236 | |
237 // Look ahead 'how_many' characters. Returns the character, or '\0' if | 217 // Look ahead 'how_many' characters. Returns the character, or '\0' if |
238 // the lookahead position is beyond the end of the string. Does not | 218 // the lookahead position is beyond the end of the string. Does not |
239 // normalize line end characters into '\n'. | 219 // normalize line end characters into '\n'. |
240 int32_t Scanner::LookaheadChar(int how_many) { | 220 int32_t Scanner::LookaheadChar(int how_many) { |
241 ASSERT(how_many >= 0); | 221 ASSERT(how_many >= 0); |
242 int32_t lookahead_char = '\0'; | 222 int32_t lookahead_char = '\0'; |
243 if (lookahead_pos_ + how_many < source_length_) { | 223 if (lookahead_pos_ + how_many < source_length_) { |
244 lookahead_char = CallCharAt()(source_, lookahead_pos_ + how_many); | 224 lookahead_char = CallCharAt()(source_, lookahead_pos_ + how_many); |
245 } | 225 } |
246 return lookahead_char; | 226 return lookahead_char; |
247 } | 227 } |
248 | 228 |
249 | |
250 void Scanner::ConsumeWhiteSpace() { | 229 void Scanner::ConsumeWhiteSpace() { |
251 while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n') { | 230 while (c0_ == ' ' || c0_ == '\t' || c0_ == '\n') { |
252 ReadChar(); | 231 ReadChar(); |
253 } | 232 } |
254 } | 233 } |
255 | 234 |
256 | |
257 void Scanner::ConsumeLineComment() { | 235 void Scanner::ConsumeLineComment() { |
258 ASSERT(c0_ == '/'); | 236 ASSERT(c0_ == '/'); |
259 while (c0_ != '\n' && c0_ != '\0') { | 237 while (c0_ != '\n' && c0_ != '\0') { |
260 ReadChar(); | 238 ReadChar(); |
261 } | 239 } |
262 ReadChar(); | 240 ReadChar(); |
263 current_token_.kind = Token::kWHITESP; | 241 current_token_.kind = Token::kWHITESP; |
264 } | 242 } |
265 | 243 |
266 | |
267 void Scanner::ConsumeBlockComment() { | 244 void Scanner::ConsumeBlockComment() { |
268 ASSERT(c0_ == '*'); | 245 ASSERT(c0_ == '*'); |
269 ReadChar(); | 246 ReadChar(); |
270 int nesting_level = 1; | 247 int nesting_level = 1; |
271 | 248 |
272 while (true) { | 249 while (true) { |
273 const char c = c0_; | 250 const char c = c0_; |
274 ReadChar(); | 251 ReadChar(); |
275 if (c0_ == '\0') { | 252 if (c0_ == '\0') { |
276 break; | 253 break; |
277 } | 254 } |
278 if (c == '/' && c0_ == '*') { | 255 if (c == '/' && c0_ == '*') { |
279 nesting_level++; | 256 nesting_level++; |
280 ReadChar(); // Consume asterisk. | 257 ReadChar(); // Consume asterisk. |
281 } else if (c == '*' && c0_ == '/') { | 258 } else if (c == '*' && c0_ == '/') { |
282 nesting_level--; | 259 nesting_level--; |
283 ReadChar(); // Consume slash. | 260 ReadChar(); // Consume slash. |
284 if (nesting_level == 0) { | 261 if (nesting_level == 0) { |
285 break; | 262 break; |
286 } | 263 } |
287 } | 264 } |
288 } | 265 } |
289 current_token_.kind = | 266 current_token_.kind = |
290 (nesting_level == 0) ? Token::kWHITESP : Token::kILLEGAL; | 267 (nesting_level == 0) ? Token::kWHITESP : Token::kILLEGAL; |
291 } | 268 } |
292 | 269 |
293 | |
294 void Scanner::ScanIdentChars(bool allow_dollar) { | 270 void Scanner::ScanIdentChars(bool allow_dollar) { |
295 ASSERT(IsIdentStartChar(c0_)); | 271 ASSERT(IsIdentStartChar(c0_)); |
296 ASSERT(allow_dollar || (c0_ != '$')); | 272 ASSERT(allow_dollar || (c0_ != '$')); |
297 int ident_length = 0; | 273 int ident_length = 0; |
298 int ident_pos = lookahead_pos_; | 274 int ident_pos = lookahead_pos_; |
299 int32_t ident_char0 = CallCharAt()(source_, ident_pos); | 275 int32_t ident_char0 = CallCharAt()(source_, ident_pos); |
300 while (IsIdentChar(c0_) && (allow_dollar || (c0_ != '$'))) { | 276 while (IsIdentChar(c0_) && (allow_dollar || (c0_ != '$'))) { |
301 ReadChar(); | 277 ReadChar(); |
302 ident_length++; | 278 ident_length++; |
303 } | 279 } |
(...skipping 28 matching lines...) Expand all Loading... |
332 if (ident_char0 == Library::kPrivateIdentifierStart) { | 308 if (ident_char0 == Library::kPrivateIdentifierStart) { |
333 // Private identifiers are mangled on a per library basis. | 309 // Private identifiers are mangled on a per library basis. |
334 literal = String::SubString(T, source_, ident_pos, ident_length); | 310 literal = String::SubString(T, source_, ident_pos, ident_length); |
335 literal = Symbols::FromConcat(T, literal, private_key_); | 311 literal = Symbols::FromConcat(T, literal, private_key_); |
336 } else { | 312 } else { |
337 literal = Symbols::New(T, source_, ident_pos, ident_length); | 313 literal = Symbols::New(T, source_, ident_pos, ident_length); |
338 } | 314 } |
339 current_token_.literal = &literal; | 315 current_token_.literal = &literal; |
340 } | 316 } |
341 | 317 |
342 | |
343 // Parse integer or double number literal of format: | 318 // Parse integer or double number literal of format: |
344 // NUMBER = INTEGER | DOUBLE | 319 // NUMBER = INTEGER | DOUBLE |
345 // INTEGER = D+ | (("0x" | "0X") H+) | 320 // INTEGER = D+ | (("0x" | "0X") H+) |
346 // DOUBLE = ((D+ ["." D*]) | ("." D+)) [ EXPONENT ] | 321 // DOUBLE = ((D+ ["." D*]) | ("." D+)) [ EXPONENT ] |
347 // EXPONENT = ("e" | "E") ["+" | "-"] D+ | 322 // EXPONENT = ("e" | "E") ["+" | "-"] D+ |
348 void Scanner::ScanNumber(bool dec_point_seen) { | 323 void Scanner::ScanNumber(bool dec_point_seen) { |
349 ASSERT(IsDecimalDigit(c0_)); | 324 ASSERT(IsDecimalDigit(c0_)); |
350 char first_digit = c0_; | 325 char first_digit = c0_; |
351 | 326 |
352 Recognize(dec_point_seen ? Token::kDOUBLE : Token::kINTEGER); | 327 Recognize(dec_point_seen ? Token::kDOUBLE : Token::kINTEGER); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 } | 361 } |
387 } | 362 } |
388 if (current_token_.kind != Token::kILLEGAL) { | 363 if (current_token_.kind != Token::kILLEGAL) { |
389 intptr_t len = lookahead_pos_ - token_start_; | 364 intptr_t len = lookahead_pos_ - token_start_; |
390 const String& str = | 365 const String& str = |
391 String::ZoneHandle(Z, Symbols::New(T, source_, token_start_, len)); | 366 String::ZoneHandle(Z, Symbols::New(T, source_, token_start_, len)); |
392 current_token_.literal = &str; | 367 current_token_.literal = &str; |
393 } | 368 } |
394 } | 369 } |
395 | 370 |
396 | |
397 void Scanner::SkipLine() { | 371 void Scanner::SkipLine() { |
398 while (c0_ != '\n' && c0_ != '\0') { | 372 while (c0_ != '\n' && c0_ != '\0') { |
399 ReadChar(); | 373 ReadChar(); |
400 } | 374 } |
401 } | 375 } |
402 | 376 |
403 | |
404 void Scanner::ScanScriptTag() { | 377 void Scanner::ScanScriptTag() { |
405 ReadChar(); | 378 ReadChar(); |
406 ASSERT(c0_ == '!'); | 379 ASSERT(c0_ == '!'); |
407 Recognize(Token::kSCRIPTTAG); | 380 Recognize(Token::kSCRIPTTAG); |
408 // The script tag extends to the end of the line. Just treat this | 381 // The script tag extends to the end of the line. Just treat this |
409 // similar to a line comment. | 382 // similar to a line comment. |
410 SkipLine(); | 383 SkipLine(); |
411 } | 384 } |
412 | 385 |
413 | |
414 void Scanner::ScanLiteralString(bool is_raw) { | 386 void Scanner::ScanLiteralString(bool is_raw) { |
415 ASSERT(!IsScanningString()); | 387 ASSERT(!IsScanningString()); |
416 ASSERT(c0_ == '"' || c0_ == '\''); | 388 ASSERT(c0_ == '"' || c0_ == '\''); |
417 | 389 |
418 // Entering string scanning mode. | 390 // Entering string scanning mode. |
419 BeginStringLiteral(c0_); | 391 BeginStringLiteral(c0_); |
420 ReadChar(); | 392 ReadChar(); |
421 | 393 |
422 if ((c0_ == string_delimiter_) && (LookaheadChar(1) == string_delimiter_)) { | 394 if ((c0_ == string_delimiter_) && (LookaheadChar(1) == string_delimiter_)) { |
423 string_is_multiline_ = true; | 395 string_is_multiline_ = true; |
424 ReadChar(); // Skip two additional string delimiters. | 396 ReadChar(); // Skip two additional string delimiters. |
425 ReadChar(); | 397 ReadChar(); |
426 } | 398 } |
427 ScanLiteralStringChars(is_raw, string_is_multiline_); | 399 ScanLiteralStringChars(is_raw, string_is_multiline_); |
428 } | 400 } |
429 | 401 |
430 | |
431 bool Scanner::ScanHexDigits(int digits, int32_t* value) { | 402 bool Scanner::ScanHexDigits(int digits, int32_t* value) { |
432 *value = 0; | 403 *value = 0; |
433 for (int i = 0; i < digits; ++i) { | 404 for (int i = 0; i < digits; ++i) { |
434 ReadChar(); | 405 ReadChar(); |
435 if (!IsHexDigit(c0_)) { | 406 if (!IsHexDigit(c0_)) { |
436 ErrorMsg("too few hexadecimal digits"); | 407 ErrorMsg("too few hexadecimal digits"); |
437 return false; | 408 return false; |
438 } | 409 } |
439 *value <<= 4; | 410 *value <<= 4; |
440 *value |= Utils::HexDigitToInt(c0_); | 411 *value |= Utils::HexDigitToInt(c0_); |
441 } | 412 } |
442 return true; | 413 return true; |
443 } | 414 } |
444 | 415 |
445 | |
446 bool Scanner::ScanHexDigits(int min_digits, int max_digits, int32_t* value) { | 416 bool Scanner::ScanHexDigits(int min_digits, int max_digits, int32_t* value) { |
447 *value = 0; | 417 *value = 0; |
448 ReadChar(); | 418 ReadChar(); |
449 for (int i = 0; i < max_digits; ++i) { | 419 for (int i = 0; i < max_digits; ++i) { |
450 if (!IsHexDigit(c0_)) { | 420 if (!IsHexDigit(c0_)) { |
451 if (i < min_digits) { | 421 if (i < min_digits) { |
452 ErrorMsg("hexadecimal digit expected"); | 422 ErrorMsg("hexadecimal digit expected"); |
453 return false; | 423 return false; |
454 } | 424 } |
455 break; | 425 break; |
456 } | 426 } |
457 *value <<= 4; | 427 *value <<= 4; |
458 *value |= Utils::HexDigitToInt(c0_); | 428 *value |= Utils::HexDigitToInt(c0_); |
459 ReadChar(); | 429 ReadChar(); |
460 } | 430 } |
461 return true; | 431 return true; |
462 } | 432 } |
463 | 433 |
464 | |
465 void Scanner::ScanEscapedCodePoint(int32_t* code_point) { | 434 void Scanner::ScanEscapedCodePoint(int32_t* code_point) { |
466 ASSERT(c0_ == 'u' || c0_ == 'x'); | 435 ASSERT(c0_ == 'u' || c0_ == 'x'); |
467 bool is_valid; | 436 bool is_valid; |
468 if (c0_ == 'x') { | 437 if (c0_ == 'x') { |
469 is_valid = ScanHexDigits(2, code_point); | 438 is_valid = ScanHexDigits(2, code_point); |
470 } else if (c0_ == 'u' && LookaheadChar(1) != '{') { | 439 } else if (c0_ == 'u' && LookaheadChar(1) != '{') { |
471 is_valid = ScanHexDigits(4, code_point); | 440 is_valid = ScanHexDigits(4, code_point); |
472 } else { | 441 } else { |
473 ReadChar(); // Skip left curly bracket. | 442 ReadChar(); // Skip left curly bracket. |
474 is_valid = ScanHexDigits(1, 6, code_point); | 443 is_valid = ScanHexDigits(1, 6, code_point); |
475 if (is_valid) { | 444 if (is_valid) { |
476 if (c0_ != '}') { | 445 if (c0_ != '}') { |
477 ErrorMsg("expected '}' after character code"); | 446 ErrorMsg("expected '}' after character code"); |
478 return; | 447 return; |
479 } | 448 } |
480 } | 449 } |
481 } | 450 } |
482 if (is_valid && (Utf::IsOutOfRange(*code_point))) { | 451 if (is_valid && (Utf::IsOutOfRange(*code_point))) { |
483 ErrorMsg("invalid code point"); | 452 ErrorMsg("invalid code point"); |
484 } | 453 } |
485 } | 454 } |
486 | 455 |
487 | |
488 void Scanner::ScanLiteralStringChars(bool is_raw, bool remove_whitespace) { | 456 void Scanner::ScanLiteralStringChars(bool is_raw, bool remove_whitespace) { |
489 GrowableArray<int32_t> string_chars(64); | 457 GrowableArray<int32_t> string_chars(64); |
490 | 458 |
491 ASSERT(IsScanningString()); | 459 ASSERT(IsScanningString()); |
492 // We are at the first character of a string literal piece. A string literal | 460 // We are at the first character of a string literal piece. A string literal |
493 // can be broken up into multiple pieces by string interpolation. | 461 // can be broken up into multiple pieces by string interpolation. |
494 while (true) { | 462 while (true) { |
495 if ((c0_ == '\0') || ((c0_ == '\n') && !string_is_multiline_)) { | 463 if ((c0_ == '\0') || ((c0_ == '\n') && !string_is_multiline_)) { |
496 ErrorMsg("unterminated string literal"); | 464 ErrorMsg("unterminated string literal"); |
497 EndStringLiteral(); | 465 EndStringLiteral(); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 } | 567 } |
600 if (whitespace_only) { | 568 if (whitespace_only) { |
601 string_chars.Clear(); // Discard characters on first line. | 569 string_chars.Clear(); // Discard characters on first line. |
602 } | 570 } |
603 remove_whitespace = false; | 571 remove_whitespace = false; |
604 } | 572 } |
605 ReadChar(); | 573 ReadChar(); |
606 } | 574 } |
607 } | 575 } |
608 | 576 |
609 | |
610 void Scanner::Scan() { | 577 void Scanner::Scan() { |
611 newline_seen_ = false; | 578 newline_seen_ = false; |
612 | 579 |
613 do { | 580 do { |
614 if (!IsScanningString()) { | 581 if (!IsScanningString()) { |
615 ConsumeWhiteSpace(); | 582 ConsumeWhiteSpace(); |
616 } | 583 } |
617 token_start_ = lookahead_pos_; | 584 token_start_ = lookahead_pos_; |
618 current_token_.offset = lookahead_pos_; | 585 current_token_.offset = lookahead_pos_; |
619 current_token_.position = c0_pos_; | 586 current_token_.position = c0_pos_; |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
873 utf8_char[len] = '\0'; | 840 utf8_char[len] = '\0'; |
874 OS::SNPrint(msg, sizeof(msg), "unexpected character: '%s' (U+%04X)\n", | 841 OS::SNPrint(msg, sizeof(msg), "unexpected character: '%s' (U+%04X)\n", |
875 utf8_char, c0_); | 842 utf8_char, c0_); |
876 ErrorMsg(msg); | 843 ErrorMsg(msg); |
877 ReadChar(); | 844 ReadChar(); |
878 } | 845 } |
879 } | 846 } |
880 } while (current_token_.kind == Token::kWHITESP); | 847 } while (current_token_.kind == Token::kWHITESP); |
881 } | 848 } |
882 | 849 |
883 | |
884 void Scanner::ScanAll(TokenCollector* collector) { | 850 void Scanner::ScanAll(TokenCollector* collector) { |
885 Reset(); | 851 Reset(); |
886 do { | 852 do { |
887 Scan(); | 853 Scan(); |
888 bool inserted_new_lines = false; | 854 bool inserted_new_lines = false; |
889 for (intptr_t diff = current_token_.position.line - prev_token_line_; | 855 for (intptr_t diff = current_token_.position.line - prev_token_line_; |
890 diff > 0; diff--) { | 856 diff > 0; diff--) { |
891 newline_token_.position.line = current_token_.position.line - diff; | 857 newline_token_.position.line = current_token_.position.line - diff; |
892 collector->AddToken(newline_token_); | 858 collector->AddToken(newline_token_); |
893 inserted_new_lines = true; | 859 inserted_new_lines = true; |
894 } | 860 } |
895 if (inserted_new_lines && | 861 if (inserted_new_lines && |
896 ((current_token_.kind == Token::kINTERPOL_VAR) || | 862 ((current_token_.kind == Token::kINTERPOL_VAR) || |
897 (current_token_.kind == Token::kINTERPOL_START))) { | 863 (current_token_.kind == Token::kINTERPOL_START))) { |
898 // NOTE: If this changes, be sure to update | 864 // NOTE: If this changes, be sure to update |
899 // Script::GenerateLineNumberArray to stay in sync. | 865 // Script::GenerateLineNumberArray to stay in sync. |
900 empty_string_token_.position.line = current_token_.position.line; | 866 empty_string_token_.position.line = current_token_.position.line; |
901 collector->AddToken(empty_string_token_); | 867 collector->AddToken(empty_string_token_); |
902 } | 868 } |
903 collector->AddToken(current_token_); | 869 collector->AddToken(current_token_); |
904 prev_token_line_ = current_token_.position.line; | 870 prev_token_line_ = current_token_.position.line; |
905 } while (current_token_.kind != Token::kEOS); | 871 } while (current_token_.kind != Token::kEOS); |
906 } | 872 } |
907 | 873 |
908 | |
909 void Scanner::ScanTo(intptr_t token_index) { | 874 void Scanner::ScanTo(intptr_t token_index) { |
910 ASSERT(token_index >= 0); | 875 ASSERT(token_index >= 0); |
911 intptr_t index = 0; | 876 intptr_t index = 0; |
912 Reset(); | 877 Reset(); |
913 do { | 878 do { |
914 Scan(); | 879 Scan(); |
915 bool inserted_new_lines = false; | 880 bool inserted_new_lines = false; |
916 for (intptr_t diff = current_token_.position.line - prev_token_line_; | 881 for (intptr_t diff = current_token_.position.line - prev_token_line_; |
917 diff > 0; diff--) { | 882 diff > 0; diff--) { |
918 // Advance the index to account for tokens added in ScanAll. | 883 // Advance the index to account for tokens added in ScanAll. |
919 index++; | 884 index++; |
920 inserted_new_lines = true; | 885 inserted_new_lines = true; |
921 } | 886 } |
922 if (inserted_new_lines && | 887 if (inserted_new_lines && |
923 ((current_token_.kind == Token::kINTERPOL_VAR) || | 888 ((current_token_.kind == Token::kINTERPOL_VAR) || |
924 (current_token_.kind == Token::kINTERPOL_START))) { | 889 (current_token_.kind == Token::kINTERPOL_START))) { |
925 // Advance the index to account for tokens added in ScanAll. | 890 // Advance the index to account for tokens added in ScanAll. |
926 index++; | 891 index++; |
927 } | 892 } |
928 index++; | 893 index++; |
929 prev_token_line_ = current_token_.position.line; | 894 prev_token_line_ = current_token_.position.line; |
930 } while ((token_index >= index) && (current_token_.kind != Token::kEOS)); | 895 } while ((token_index >= index) && (current_token_.kind != Token::kEOS)); |
931 } | 896 } |
932 | 897 |
933 | |
934 void Scanner::InitOnce() { | 898 void Scanner::InitOnce() { |
935 ASSERT(Isolate::Current() == Dart::vm_isolate()); | 899 ASSERT(Isolate::Current() == Dart::vm_isolate()); |
936 for (int i = 0; i < kNumLowercaseChars; i++) { | 900 for (int i = 0; i < kNumLowercaseChars; i++) { |
937 keywords_char_offset_[i] = Token::kNumKeywords; | 901 keywords_char_offset_[i] = Token::kNumKeywords; |
938 } | 902 } |
939 for (int i = 0; i < Token::kNumKeywords; i++) { | 903 for (int i = 0; i < Token::kNumKeywords; i++) { |
940 Token::Kind token = static_cast<Token::Kind>(Token::kFirstKeyword + i); | 904 Token::Kind token = static_cast<Token::Kind>(Token::kFirstKeyword + i); |
941 keywords_[i].kind = token; | 905 keywords_[i].kind = token; |
942 keywords_[i].keyword_chars = Token::Str(token); | 906 keywords_[i].keyword_chars = Token::Str(token); |
943 keywords_[i].keyword_len = strlen(Token::Str(token)); | 907 keywords_[i].keyword_len = strlen(Token::Str(token)); |
944 keywords_[i].keyword_symbol = &Symbols::Token(token); | 908 keywords_[i].keyword_symbol = &Symbols::Token(token); |
945 | 909 |
946 int ch = keywords_[i].keyword_chars[0] - 'a'; | 910 int ch = keywords_[i].keyword_chars[0] - 'a'; |
947 if (keywords_char_offset_[ch] == Token::kNumKeywords) { | 911 if (keywords_char_offset_[ch] == Token::kNumKeywords) { |
948 keywords_char_offset_[ch] = i; | 912 keywords_char_offset_[ch] = i; |
949 } | 913 } |
950 } | 914 } |
951 } | 915 } |
952 | 916 |
953 } // namespace dart | 917 } // namespace dart |
OLD | NEW |