| 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 |