Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 #define V8_PREPARSER_H | 29 #define V8_PREPARSER_H |
| 30 | 30 |
| 31 #include "hashmap.h" | 31 #include "hashmap.h" |
| 32 #include "token.h" | 32 #include "token.h" |
| 33 #include "scanner.h" | 33 #include "scanner.h" |
| 34 | 34 |
| 35 namespace v8 { | 35 namespace v8 { |
| 36 namespace internal { | 36 namespace internal { |
| 37 | 37 |
| 38 // Common base class shared between parser and pre-parser. | 38 // Common base class shared between parser and pre-parser. |
| 39 class ParserBase { | 39 template <typename Traits> |
| 40 class ParserBase : public Traits { | |
| 40 public: | 41 public: |
| 41 ParserBase(Scanner* scanner, uintptr_t stack_limit) | 42 ParserBase(Scanner* scanner, uintptr_t stack_limit, |
| 42 : scanner_(scanner), | 43 typename Traits::ParserType this_object) |
| 44 : Traits(this_object), | |
| 45 scanner_(scanner), | |
| 43 stack_limit_(stack_limit), | 46 stack_limit_(stack_limit), |
| 44 stack_overflow_(false), | 47 stack_overflow_(false), |
| 45 allow_lazy_(false), | 48 allow_lazy_(false), |
| 46 allow_natives_syntax_(false), | 49 allow_natives_syntax_(false), |
| 47 allow_generators_(false), | 50 allow_generators_(false), |
| 48 allow_for_of_(false) { } | 51 allow_for_of_(false) { } |
| 49 // TODO(mstarzinger): Only virtual until message reporting has been unified. | 52 |
| 50 virtual ~ParserBase() { } | 53 ~ParserBase() {} |
|
Michael Starzinger
2014/02/10 15:25:12
nit: Shouldn't be necessary to declare at all now.
marja
2014/02/10 15:32:01
Done.
| |
| 51 | 54 |
| 52 // Getters that indicate whether certain syntactical constructs are | 55 // Getters that indicate whether certain syntactical constructs are |
| 53 // allowed to be parsed by this instance of the parser. | 56 // allowed to be parsed by this instance of the parser. |
| 54 bool allow_lazy() const { return allow_lazy_; } | 57 bool allow_lazy() const { return allow_lazy_; } |
| 55 bool allow_natives_syntax() const { return allow_natives_syntax_; } | 58 bool allow_natives_syntax() const { return allow_natives_syntax_; } |
| 56 bool allow_generators() const { return allow_generators_; } | 59 bool allow_generators() const { return allow_generators_; } |
| 57 bool allow_for_of() const { return allow_for_of_; } | 60 bool allow_for_of() const { return allow_for_of_; } |
| 58 bool allow_modules() const { return scanner()->HarmonyModules(); } | 61 bool allow_modules() const { return scanner()->HarmonyModules(); } |
| 59 bool allow_harmony_scoping() const { return scanner()->HarmonyScoping(); } | 62 bool allow_harmony_scoping() const { return scanner()->HarmonyScoping(); } |
| 60 bool allow_harmony_numeric_literals() const { | 63 bool allow_harmony_numeric_literals() const { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 80 kAllowEvalOrArguments, | 83 kAllowEvalOrArguments, |
| 81 kDontAllowEvalOrArguments | 84 kDontAllowEvalOrArguments |
| 82 }; | 85 }; |
| 83 | 86 |
| 84 Scanner* scanner() const { return scanner_; } | 87 Scanner* scanner() const { return scanner_; } |
| 85 int position() { return scanner_->location().beg_pos; } | 88 int position() { return scanner_->location().beg_pos; } |
| 86 int peek_position() { return scanner_->peek_location().beg_pos; } | 89 int peek_position() { return scanner_->peek_location().beg_pos; } |
| 87 bool stack_overflow() const { return stack_overflow_; } | 90 bool stack_overflow() const { return stack_overflow_; } |
| 88 void set_stack_overflow() { stack_overflow_ = true; } | 91 void set_stack_overflow() { stack_overflow_ = true; } |
| 89 | 92 |
| 90 virtual bool is_classic_mode() = 0; | |
| 91 | |
| 92 INLINE(Token::Value peek()) { | 93 INLINE(Token::Value peek()) { |
| 93 if (stack_overflow_) return Token::ILLEGAL; | 94 if (stack_overflow_) return Token::ILLEGAL; |
| 94 return scanner()->peek(); | 95 return scanner()->peek(); |
| 95 } | 96 } |
| 96 | 97 |
| 97 INLINE(Token::Value Next()) { | 98 INLINE(Token::Value Next()) { |
| 98 if (stack_overflow_) return Token::ILLEGAL; | 99 if (stack_overflow_) return Token::ILLEGAL; |
| 99 { | 100 { |
| 100 int marker; | 101 int marker; |
| 101 if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) { | 102 if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 125 } | 126 } |
| 126 | 127 |
| 127 void Expect(Token::Value token, bool* ok) { | 128 void Expect(Token::Value token, bool* ok) { |
| 128 Token::Value next = Next(); | 129 Token::Value next = Next(); |
| 129 if (next != token) { | 130 if (next != token) { |
| 130 ReportUnexpectedToken(next); | 131 ReportUnexpectedToken(next); |
| 131 *ok = false; | 132 *ok = false; |
| 132 } | 133 } |
| 133 } | 134 } |
| 134 | 135 |
| 135 bool peek_any_identifier(); | 136 void ExpectSemicolon(bool* ok) { |
| 136 void ExpectSemicolon(bool* ok); | 137 // Check for automatic semicolon insertion according to |
| 137 bool CheckContextualKeyword(Vector<const char> keyword); | 138 // the rules given in ECMA-262, section 7.9, page 21. |
| 138 void ExpectContextualKeyword(Vector<const char> keyword, bool* ok); | 139 Token::Value tok = peek(); |
| 140 if (tok == Token::SEMICOLON) { | |
| 141 Next(); | |
| 142 return; | |
| 143 } | |
| 144 if (scanner()->HasAnyLineTerminatorBeforeNext() || | |
| 145 tok == Token::RBRACE || | |
| 146 tok == Token::EOS) { | |
| 147 return; | |
| 148 } | |
| 149 Expect(Token::SEMICOLON, ok); | |
| 150 } | |
| 139 | 151 |
| 140 // Strict mode octal literal validation. | 152 bool peek_any_identifier() { |
| 141 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok); | 153 Token::Value next = peek(); |
| 154 return next == Token::IDENTIFIER || | |
| 155 next == Token::FUTURE_RESERVED_WORD || | |
| 156 next == Token::FUTURE_STRICT_RESERVED_WORD || | |
| 157 next == Token::YIELD; | |
| 158 } | |
| 159 | |
| 160 bool CheckContextualKeyword(Vector<const char> keyword) { | |
| 161 if (peek() == Token::IDENTIFIER && | |
| 162 scanner()->is_next_contextual_keyword(keyword)) { | |
| 163 Consume(Token::IDENTIFIER); | |
| 164 return true; | |
| 165 } | |
| 166 return false; | |
| 167 } | |
| 168 | |
| 169 void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) { | |
| 170 Expect(Token::IDENTIFIER, ok); | |
| 171 if (!*ok) return; | |
| 172 if (!scanner()->is_literal_contextual_keyword(keyword)) { | |
| 173 ReportUnexpectedToken(scanner()->current_token()); | |
| 174 *ok = false; | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 // Checks whether an octal literal was last seen between beg_pos and end_pos. | |
| 179 // If so, reports an error. Only called for strict mode. | |
| 180 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { | |
| 181 Scanner::Location octal = scanner()->octal_position(); | |
| 182 if (octal.IsValid() && beg_pos <= octal.beg_pos && | |
| 183 octal.end_pos <= end_pos) { | |
| 184 ReportMessageAt(octal, "strict_octal_literal"); | |
| 185 scanner()->clear_octal_position(); | |
| 186 *ok = false; | |
| 187 } | |
| 188 } | |
| 142 | 189 |
| 143 // Determine precedence of given token. | 190 // Determine precedence of given token. |
| 144 static int Precedence(Token::Value token, bool accept_IN); | 191 static int Precedence(Token::Value token, bool accept_IN) { |
| 192 if (token == Token::IN && !accept_IN) | |
| 193 return 0; // 0 precedence will terminate binary expression parsing | |
| 194 return Token::Precedence(token); | |
| 195 } | |
| 145 | 196 |
| 146 // Report syntax errors. | 197 // Report syntax errors. |
| 198 void ReportMessage(const char* message, Vector<const char*> args) { | |
| 199 Scanner::Location source_location = scanner()->location(); | |
| 200 Traits::ReportMessageAt(source_location, message, args); | |
| 201 } | |
| 202 | |
| 203 void ReportMessageAt(Scanner::Location location, const char* message) { | |
| 204 Traits::ReportMessageAt(location, message, Vector<const char*>::empty()); | |
| 205 } | |
| 206 | |
| 147 void ReportUnexpectedToken(Token::Value token); | 207 void ReportUnexpectedToken(Token::Value token); |
| 148 void ReportMessageAt(Scanner::Location location, const char* type) { | 208 |
| 149 ReportMessageAt(location, type, Vector<const char*>::empty()); | 209 // Recursive descent functions: |
| 150 } | 210 |
| 151 virtual void ReportMessageAt(Scanner::Location source_location, | 211 // Parses an identifier that is valid for the current scope, in particular it |
| 152 const char* message, | 212 // fails on strict mode future reserved keywords in a strict scope. If |
| 153 Vector<const char*> args) = 0; | 213 // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or |
| 214 // "arguments" as identifier even in strict mode (this is needed in cases like | |
| 215 // "var foo = eval;"). | |
| 216 typename Traits::IdentifierType ParseIdentifier( | |
|
Michael Starzinger
2014/02/10 15:25:12
Puzzler of the day: Can a typename nested within a
marja
2014/02/10 15:32:01
Nope :)
| |
| 217 AllowEvalOrArgumentsAsIdentifier, | |
| 218 bool* ok); | |
| 219 // Parses an identifier or a strict mode future reserved word, and indicate | |
| 220 // whether it is strict mode future reserved. | |
| 221 typename Traits::IdentifierType ParseIdentifierOrStrictReservedWord( | |
| 222 bool* is_strict_reserved, | |
| 223 bool* ok); | |
| 224 typename Traits::IdentifierType ParseIdentifierName(bool* ok); | |
| 225 // Parses an identifier and determines whether or not it is 'get' or 'set'. | |
| 226 typename Traits::IdentifierType ParseIdentifierNameOrGetOrSet(bool* is_get, | |
| 227 bool* is_set, | |
| 228 bool* ok); | |
| 154 | 229 |
| 155 // Used to detect duplicates in object literals. Each of the values | 230 // Used to detect duplicates in object literals. Each of the values |
| 156 // kGetterProperty, kSetterProperty and kValueProperty represents | 231 // kGetterProperty, kSetterProperty and kValueProperty represents |
| 157 // a type of object literal property. When parsing a property, its | 232 // a type of object literal property. When parsing a property, its |
| 158 // type value is stored in the DuplicateFinder for the property name. | 233 // type value is stored in the DuplicateFinder for the property name. |
| 159 // Values are chosen so that having intersection bits means the there is | 234 // Values are chosen so that having intersection bits means the there is |
| 160 // an incompatibility. | 235 // an incompatibility. |
| 161 // I.e., you can add a getter to a property that already has a setter, since | 236 // I.e., you can add a getter to a property that already has a setter, since |
| 162 // kGetterProperty and kSetterProperty doesn't intersect, but not if it | 237 // kGetterProperty and kSetterProperty doesn't intersect, but not if it |
| 163 // already has a getter or a value. Adding the getter to an existing | 238 // already has a getter or a value. Adding the getter to an existing |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 222 // a later parsing to be faster. | 297 // a later parsing to be faster. |
| 223 // See preparse-data-format.h for the data format. | 298 // See preparse-data-format.h for the data format. |
| 224 | 299 |
| 225 // The PreParser checks that the syntax follows the grammar for JavaScript, | 300 // The PreParser checks that the syntax follows the grammar for JavaScript, |
| 226 // and collects some information about the program along the way. | 301 // and collects some information about the program along the way. |
| 227 // The grammar check is only performed in order to understand the program | 302 // The grammar check is only performed in order to understand the program |
| 228 // sufficiently to deduce some information about it, that can be used | 303 // sufficiently to deduce some information about it, that can be used |
| 229 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 304 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
| 230 // rather it is to speed up properly written and correct programs. | 305 // rather it is to speed up properly written and correct programs. |
| 231 // That means that contextual checks (like a label being declared where | 306 // That means that contextual checks (like a label being declared where |
| 232 // it is used) are generally omitted. | 307 // it is used) are generally omitted. |
|
Michael Starzinger
2014/02/10 15:25:12
This whole block of comments mainly applies to the
marja
2014/02/10 15:32:01
Done.
| |
| 233 class PreParser : public ParserBase { | 308 |
| 309 class PreParserIdentifier { | |
| 234 public: | 310 public: |
| 311 static PreParserIdentifier Default() { | |
| 312 return PreParserIdentifier(kUnknownIdentifier); | |
| 313 } | |
| 314 static PreParserIdentifier Eval() { | |
| 315 return PreParserIdentifier(kEvalIdentifier); | |
| 316 } | |
| 317 static PreParserIdentifier Arguments() { | |
| 318 return PreParserIdentifier(kArgumentsIdentifier); | |
| 319 } | |
| 320 static PreParserIdentifier FutureReserved() { | |
| 321 return PreParserIdentifier(kFutureReservedIdentifier); | |
| 322 } | |
| 323 static PreParserIdentifier FutureStrictReserved() { | |
| 324 return PreParserIdentifier(kFutureStrictReservedIdentifier); | |
| 325 } | |
| 326 static PreParserIdentifier Yield() { | |
| 327 return PreParserIdentifier(kYieldIdentifier); | |
| 328 } | |
| 329 bool IsEval() { return type_ == kEvalIdentifier; } | |
| 330 bool IsArguments() { return type_ == kArgumentsIdentifier; } | |
| 331 bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } | |
| 332 bool IsYield() { return type_ == kYieldIdentifier; } | |
| 333 bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } | |
| 334 bool IsFutureStrictReserved() { | |
| 335 return type_ == kFutureStrictReservedIdentifier; | |
| 336 } | |
| 337 bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; } | |
| 338 | |
| 339 private: | |
| 340 enum Type { | |
| 341 kUnknownIdentifier, | |
| 342 kFutureReservedIdentifier, | |
| 343 kFutureStrictReservedIdentifier, | |
| 344 kYieldIdentifier, | |
| 345 kEvalIdentifier, | |
| 346 kArgumentsIdentifier | |
| 347 }; | |
| 348 explicit PreParserIdentifier(Type type) : type_(type) {} | |
| 349 Type type_; | |
| 350 | |
| 351 friend class PreParserExpression; | |
| 352 }; | |
| 353 | |
| 354 | |
| 355 // Bits 0 and 1 are used to identify the type of expression: | |
| 356 // If bit 0 is set, it's an identifier. | |
| 357 // if bit 1 is set, it's a string literal. | |
| 358 // If neither is set, it's no particular type, and both set isn't | |
| 359 // use yet. | |
| 360 class PreParserExpression { | |
| 361 public: | |
| 362 static PreParserExpression Default() { | |
| 363 return PreParserExpression(kUnknownExpression); | |
| 364 } | |
| 365 | |
| 366 static PreParserExpression FromIdentifier(PreParserIdentifier id) { | |
| 367 return PreParserExpression(kIdentifierFlag | | |
| 368 (id.type_ << kIdentifierShift)); | |
| 369 } | |
| 370 | |
| 371 static PreParserExpression StringLiteral() { | |
| 372 return PreParserExpression(kUnknownStringLiteral); | |
| 373 } | |
| 374 | |
| 375 static PreParserExpression UseStrictStringLiteral() { | |
| 376 return PreParserExpression(kUseStrictString); | |
| 377 } | |
| 378 | |
| 379 static PreParserExpression This() { | |
| 380 return PreParserExpression(kThisExpression); | |
| 381 } | |
| 382 | |
| 383 static PreParserExpression ThisProperty() { | |
| 384 return PreParserExpression(kThisPropertyExpression); | |
| 385 } | |
| 386 | |
| 387 static PreParserExpression StrictFunction() { | |
| 388 return PreParserExpression(kStrictFunctionExpression); | |
| 389 } | |
| 390 | |
| 391 bool IsIdentifier() { return (code_ & kIdentifierFlag) != 0; } | |
| 392 | |
| 393 // Only works corretly if it is actually an identifier expression. | |
| 394 PreParserIdentifier AsIdentifier() { | |
| 395 return PreParserIdentifier( | |
| 396 static_cast<PreParserIdentifier::Type>(code_ >> kIdentifierShift)); | |
| 397 } | |
| 398 | |
| 399 bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; } | |
| 400 | |
| 401 bool IsUseStrictLiteral() { | |
| 402 return (code_ & kStringLiteralMask) == kUseStrictString; | |
| 403 } | |
| 404 | |
| 405 bool IsThis() { return code_ == kThisExpression; } | |
| 406 | |
| 407 bool IsThisProperty() { return code_ == kThisPropertyExpression; } | |
| 408 | |
| 409 bool IsStrictFunction() { return code_ == kStrictFunctionExpression; } | |
| 410 | |
| 411 private: | |
| 412 // First two/three bits are used as flags. | |
| 413 // Bit 0 and 1 represent identifiers or strings literals, and are | |
| 414 // mutually exclusive, but can both be absent. | |
| 415 enum { | |
| 416 kUnknownExpression = 0, | |
| 417 // Identifiers | |
| 418 kIdentifierFlag = 1, // Used to detect labels. | |
| 419 kIdentifierShift = 3, | |
| 420 | |
| 421 kStringLiteralFlag = 2, // Used to detect directive prologue. | |
| 422 kUnknownStringLiteral = kStringLiteralFlag, | |
| 423 kUseStrictString = kStringLiteralFlag | 8, | |
| 424 kStringLiteralMask = kUseStrictString, | |
| 425 | |
| 426 // Below here applies if neither identifier nor string literal. | |
| 427 kThisExpression = 4, | |
| 428 kThisPropertyExpression = 8, | |
| 429 kStrictFunctionExpression = 12 | |
| 430 }; | |
| 431 | |
| 432 explicit PreParserExpression(int expression_code) : code_(expression_code) {} | |
| 433 | |
| 434 int code_; | |
| 435 }; | |
| 436 | |
| 437 class PreParser; | |
| 438 | |
| 439 | |
| 440 class PreParserTraits { | |
| 441 public: | |
| 442 typedef PreParser* ParserType; | |
| 443 // Return types for traversing functions. | |
| 444 typedef PreParserIdentifier IdentifierType; | |
| 445 | |
| 446 explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {} | |
| 447 | |
| 448 // Helper functions for recursive descent. | |
| 449 bool is_classic_mode() const; | |
| 450 bool is_generator() const; | |
| 451 static bool IsEvalOrArguments(IdentifierType identifier) { | |
| 452 return identifier.IsEvalOrArguments(); | |
| 453 } | |
| 454 | |
| 455 // Reporting errors. | |
| 456 void ReportMessageAt(Scanner::Location location, | |
| 457 const char* message, | |
| 458 Vector<const char*> args); | |
| 459 void ReportMessageAt(Scanner::Location location, | |
| 460 const char* type, | |
| 461 const char* name_opt); | |
| 462 void ReportMessageAt(int start_pos, | |
| 463 int end_pos, | |
| 464 const char* type, | |
| 465 const char* name_opt); | |
| 466 | |
| 467 // Identifiers: | |
| 468 static IdentifierType EmptyIdentifier() { | |
| 469 return PreParserIdentifier::Default(); | |
| 470 } | |
| 471 | |
| 472 IdentifierType GetSymbol(); | |
| 473 | |
| 474 private: | |
| 475 PreParser* pre_parser_; | |
| 476 }; | |
| 477 | |
| 478 | |
| 479 class PreParser : public ParserBase<PreParserTraits> { | |
| 480 public: | |
| 481 typedef PreParserIdentifier Identifier; | |
| 482 typedef PreParserExpression Expression; | |
| 483 | |
| 235 enum PreParseResult { | 484 enum PreParseResult { |
| 236 kPreParseStackOverflow, | 485 kPreParseStackOverflow, |
| 237 kPreParseSuccess | 486 kPreParseSuccess |
| 238 }; | 487 }; |
| 239 | 488 |
| 240 PreParser(Scanner* scanner, | 489 PreParser(Scanner* scanner, |
| 241 ParserRecorder* log, | 490 ParserRecorder* log, |
| 242 uintptr_t stack_limit) | 491 uintptr_t stack_limit) |
| 243 : ParserBase(scanner, stack_limit), | 492 : ParserBase(scanner, stack_limit, this), |
| 244 log_(log), | 493 log_(log), |
| 245 scope_(NULL), | 494 scope_(NULL), |
| 246 parenthesized_function_(false) { } | 495 parenthesized_function_(false) { } |
| 247 | 496 |
| 248 ~PreParser() {} | 497 ~PreParser() {} |
| 249 | 498 |
| 250 // Pre-parse the program from the character stream; returns true on | 499 // Pre-parse the program from the character stream; returns true on |
| 251 // success (even if parsing failed, the pre-parse data successfully | 500 // success (even if parsing failed, the pre-parse data successfully |
| 252 // captured the syntax error), and false if a stack-overflow happened | 501 // captured the syntax error), and false if a stack-overflow happened |
| 253 // during parsing. | 502 // during parsing. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 271 // detail that it can be lazily compiled. | 520 // detail that it can be lazily compiled. |
| 272 // The scanner is expected to have matched the "function" or "function*" | 521 // The scanner is expected to have matched the "function" or "function*" |
| 273 // keyword and parameters, and have consumed the initial '{'. | 522 // keyword and parameters, and have consumed the initial '{'. |
| 274 // At return, unless an error occurred, the scanner is positioned before the | 523 // At return, unless an error occurred, the scanner is positioned before the |
| 275 // the final '}'. | 524 // the final '}'. |
| 276 PreParseResult PreParseLazyFunction(LanguageMode mode, | 525 PreParseResult PreParseLazyFunction(LanguageMode mode, |
| 277 bool is_generator, | 526 bool is_generator, |
| 278 ParserRecorder* log); | 527 ParserRecorder* log); |
| 279 | 528 |
| 280 private: | 529 private: |
| 530 friend class PreParserTraits; | |
| 531 | |
| 281 // These types form an algebra over syntactic categories that is just | 532 // These types form an algebra over syntactic categories that is just |
| 282 // rich enough to let us recognize and propagate the constructs that | 533 // rich enough to let us recognize and propagate the constructs that |
| 283 // are either being counted in the preparser data, or is important | 534 // are either being counted in the preparser data, or is important |
| 284 // to throw the correct syntax error exceptions. | 535 // to throw the correct syntax error exceptions. |
| 285 | 536 |
| 286 enum ScopeType { | 537 enum ScopeType { |
| 287 kTopLevelScope, | 538 kTopLevelScope, |
| 288 kFunctionScope | 539 kFunctionScope |
| 289 }; | 540 }; |
| 290 | 541 |
| 291 enum VariableDeclarationContext { | 542 enum VariableDeclarationContext { |
| 292 kSourceElement, | 543 kSourceElement, |
| 293 kStatement, | 544 kStatement, |
| 294 kForStatement | 545 kForStatement |
| 295 }; | 546 }; |
| 296 | 547 |
| 297 // If a list of variable declarations includes any initializers. | 548 // If a list of variable declarations includes any initializers. |
| 298 enum VariableDeclarationProperties { | 549 enum VariableDeclarationProperties { |
| 299 kHasInitializers, | 550 kHasInitializers, |
| 300 kHasNoInitializers | 551 kHasNoInitializers |
| 301 }; | 552 }; |
| 302 | 553 |
| 303 class Expression; | |
| 304 | |
| 305 class Identifier { | |
| 306 public: | |
| 307 static Identifier Default() { | |
| 308 return Identifier(kUnknownIdentifier); | |
| 309 } | |
| 310 static Identifier Eval() { | |
| 311 return Identifier(kEvalIdentifier); | |
| 312 } | |
| 313 static Identifier Arguments() { | |
| 314 return Identifier(kArgumentsIdentifier); | |
| 315 } | |
| 316 static Identifier FutureReserved() { | |
| 317 return Identifier(kFutureReservedIdentifier); | |
| 318 } | |
| 319 static Identifier FutureStrictReserved() { | |
| 320 return Identifier(kFutureStrictReservedIdentifier); | |
| 321 } | |
| 322 static Identifier Yield() { | |
| 323 return Identifier(kYieldIdentifier); | |
| 324 } | |
| 325 bool IsEval() { return type_ == kEvalIdentifier; } | |
| 326 bool IsArguments() { return type_ == kArgumentsIdentifier; } | |
| 327 bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } | |
| 328 bool IsYield() { return type_ == kYieldIdentifier; } | |
| 329 bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } | |
| 330 bool IsFutureStrictReserved() { | |
| 331 return type_ == kFutureStrictReservedIdentifier; | |
| 332 } | |
| 333 bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; } | |
| 334 | |
| 335 private: | |
| 336 enum Type { | |
| 337 kUnknownIdentifier, | |
| 338 kFutureReservedIdentifier, | |
| 339 kFutureStrictReservedIdentifier, | |
| 340 kYieldIdentifier, | |
| 341 kEvalIdentifier, | |
| 342 kArgumentsIdentifier | |
| 343 }; | |
| 344 explicit Identifier(Type type) : type_(type) { } | |
| 345 Type type_; | |
| 346 | |
| 347 friend class Expression; | |
| 348 }; | |
| 349 | |
| 350 // Bits 0 and 1 are used to identify the type of expression: | |
| 351 // If bit 0 is set, it's an identifier. | |
| 352 // if bit 1 is set, it's a string literal. | |
| 353 // If neither is set, it's no particular type, and both set isn't | |
| 354 // use yet. | |
| 355 class Expression { | |
| 356 public: | |
| 357 static Expression Default() { | |
| 358 return Expression(kUnknownExpression); | |
| 359 } | |
| 360 | |
| 361 static Expression FromIdentifier(Identifier id) { | |
| 362 return Expression(kIdentifierFlag | (id.type_ << kIdentifierShift)); | |
| 363 } | |
| 364 | |
| 365 static Expression StringLiteral() { | |
| 366 return Expression(kUnknownStringLiteral); | |
| 367 } | |
| 368 | |
| 369 static Expression UseStrictStringLiteral() { | |
| 370 return Expression(kUseStrictString); | |
| 371 } | |
| 372 | |
| 373 static Expression This() { | |
| 374 return Expression(kThisExpression); | |
| 375 } | |
| 376 | |
| 377 static Expression ThisProperty() { | |
| 378 return Expression(kThisPropertyExpression); | |
| 379 } | |
| 380 | |
| 381 static Expression StrictFunction() { | |
| 382 return Expression(kStrictFunctionExpression); | |
| 383 } | |
| 384 | |
| 385 bool IsIdentifier() { | |
| 386 return (code_ & kIdentifierFlag) != 0; | |
| 387 } | |
| 388 | |
| 389 // Only works corretly if it is actually an identifier expression. | |
| 390 PreParser::Identifier AsIdentifier() { | |
| 391 return PreParser::Identifier( | |
| 392 static_cast<PreParser::Identifier::Type>(code_ >> kIdentifierShift)); | |
| 393 } | |
| 394 | |
| 395 bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; } | |
| 396 | |
| 397 bool IsUseStrictLiteral() { | |
| 398 return (code_ & kStringLiteralMask) == kUseStrictString; | |
| 399 } | |
| 400 | |
| 401 bool IsThis() { | |
| 402 return code_ == kThisExpression; | |
| 403 } | |
| 404 | |
| 405 bool IsThisProperty() { | |
| 406 return code_ == kThisPropertyExpression; | |
| 407 } | |
| 408 | |
| 409 bool IsStrictFunction() { | |
| 410 return code_ == kStrictFunctionExpression; | |
| 411 } | |
| 412 | |
| 413 private: | |
| 414 // First two/three bits are used as flags. | |
| 415 // Bit 0 and 1 represent identifiers or strings literals, and are | |
| 416 // mutually exclusive, but can both be absent. | |
| 417 enum { | |
| 418 kUnknownExpression = 0, | |
| 419 // Identifiers | |
| 420 kIdentifierFlag = 1, // Used to detect labels. | |
| 421 kIdentifierShift = 3, | |
| 422 | |
| 423 kStringLiteralFlag = 2, // Used to detect directive prologue. | |
| 424 kUnknownStringLiteral = kStringLiteralFlag, | |
| 425 kUseStrictString = kStringLiteralFlag | 8, | |
| 426 kStringLiteralMask = kUseStrictString, | |
| 427 | |
| 428 // Below here applies if neither identifier nor string literal. | |
| 429 kThisExpression = 4, | |
| 430 kThisPropertyExpression = 8, | |
| 431 kStrictFunctionExpression = 12 | |
| 432 }; | |
| 433 | |
| 434 explicit Expression(int expression_code) : code_(expression_code) { } | |
| 435 | |
| 436 int code_; | |
| 437 }; | |
| 438 | |
| 439 class Statement { | 554 class Statement { |
| 440 public: | 555 public: |
| 441 static Statement Default() { | 556 static Statement Default() { |
| 442 return Statement(kUnknownStatement); | 557 return Statement(kUnknownStatement); |
| 443 } | 558 } |
| 444 | 559 |
| 445 static Statement FunctionDeclaration() { | 560 static Statement FunctionDeclaration() { |
| 446 return Statement(kFunctionDeclaration); | 561 return Statement(kFunctionDeclaration); |
| 447 } | 562 } |
| 448 | 563 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 539 Scope** const variable_; | 654 Scope** const variable_; |
| 540 Scope* const prev_; | 655 Scope* const prev_; |
| 541 const ScopeType type_; | 656 const ScopeType type_; |
| 542 int materialized_literal_count_; | 657 int materialized_literal_count_; |
| 543 int expected_properties_; | 658 int expected_properties_; |
| 544 int with_nesting_count_; | 659 int with_nesting_count_; |
| 545 LanguageMode language_mode_; | 660 LanguageMode language_mode_; |
| 546 bool is_generator_; | 661 bool is_generator_; |
| 547 }; | 662 }; |
| 548 | 663 |
| 549 // Report syntax error | |
| 550 void ReportMessageAt(Scanner::Location location, | |
| 551 const char* message, | |
| 552 Vector<const char*> args) { | |
| 553 ReportMessageAt(location.beg_pos, | |
| 554 location.end_pos, | |
| 555 message, | |
| 556 args.length() > 0 ? args[0] : NULL); | |
| 557 } | |
| 558 void ReportMessageAt(Scanner::Location location, | |
| 559 const char* type, | |
| 560 const char* name_opt) { | |
| 561 log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt); | |
| 562 } | |
| 563 void ReportMessageAt(int start_pos, | |
| 564 int end_pos, | |
| 565 const char* type, | |
| 566 const char* name_opt) { | |
| 567 log_->LogMessage(start_pos, end_pos, type, name_opt); | |
| 568 } | |
| 569 | |
| 570 // All ParseXXX functions take as the last argument an *ok parameter | 664 // All ParseXXX functions take as the last argument an *ok parameter |
| 571 // which is set to false if parsing failed; it is unchanged otherwise. | 665 // which is set to false if parsing failed; it is unchanged otherwise. |
| 572 // By making the 'exception handling' explicit, we are forced to check | 666 // By making the 'exception handling' explicit, we are forced to check |
| 573 // for failure at the call sites. | 667 // for failure at the call sites. |
| 574 Statement ParseSourceElement(bool* ok); | 668 Statement ParseSourceElement(bool* ok); |
| 575 SourceElements ParseSourceElements(int end_token, bool* ok); | 669 SourceElements ParseSourceElements(int end_token, bool* ok); |
| 576 Statement ParseStatement(bool* ok); | 670 Statement ParseStatement(bool* ok); |
| 577 Statement ParseFunctionDeclaration(bool* ok); | 671 Statement ParseFunctionDeclaration(bool* ok); |
| 578 Statement ParseBlock(bool* ok); | 672 Statement ParseBlock(bool* ok); |
| 579 Statement ParseVariableStatement(VariableDeclarationContext var_context, | 673 Statement ParseVariableStatement(VariableDeclarationContext var_context, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 615 | 709 |
| 616 Arguments ParseArguments(bool* ok); | 710 Arguments ParseArguments(bool* ok); |
| 617 Expression ParseFunctionLiteral( | 711 Expression ParseFunctionLiteral( |
| 618 Identifier name, | 712 Identifier name, |
| 619 Scanner::Location function_name_location, | 713 Scanner::Location function_name_location, |
| 620 bool name_is_strict_reserved, | 714 bool name_is_strict_reserved, |
| 621 bool is_generator, | 715 bool is_generator, |
| 622 bool* ok); | 716 bool* ok); |
| 623 void ParseLazyFunctionLiteralBody(bool* ok); | 717 void ParseLazyFunctionLiteralBody(bool* ok); |
| 624 | 718 |
| 625 Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok); | |
| 626 Identifier ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, | |
| 627 bool* ok); | |
| 628 Identifier ParseIdentifierName(bool* ok); | |
| 629 Identifier ParseIdentifierNameOrGetOrSet(bool* is_get, | |
| 630 bool* is_set, | |
| 631 bool* ok); | |
| 632 | |
| 633 // Logs the currently parsed literal as a symbol in the preparser data. | 719 // Logs the currently parsed literal as a symbol in the preparser data. |
| 634 void LogSymbol(); | 720 void LogSymbol(); |
| 635 // Log the currently parsed identifier. | |
| 636 Identifier GetIdentifierSymbol(); | |
| 637 // Log the currently parsed string literal. | 721 // Log the currently parsed string literal. |
| 638 Expression GetStringSymbol(); | 722 Expression GetStringSymbol(); |
| 639 | 723 |
| 640 void set_language_mode(LanguageMode language_mode) { | 724 void set_language_mode(LanguageMode language_mode) { |
| 641 scope_->set_language_mode(language_mode); | 725 scope_->set_language_mode(language_mode); |
| 642 } | 726 } |
| 643 | 727 |
| 644 virtual bool is_classic_mode() { | |
| 645 return scope_->language_mode() == CLASSIC_MODE; | |
| 646 } | |
| 647 | |
| 648 bool is_extended_mode() { | 728 bool is_extended_mode() { |
| 649 return scope_->language_mode() == EXTENDED_MODE; | 729 return scope_->language_mode() == EXTENDED_MODE; |
| 650 } | 730 } |
| 651 | 731 |
| 652 LanguageMode language_mode() { return scope_->language_mode(); } | 732 LanguageMode language_mode() { return scope_->language_mode(); } |
| 653 | 733 |
| 654 bool CheckInOrOf(bool accept_OF); | 734 bool CheckInOrOf(bool accept_OF); |
| 655 | 735 |
| 656 ParserRecorder* log_; | 736 ParserRecorder* log_; |
| 657 Scope* scope_; | 737 Scope* scope_; |
| 658 bool parenthesized_function_; | 738 bool parenthesized_function_; |
| 659 }; | 739 }; |
| 660 | 740 |
| 741 | |
| 742 template<class Traits> | |
| 743 void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) { | |
| 744 // We don't report stack overflows here, to avoid increasing the | |
| 745 // stack depth even further. Instead we report it after parsing is | |
| 746 // over, in ParseProgram. | |
| 747 if (token == Token::ILLEGAL && stack_overflow()) { | |
| 748 return; | |
| 749 } | |
| 750 Scanner::Location source_location = scanner()->location(); | |
| 751 | |
| 752 // Four of the tokens are treated specially | |
| 753 switch (token) { | |
| 754 case Token::EOS: | |
| 755 return ReportMessageAt(source_location, "unexpected_eos"); | |
| 756 case Token::NUMBER: | |
| 757 return ReportMessageAt(source_location, "unexpected_token_number"); | |
| 758 case Token::STRING: | |
| 759 return ReportMessageAt(source_location, "unexpected_token_string"); | |
| 760 case Token::IDENTIFIER: | |
| 761 return ReportMessageAt(source_location, "unexpected_token_identifier"); | |
| 762 case Token::FUTURE_RESERVED_WORD: | |
| 763 return ReportMessageAt(source_location, "unexpected_reserved"); | |
| 764 case Token::YIELD: | |
| 765 case Token::FUTURE_STRICT_RESERVED_WORD: | |
| 766 return ReportMessageAt( | |
| 767 source_location, | |
| 768 this->is_classic_mode() ? "unexpected_token_identifier" | |
| 769 : "unexpected_strict_reserved"); | |
| 770 default: | |
| 771 const char* name = Token::String(token); | |
| 772 ASSERT(name != NULL); | |
| 773 Traits::ReportMessageAt( | |
| 774 source_location, "unexpected_token", Vector<const char*>(&name, 1)); | |
| 775 } | |
| 776 } | |
| 777 | |
| 778 | |
| 779 template<class Traits> | |
| 780 typename Traits::IdentifierType ParserBase<Traits>::ParseIdentifier( | |
| 781 AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments, | |
| 782 bool* ok) { | |
| 783 Token::Value next = Next(); | |
| 784 if (next == Token::IDENTIFIER) { | |
| 785 typename Traits::IdentifierType name = this->GetSymbol(); | |
| 786 if (allow_eval_or_arguments == kDontAllowEvalOrArguments && | |
| 787 !this->is_classic_mode() && this->IsEvalOrArguments(name)) { | |
| 788 ReportMessageAt(scanner()->location(), "strict_eval_arguments"); | |
| 789 *ok = false; | |
| 790 } | |
| 791 return name; | |
| 792 } else if (this->is_classic_mode() && | |
| 793 (next == Token::FUTURE_STRICT_RESERVED_WORD || | |
| 794 (next == Token::YIELD && !this->is_generator()))) { | |
| 795 return this->GetSymbol(); | |
| 796 } else { | |
| 797 this->ReportUnexpectedToken(next); | |
| 798 *ok = false; | |
| 799 return Traits::EmptyIdentifier(); | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 | |
| 804 template <class Traits> | |
| 805 typename Traits::IdentifierType ParserBase< | |
| 806 Traits>::ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved, | |
| 807 bool* ok) { | |
| 808 Token::Value next = Next(); | |
| 809 if (next == Token::IDENTIFIER) { | |
| 810 *is_strict_reserved = false; | |
| 811 } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || | |
| 812 (next == Token::YIELD && !this->is_generator())) { | |
| 813 *is_strict_reserved = true; | |
| 814 } else { | |
| 815 ReportUnexpectedToken(next); | |
| 816 *ok = false; | |
| 817 return Traits::EmptyIdentifier(); | |
| 818 } | |
| 819 return this->GetSymbol(); | |
| 820 } | |
| 821 | |
| 822 | |
| 823 template <class Traits> | |
| 824 typename Traits::IdentifierType ParserBase<Traits>::ParseIdentifierName( | |
| 825 bool* ok) { | |
| 826 Token::Value next = Next(); | |
| 827 if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD && | |
| 828 next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) { | |
| 829 this->ReportUnexpectedToken(next); | |
| 830 *ok = false; | |
| 831 return Traits::EmptyIdentifier(); | |
| 832 } | |
| 833 return this->GetSymbol(); | |
| 834 } | |
| 835 | |
| 836 | |
| 837 template <class Traits> | |
| 838 typename Traits::IdentifierType | |
| 839 ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get, | |
| 840 bool* is_set, | |
| 841 bool* ok) { | |
| 842 typename Traits::IdentifierType result = ParseIdentifierName(ok); | |
| 843 if (!*ok) return Traits::EmptyIdentifier(); | |
| 844 if (scanner()->is_literal_ascii() && | |
| 845 scanner()->literal_length() == 3) { | |
| 846 const char* token = scanner()->literal_ascii_string().start(); | |
| 847 *is_get = strncmp(token, "get", 3) == 0; | |
| 848 *is_set = !*is_get && strncmp(token, "set", 3) == 0; | |
| 849 } | |
| 850 return result; | |
| 851 } | |
| 852 | |
| 853 | |
| 854 template <typename Traits> | |
| 855 void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty( | |
| 856 Token::Value property, | |
| 857 PropertyKind type, | |
| 858 bool* ok) { | |
| 859 int old; | |
| 860 if (property == Token::NUMBER) { | |
| 861 old = finder_.AddNumber(scanner()->literal_ascii_string(), type); | |
| 862 } else if (scanner()->is_literal_ascii()) { | |
| 863 old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type); | |
| 864 } else { | |
| 865 old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type); | |
| 866 } | |
| 867 PropertyKind old_type = static_cast<PropertyKind>(old); | |
| 868 if (HasConflict(old_type, type)) { | |
| 869 if (IsDataDataConflict(old_type, type)) { | |
| 870 // Both are data properties. | |
| 871 if (language_mode_ == CLASSIC_MODE) return; | |
| 872 parser()->ReportMessageAt(scanner()->location(), | |
| 873 "strict_duplicate_property"); | |
| 874 } else if (IsDataAccessorConflict(old_type, type)) { | |
| 875 // Both a data and an accessor property with the same name. | |
| 876 parser()->ReportMessageAt(scanner()->location(), | |
| 877 "accessor_data_property"); | |
| 878 } else { | |
| 879 ASSERT(IsAccessorAccessorConflict(old_type, type)); | |
| 880 // Both accessors of the same type. | |
| 881 parser()->ReportMessageAt(scanner()->location(), | |
| 882 "accessor_get_set"); | |
| 883 } | |
| 884 *ok = false; | |
| 885 } | |
| 886 } | |
| 887 | |
| 888 | |
| 661 } } // v8::internal | 889 } } // v8::internal |
| 662 | 890 |
| 663 #endif // V8_PREPARSER_H | 891 #endif // V8_PREPARSER_H |
| OLD | NEW |