Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the above copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the above | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | |
| 28 #ifndef V8_PREPARSER_H | |
| 29 #define V8_PREPARSER_H | |
| 30 | |
| 31 #include "unicode.h" | |
| 32 | |
| 33 namespace v8 { | |
| 34 namespace internal { | |
| 35 namespace preparser { | |
| 36 | |
| 37 // Preparsing checks a JavaScript program and emits preparse-data that helps | |
| 38 // a later parsing to be faster. | |
| 39 // See preparser-data.h for the data. | |
| 40 | |
| 41 // The PreParser checks that the syntax follows the grammar for JavaScript, | |
| 42 // and collects some information about the program along the way. | |
| 43 // The grammar check is only performed in order to understand the program | |
| 44 // sufficiently to deduce some information about it, that can be used | |
| 45 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | |
| 46 // rather it is to speed up properly written and correct programs. | |
| 47 // That means that contextual checks (like a label being declared where | |
| 48 // it is used) are generally omitted. | |
| 49 | |
| 50 enum StatementType { | |
| 51 kUnknownStatement | |
| 52 }; | |
| 53 | |
| 54 enum ExpressionType { | |
| 55 kUnknownExpression, | |
| 56 kIdentifierExpression, // Used to detect labels. | |
| 57 kThisExpression, | |
| 58 kThisPropertyExpression | |
| 59 }; | |
| 60 | |
| 61 enum IdentifierType { | |
| 62 kUnknownIdentifier | |
| 63 }; | |
| 64 | |
| 65 enum SourceElementTypes { | |
| 66 kUnknownSourceElements | |
| 67 }; | |
| 68 | |
| 69 | |
| 70 typedef int SourceElements; | |
| 71 typedef int Expression; | |
| 72 typedef int Statement; | |
| 73 typedef int Identifier; | |
| 74 typedef int Arguments; | |
| 75 | |
| 76 | |
| 77 template <typename Scanner, typename PreParserLog> | |
| 78 class PreParser { | |
| 79 public: | |
| 80 PreParser() : scope_(NULL), allow_lazy_(true) { } | |
| 81 ~PreParser() { } | |
| 82 | |
| 83 // Pre-parse the program from the character stream; returns true on | |
| 84 // success (even if parsing failed, the pre-parse data successfully | |
| 85 // captured the syntax error), and false if a stack-overflow happened | |
| 86 // during parsing. | |
| 87 bool PreParseProgram(Scanner* scanner, | |
| 88 PreParserLog* log, | |
| 89 bool allow_lazy) { | |
| 90 allow_lazy_ = allow_lazy; | |
| 91 scanner_ = scanner; | |
| 92 log_ = log; | |
| 93 Scope top_scope(&scope_, kTopLevelScope); | |
| 94 bool ok = true; | |
| 95 ParseSourceElements(Token::EOS, &ok); | |
| 96 bool stack_overflow = scanner_->stack_overflow(); | |
| 97 if (!ok && !stack_overflow) { | |
| 98 ReportUnexpectedToken(scanner_->current_token()); | |
| 99 } | |
| 100 return !stack_overflow; | |
| 101 } | |
| 102 | |
| 103 private: | |
| 104 enum ScopeType { | |
| 105 kTopLevelScope, | |
| 106 kFunctionScope | |
| 107 }; | |
| 108 | |
| 109 class Scope { | |
| 110 public: | |
| 111 Scope(Scope** variable, ScopeType type) | |
| 112 : variable_(variable), | |
| 113 prev_(*variable), | |
| 114 type_(type), | |
| 115 materialized_literal_count_(0), | |
| 116 expected_properties_(0), | |
| 117 with_nesting_count_(0) { | |
| 118 *variable = this; | |
| 119 } | |
| 120 ~Scope() { *variable_ = prev_; } | |
| 121 void NextMaterializedLiteralIndex() { materialized_literal_count_++; } | |
| 122 void AddProperty() { expected_properties_++; } | |
| 123 ScopeType type() { return type_; } | |
| 124 int expected_properties() { return expected_properties_; } | |
| 125 int materialized_literal_count() { return materialized_literal_count_; } | |
| 126 bool IsInsideWith() { return with_nesting_count_ != 0; } | |
| 127 void EnterWith() { with_nesting_count_++; } | |
| 128 void LeaveWith() { with_nesting_count_--; } | |
| 129 | |
| 130 private: | |
| 131 Scope** const variable_; | |
| 132 Scope* const prev_; | |
| 133 const ScopeType type_; | |
| 134 int materialized_literal_count_; | |
| 135 int expected_properties_; | |
| 136 int with_nesting_count_; | |
| 137 }; | |
| 138 | |
| 139 // Types that allow us to recognize simple this-property assignments. | |
| 140 // A simple this-property assignment is a statement on the form | |
| 141 // "this.propertyName = {primitive constant or function parameter name);" | |
| 142 // where propertyName isn't "__proto__". | |
| 143 // The result is only relevant if the function body contains only | |
| 144 // simple this-property assignments. | |
| 145 | |
| 146 // Report syntax error | |
| 147 void ReportUnexpectedToken(Token::Value token); | |
| 148 void ReportMessageAt(int start_pos, | |
| 149 int end_pos, | |
| 150 const char* type, | |
| 151 const char* name_opt) { | |
| 152 log_->LogMessage(start_pos, end_pos, type, name_opt); | |
| 153 } | |
| 154 | |
| 155 // All ParseXXX functions take as the last argument an *ok parameter | |
| 156 // which is set to false if parsing failed; it is unchanged otherwise. | |
| 157 // By making the 'exception handling' explicit, we are forced to check | |
| 158 // for failure at the call sites. | |
| 159 SourceElements ParseSourceElements(int end_token, bool* ok); | |
| 160 Statement ParseStatement(bool* ok); | |
| 161 Statement ParseFunctionDeclaration(bool* ok); | |
| 162 Statement ParseNativeDeclaration(bool* ok); | |
| 163 Statement ParseBlock(bool* ok); | |
| 164 Statement ParseVariableStatement(bool* ok); | |
| 165 Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok); | |
| 166 Statement ParseExpressionOrLabelledStatement(bool* ok); | |
| 167 Statement ParseIfStatement(bool* ok); | |
| 168 Statement ParseContinueStatement(bool* ok); | |
| 169 Statement ParseBreakStatement(bool* ok); | |
| 170 Statement ParseReturnStatement(bool* ok); | |
| 171 Statement ParseWithStatement(bool* ok); | |
| 172 Statement ParseSwitchStatement(bool* ok); | |
| 173 Statement ParseDoWhileStatement(bool* ok); | |
| 174 Statement ParseWhileStatement(bool* ok); | |
| 175 Statement ParseForStatement(bool* ok); | |
| 176 Statement ParseThrowStatement(bool* ok); | |
| 177 Statement ParseTryStatement(bool* ok); | |
| 178 Statement ParseDebuggerStatement(bool* ok); | |
| 179 | |
| 180 Expression ParseExpression(bool accept_IN, bool* ok); | |
| 181 Expression ParseAssignmentExpression(bool accept_IN, bool* ok); | |
| 182 Expression ParseConditionalExpression(bool accept_IN, bool* ok); | |
| 183 Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok); | |
| 184 Expression ParseUnaryExpression(bool* ok); | |
| 185 Expression ParsePostfixExpression(bool* ok); | |
| 186 Expression ParseLeftHandSideExpression(bool* ok); | |
| 187 Expression ParseNewExpression(bool* ok); | |
| 188 Expression ParseMemberExpression(bool* ok); | |
| 189 Expression ParseNewPrefix(int* new_count, bool* ok); | |
| 190 Expression ParseMemberWithNewPrefixesExpression(int* new_count, bool* ok); | |
| 191 Expression ParsePrimaryExpression(bool* ok); | |
| 192 Expression ParseArrayLiteral(bool* ok); | |
| 193 Expression ParseObjectLiteral(bool* ok); | |
| 194 Expression ParseRegExpLiteral(bool seen_equal, bool* ok); | |
| 195 Expression ParseV8Intrinsic(bool* ok); | |
| 196 | |
| 197 Arguments ParseArguments(bool* ok); | |
| 198 Expression ParseFunctionLiteral(bool* ok); | |
| 199 | |
| 200 Identifier ParseIdentifier(bool* ok); | |
| 201 Identifier ParseIdentifierName(bool* ok); | |
| 202 Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok); | |
| 203 | |
| 204 Identifier GetIdentifierSymbol(); | |
| 205 unsigned int HexDigitValue(char digit); | |
| 206 Expression GetStringSymbol(); | |
| 207 | |
| 208 | |
| 209 Token::Value peek() { return scanner_->peek(); } | |
| 210 Token::Value Next() { | |
| 211 Token::Value next = scanner_->Next(); | |
| 212 return next; | |
| 213 } | |
| 214 | |
| 215 void Consume(Token::Value token) { | |
| 216 Next(); | |
| 217 } | |
| 218 | |
| 219 void Expect(Token::Value token, bool* ok) { | |
| 220 if (Next() != token) { | |
| 221 *ok = false; | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 bool Check(Token::Value token) { | |
| 226 Token::Value next = peek(); | |
| 227 if (next == token) { | |
| 228 Consume(next); | |
| 229 return true; | |
| 230 } | |
| 231 return false; | |
| 232 } | |
| 233 void ExpectSemicolon(bool* ok); | |
| 234 | |
| 235 static int Precedence(Token::Value tok, bool accept_IN); | |
| 236 | |
| 237 Scanner* scanner_; | |
| 238 PreParserLog* log_; | |
| 239 Scope* scope_; | |
| 240 bool allow_lazy_; | |
| 241 }; | |
| 242 | |
| 243 | |
| 244 #define CHECK_OK ok); \ | |
| 245 if (!*ok) return -1; \ | |
|
Mads Ager (chromium)
2010/11/02 07:17:03
Align the two '\'
| |
| 246 ((void)0 | |
| 247 #define DUMMY ) // to make indentation work | |
| 248 #undef DUMMY | |
| 249 | |
| 250 | |
| 251 template <typename Scanner, typename Log> | |
| 252 void PreParser<Scanner, Log>::ReportUnexpectedToken(Token::Value token) { | |
| 253 // We don't report stack overflows here, to avoid increasing the | |
| 254 // stack depth even further. Instead we report it after parsing is | |
| 255 // over, in ParseProgram. | |
| 256 if (token == Token::ILLEGAL && scanner_->stack_overflow()) { | |
| 257 return; | |
| 258 } | |
| 259 typename Scanner::Location source_location = scanner_->location(); | |
| 260 | |
| 261 // Four of the tokens are treated specially | |
| 262 switch (token) { | |
| 263 case Token::EOS: | |
| 264 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 265 "unexpected_eos", NULL); | |
| 266 case Token::NUMBER: | |
| 267 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 268 "unexpected_token_number", NULL); | |
| 269 case Token::STRING: | |
| 270 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 271 "unexpected_token_string", NULL); | |
| 272 case Token::IDENTIFIER: | |
| 273 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 274 "unexpected_token_identifier", NULL); | |
| 275 default: | |
| 276 const char* name = Token::String(token); | |
| 277 ReportMessageAt(source_location.beg_pos, source_location.end_pos, | |
| 278 "unexpected_token", name); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 | |
| 283 template <typename Scanner, typename Log> | |
| 284 SourceElements PreParser<Scanner, Log>::ParseSourceElements(int end_token, | |
| 285 bool* ok) { | |
| 286 // SourceElements :: | |
| 287 // (Statement)* <end_token> | |
| 288 | |
| 289 while (peek() != end_token) { | |
| 290 ParseStatement(CHECK_OK); | |
| 291 } | |
| 292 return kUnknownSourceElements; | |
| 293 } | |
| 294 | |
| 295 | |
| 296 template <typename Scanner, typename Log> | |
| 297 Statement PreParser<Scanner, Log>::ParseStatement(bool* ok) { | |
| 298 // Statement :: | |
| 299 // Block | |
| 300 // VariableStatement | |
| 301 // EmptyStatement | |
| 302 // ExpressionStatement | |
| 303 // IfStatement | |
| 304 // IterationStatement | |
| 305 // ContinueStatement | |
| 306 // BreakStatement | |
| 307 // ReturnStatement | |
| 308 // WithStatement | |
| 309 // LabelledStatement | |
| 310 // SwitchStatement | |
| 311 // ThrowStatement | |
| 312 // TryStatement | |
| 313 // DebuggerStatement | |
| 314 | |
| 315 // Note: Since labels can only be used by 'break' and 'continue' | |
| 316 // statements, which themselves are only valid within blocks, | |
| 317 // iterations or 'switch' statements (i.e., BreakableStatements), | |
| 318 // labels can be simply ignored in all other cases; except for | |
| 319 // trivial labeled break statements 'label: break label' which is | |
| 320 // parsed into an empty statement. | |
| 321 | |
| 322 // Keep the source position of the statement | |
| 323 switch (peek()) { | |
| 324 case Token::LBRACE: | |
| 325 return ParseBlock(ok); | |
| 326 | |
| 327 case Token::CONST: | |
| 328 case Token::VAR: | |
| 329 return ParseVariableStatement(ok); | |
| 330 | |
| 331 case Token::SEMICOLON: | |
| 332 Next(); | |
| 333 return kUnknownStatement; | |
| 334 | |
| 335 case Token::IF: | |
| 336 return ParseIfStatement(ok); | |
| 337 | |
| 338 case Token::DO: | |
| 339 return ParseDoWhileStatement(ok); | |
| 340 | |
| 341 case Token::WHILE: | |
| 342 return ParseWhileStatement(ok); | |
| 343 | |
| 344 case Token::FOR: | |
| 345 return ParseForStatement(ok); | |
| 346 | |
| 347 case Token::CONTINUE: | |
| 348 return ParseContinueStatement(ok); | |
| 349 | |
| 350 case Token::BREAK: | |
| 351 return ParseBreakStatement(ok); | |
| 352 | |
| 353 case Token::RETURN: | |
| 354 return ParseReturnStatement(ok); | |
| 355 | |
| 356 case Token::WITH: | |
| 357 return ParseWithStatement(ok); | |
| 358 | |
| 359 case Token::SWITCH: | |
| 360 return ParseSwitchStatement(ok); | |
| 361 | |
| 362 case Token::THROW: | |
| 363 return ParseThrowStatement(ok); | |
| 364 | |
| 365 case Token::TRY: | |
| 366 return ParseTryStatement(ok); | |
| 367 | |
| 368 case Token::FUNCTION: | |
| 369 return ParseFunctionDeclaration(ok); | |
| 370 | |
| 371 case Token::NATIVE: | |
| 372 return ParseNativeDeclaration(ok); | |
| 373 | |
| 374 case Token::DEBUGGER: | |
| 375 return ParseDebuggerStatement(ok); | |
| 376 | |
| 377 default: | |
| 378 return ParseExpressionOrLabelledStatement(ok); | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 | |
| 383 template <typename Scanner, typename Log> | |
| 384 Statement PreParser<Scanner, Log>::ParseFunctionDeclaration(bool* ok) { | |
| 385 // FunctionDeclaration :: | |
| 386 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' | |
| 387 Expect(Token::FUNCTION, CHECK_OK); | |
| 388 ParseIdentifier(CHECK_OK); | |
| 389 ParseFunctionLiteral(CHECK_OK); | |
| 390 return kUnknownStatement; | |
| 391 } | |
| 392 | |
| 393 | |
| 394 // Language extension which is only enabled for source files loaded | |
| 395 // through the API's extension mechanism. A native function | |
| 396 // declaration is resolved by looking up the function through a | |
| 397 // callback provided by the extension. | |
| 398 template <typename Scanner, typename Log> | |
| 399 Statement PreParser<Scanner, Log>::ParseNativeDeclaration(bool* ok) { | |
| 400 Expect(Token::NATIVE, CHECK_OK); | |
| 401 Expect(Token::FUNCTION, CHECK_OK); | |
| 402 ParseIdentifier(CHECK_OK); | |
| 403 Expect(Token::LPAREN, CHECK_OK); | |
| 404 bool done = (peek() == Token::RPAREN); | |
| 405 while (!done) { | |
| 406 ParseIdentifier(CHECK_OK); | |
| 407 done = (peek() == Token::RPAREN); | |
| 408 if (!done) { | |
| 409 Expect(Token::COMMA, CHECK_OK); | |
| 410 } | |
| 411 } | |
| 412 Expect(Token::RPAREN, CHECK_OK); | |
| 413 Expect(Token::SEMICOLON, CHECK_OK); | |
| 414 return kUnknownStatement; | |
| 415 } | |
| 416 | |
| 417 | |
| 418 template <typename Scanner, typename Log> | |
| 419 Statement PreParser<Scanner, Log>::ParseBlock(bool* ok) { | |
| 420 // Block :: | |
| 421 // '{' Statement* '}' | |
| 422 | |
| 423 // Note that a Block does not introduce a new execution scope! | |
| 424 // (ECMA-262, 3rd, 12.2) | |
| 425 // | |
| 426 Expect(Token::LBRACE, CHECK_OK); | |
| 427 while (peek() != Token::RBRACE) { | |
| 428 ParseStatement(CHECK_OK); | |
| 429 } | |
| 430 Expect(Token::RBRACE, CHECK_OK); | |
| 431 return kUnknownStatement; | |
| 432 } | |
| 433 | |
| 434 | |
| 435 template <typename Scanner, typename Log> | |
| 436 Statement PreParser<Scanner, Log>::ParseVariableStatement(bool* ok) { | |
| 437 // VariableStatement :: | |
| 438 // VariableDeclarations ';' | |
| 439 | |
| 440 Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK); | |
| 441 ExpectSemicolon(CHECK_OK); | |
| 442 return result; | |
| 443 } | |
| 444 | |
| 445 | |
| 446 // If the variable declaration declares exactly one non-const | |
| 447 // variable, then *var is set to that variable. In all other cases, | |
| 448 // *var is untouched; in particular, it is the caller's responsibility | |
| 449 // to initialize it properly. This mechanism is also used for the parsing | |
| 450 // of 'for-in' loops. | |
| 451 template <typename Scanner, typename Log> | |
| 452 Statement PreParser<Scanner, Log>::ParseVariableDeclarations(bool accept_IN, | |
| 453 int* num_decl, | |
| 454 bool* ok) { | |
| 455 // VariableDeclarations :: | |
| 456 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | |
| 457 | |
| 458 if (peek() == Token::VAR) { | |
| 459 Consume(Token::VAR); | |
| 460 } else if (peek() == Token::CONST) { | |
| 461 Consume(Token::CONST); | |
| 462 } else { | |
| 463 *ok = false; | |
| 464 return 0; | |
| 465 } | |
| 466 | |
| 467 // The scope of a variable/const declared anywhere inside a function | |
| 468 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). . | |
| 469 int nvars = 0; // the number of variables declared | |
| 470 do { | |
| 471 // Parse variable name. | |
| 472 if (nvars > 0) Consume(Token::COMMA); | |
| 473 ParseIdentifier(CHECK_OK); | |
| 474 nvars++; | |
| 475 if (peek() == Token::ASSIGN) { | |
| 476 Expect(Token::ASSIGN, CHECK_OK); | |
| 477 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 478 } | |
| 479 } while (peek() == Token::COMMA); | |
| 480 | |
| 481 if (num_decl != NULL) *num_decl = nvars; | |
| 482 return kUnknownStatement; | |
| 483 } | |
| 484 | |
| 485 | |
| 486 template <typename Scanner, typename Log> | |
| 487 Statement PreParser<Scanner, Log>::ParseExpressionOrLabelledStatement( | |
| 488 bool* ok) { | |
| 489 // ExpressionStatement | LabelledStatement :: | |
| 490 // Expression ';' | |
| 491 // Identifier ':' Statement | |
| 492 | |
| 493 Expression expr = ParseExpression(true, CHECK_OK); | |
| 494 if (peek() == Token::COLON && expr == kIdentifierExpression) { | |
| 495 Consume(Token::COLON); | |
| 496 return ParseStatement(ok); | |
| 497 } | |
| 498 // Parsed expression statement. | |
| 499 ExpectSemicolon(CHECK_OK); | |
| 500 return kUnknownStatement; | |
| 501 } | |
| 502 | |
| 503 | |
| 504 template <typename Scanner, typename Log> | |
| 505 Statement PreParser<Scanner, Log>::ParseIfStatement(bool* ok) { | |
| 506 // IfStatement :: | |
| 507 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
| 508 | |
| 509 Expect(Token::IF, CHECK_OK); | |
| 510 Expect(Token::LPAREN, CHECK_OK); | |
| 511 ParseExpression(true, CHECK_OK); | |
| 512 Expect(Token::RPAREN, CHECK_OK); | |
| 513 ParseStatement(CHECK_OK); | |
| 514 if (peek() == Token::ELSE) { | |
| 515 Next(); | |
| 516 ParseStatement(CHECK_OK); | |
| 517 } | |
| 518 return kUnknownStatement; | |
| 519 } | |
| 520 | |
| 521 | |
| 522 template <typename Scanner, typename Log> | |
| 523 Statement PreParser<Scanner, Log>::ParseContinueStatement(bool* ok) { | |
| 524 // ContinueStatement :: | |
| 525 // 'continue' [no line terminator] Identifier? ';' | |
| 526 | |
| 527 Expect(Token::CONTINUE, CHECK_OK); | |
| 528 Token::Value tok = peek(); | |
| 529 if (!scanner_->has_line_terminator_before_next() && | |
| 530 tok != Token::SEMICOLON && | |
| 531 tok != Token::RBRACE && | |
| 532 tok != Token::EOS) { | |
| 533 ParseIdentifier(CHECK_OK); | |
| 534 } | |
| 535 ExpectSemicolon(CHECK_OK); | |
| 536 return kUnknownStatement; | |
| 537 } | |
| 538 | |
| 539 | |
| 540 template <typename Scanner, typename Log> | |
| 541 Statement PreParser<Scanner, Log>::ParseBreakStatement(bool* ok) { | |
| 542 // BreakStatement :: | |
| 543 // 'break' [no line terminator] Identifier? ';' | |
| 544 | |
| 545 Expect(Token::BREAK, CHECK_OK); | |
| 546 Token::Value tok = peek(); | |
| 547 if (!scanner_->has_line_terminator_before_next() && | |
| 548 tok != Token::SEMICOLON && | |
| 549 tok != Token::RBRACE && | |
| 550 tok != Token::EOS) { | |
| 551 ParseIdentifier(CHECK_OK); | |
| 552 } | |
| 553 ExpectSemicolon(CHECK_OK); | |
| 554 return kUnknownStatement; | |
| 555 } | |
| 556 | |
| 557 | |
| 558 template <typename Scanner, typename Log> | |
| 559 Statement PreParser<Scanner, Log>::ParseReturnStatement(bool* ok) { | |
| 560 // ReturnStatement :: | |
| 561 // 'return' [no line terminator] Expression? ';' | |
| 562 | |
| 563 // Consume the return token. It is necessary to do the before | |
| 564 // reporting any errors on it, because of the way errors are | |
| 565 // reported (underlining). | |
| 566 Expect(Token::RETURN, CHECK_OK); | |
| 567 | |
| 568 // An ECMAScript program is considered syntactically incorrect if it | |
| 569 // contains a return statement that is not within the body of a | |
| 570 // function. See ECMA-262, section 12.9, page 67. | |
| 571 // This is not handled during preparsing. | |
| 572 | |
| 573 Token::Value tok = peek(); | |
| 574 if (!scanner_->has_line_terminator_before_next() && | |
| 575 tok != Token::SEMICOLON && | |
| 576 tok != Token::RBRACE && | |
| 577 tok != Token::EOS) { | |
| 578 ParseExpression(true, CHECK_OK); | |
| 579 } | |
| 580 ExpectSemicolon(CHECK_OK); | |
| 581 return kUnknownStatement; | |
| 582 } | |
| 583 | |
| 584 | |
| 585 template <typename Scanner, typename Log> | |
| 586 Statement PreParser<Scanner, Log>::ParseWithStatement(bool* ok) { | |
| 587 // WithStatement :: | |
| 588 // 'with' '(' Expression ')' Statement | |
| 589 Expect(Token::WITH, CHECK_OK); | |
| 590 Expect(Token::LPAREN, CHECK_OK); | |
| 591 ParseExpression(true, CHECK_OK); | |
| 592 Expect(Token::RPAREN, CHECK_OK); | |
| 593 | |
| 594 scope_->EnterWith(); | |
| 595 ParseStatement(CHECK_OK); | |
| 596 scope_->LeaveWith(); | |
| 597 return kUnknownStatement; | |
| 598 } | |
| 599 | |
| 600 | |
| 601 template <typename Scanner, typename Log> | |
| 602 Statement PreParser<Scanner, Log>::ParseSwitchStatement(bool* ok) { | |
| 603 // SwitchStatement :: | |
| 604 // 'switch' '(' Expression ')' '{' CaseClause* '}' | |
| 605 | |
| 606 Expect(Token::SWITCH, CHECK_OK); | |
| 607 Expect(Token::LPAREN, CHECK_OK); | |
| 608 ParseExpression(true, CHECK_OK); | |
| 609 Expect(Token::RPAREN, CHECK_OK); | |
| 610 | |
| 611 Expect(Token::LBRACE, CHECK_OK); | |
| 612 Token::Value token = peek(); | |
| 613 while (token != Token::RBRACE) { | |
| 614 if (token == Token::CASE) { | |
| 615 Expect(Token::CASE, CHECK_OK); | |
| 616 ParseExpression(true, CHECK_OK); | |
| 617 Expect(Token::COLON, CHECK_OK); | |
| 618 } else if (token == Token::DEFAULT) { | |
| 619 Expect(Token::DEFAULT, CHECK_OK); | |
| 620 Expect(Token::COLON, CHECK_OK); | |
| 621 } else { | |
| 622 ParseStatement(CHECK_OK); | |
| 623 } | |
| 624 token = peek(); | |
| 625 } | |
| 626 Expect(Token::RBRACE, CHECK_OK); | |
| 627 | |
| 628 return kUnknownStatement; | |
| 629 } | |
| 630 | |
| 631 | |
| 632 template <typename Scanner, typename Log> | |
| 633 Statement PreParser<Scanner, Log>::ParseDoWhileStatement(bool* ok) { | |
| 634 // DoStatement :: | |
| 635 // 'do' Statement 'while' '(' Expression ')' ';' | |
| 636 | |
| 637 Expect(Token::DO, CHECK_OK); | |
| 638 ParseStatement(CHECK_OK); | |
| 639 Expect(Token::WHILE, CHECK_OK); | |
| 640 Expect(Token::LPAREN, CHECK_OK); | |
| 641 ParseExpression(true, CHECK_OK); | |
| 642 Expect(Token::RPAREN, CHECK_OK); | |
| 643 return kUnknownStatement; | |
| 644 } | |
| 645 | |
| 646 | |
| 647 template <typename Scanner, typename Log> | |
| 648 Statement PreParser<Scanner, Log>::ParseWhileStatement(bool* ok) { | |
| 649 // WhileStatement :: | |
| 650 // 'while' '(' Expression ')' Statement | |
| 651 | |
| 652 Expect(Token::WHILE, CHECK_OK); | |
| 653 Expect(Token::LPAREN, CHECK_OK); | |
| 654 ParseExpression(true, CHECK_OK); | |
| 655 Expect(Token::RPAREN, CHECK_OK); | |
| 656 ParseStatement(CHECK_OK); | |
| 657 return kUnknownStatement; | |
| 658 } | |
| 659 | |
| 660 | |
| 661 template <typename Scanner, typename Log> | |
| 662 Statement PreParser<Scanner, Log>::ParseForStatement(bool* ok) { | |
| 663 // ForStatement :: | |
| 664 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | |
| 665 | |
| 666 Expect(Token::FOR, CHECK_OK); | |
| 667 Expect(Token::LPAREN, CHECK_OK); | |
| 668 if (peek() != Token::SEMICOLON) { | |
| 669 if (peek() == Token::VAR || peek() == Token::CONST) { | |
| 670 int decl_count; | |
| 671 ParseVariableDeclarations(false, &decl_count, CHECK_OK); | |
| 672 if (peek() == Token::IN && decl_count == 1) { | |
| 673 Expect(Token::IN, CHECK_OK); | |
| 674 ParseExpression(true, CHECK_OK); | |
| 675 Expect(Token::RPAREN, CHECK_OK); | |
| 676 | |
| 677 ParseStatement(CHECK_OK); | |
| 678 return kUnknownStatement; | |
| 679 } | |
| 680 } else { | |
| 681 ParseExpression(false, CHECK_OK); | |
| 682 if (peek() == Token::IN) { | |
| 683 Expect(Token::IN, CHECK_OK); | |
| 684 ParseExpression(true, CHECK_OK); | |
| 685 Expect(Token::RPAREN, CHECK_OK); | |
| 686 | |
| 687 ParseStatement(CHECK_OK); | |
| 688 return kUnknownStatement; | |
| 689 } | |
| 690 } | |
| 691 } | |
| 692 | |
| 693 // Parsed initializer at this point. | |
| 694 Expect(Token::SEMICOLON, CHECK_OK); | |
| 695 | |
| 696 if (peek() != Token::SEMICOLON) { | |
| 697 ParseExpression(true, CHECK_OK); | |
| 698 } | |
| 699 Expect(Token::SEMICOLON, CHECK_OK); | |
| 700 | |
| 701 if (peek() != Token::RPAREN) { | |
| 702 ParseExpression(true, CHECK_OK); | |
| 703 } | |
| 704 Expect(Token::RPAREN, CHECK_OK); | |
| 705 | |
| 706 ParseStatement(CHECK_OK); | |
| 707 return kUnknownStatement; | |
| 708 } | |
| 709 | |
| 710 | |
| 711 template <typename Scanner, typename Log> | |
| 712 Statement PreParser<Scanner, Log>::ParseThrowStatement(bool* ok) { | |
| 713 // ThrowStatement :: | |
| 714 // 'throw' [no line terminator] Expression ';' | |
| 715 | |
| 716 Expect(Token::THROW, CHECK_OK); | |
| 717 if (scanner_->has_line_terminator_before_next()) { | |
| 718 typename Scanner::Location pos = scanner_->location(); | |
| 719 ReportMessageAt(pos.beg_pos, pos.end_pos, | |
| 720 "newline_after_throw", NULL); | |
| 721 *ok = false; | |
| 722 return NULL; | |
| 723 } | |
| 724 ParseExpression(true, CHECK_OK); | |
| 725 ExpectSemicolon(CHECK_OK); | |
| 726 | |
| 727 return kUnknownStatement; | |
| 728 } | |
| 729 | |
| 730 | |
| 731 template <typename Scanner, typename Log> | |
| 732 Statement PreParser<Scanner, Log>::ParseTryStatement(bool* ok) { | |
| 733 // TryStatement :: | |
| 734 // 'try' Block Catch | |
| 735 // 'try' Block Finally | |
| 736 // 'try' Block Catch Finally | |
| 737 // | |
| 738 // Catch :: | |
| 739 // 'catch' '(' Identifier ')' Block | |
| 740 // | |
| 741 // Finally :: | |
| 742 // 'finally' Block | |
| 743 | |
| 744 // In preparsing, allow any number of catch/finally blocks, including zero | |
| 745 // of both. | |
| 746 | |
| 747 Expect(Token::TRY, CHECK_OK); | |
| 748 | |
| 749 ParseBlock(CHECK_OK); | |
| 750 | |
| 751 bool catch_or_finally_seen = false; | |
| 752 if (peek() == Token::CATCH) { | |
| 753 Expect(Token::CATCH, CHECK_OK); | |
| 754 Expect(Token::LPAREN, CHECK_OK); | |
| 755 ParseIdentifier(CHECK_OK); | |
| 756 Expect(Token::RPAREN, CHECK_OK); | |
| 757 ParseBlock(CHECK_OK); | |
| 758 catch_or_finally_seen = true; | |
| 759 } | |
| 760 if (peek() == Token::FINALLY) { | |
| 761 Expect(Token::FINALLY, CHECK_OK); | |
| 762 ParseBlock(CHECK_OK); | |
| 763 catch_or_finally_seen = true; | |
| 764 } | |
| 765 if (!catch_or_finally_seen) { | |
| 766 *ok = false; | |
| 767 } | |
| 768 return kUnknownStatement; | |
| 769 } | |
| 770 | |
| 771 | |
| 772 template <typename Scanner, typename Log> | |
| 773 Statement PreParser<Scanner, Log>::ParseDebuggerStatement(bool* ok) { | |
| 774 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser | |
| 775 // contexts this is used as a statement which invokes the debugger as if a | |
| 776 // break point is present. | |
| 777 // DebuggerStatement :: | |
| 778 // 'debugger' ';' | |
| 779 | |
| 780 Expect(Token::DEBUGGER, CHECK_OK); | |
| 781 ExpectSemicolon(CHECK_OK); | |
| 782 return kUnknownStatement; | |
| 783 } | |
| 784 | |
| 785 | |
| 786 // Precedence = 1 | |
| 787 template <typename Scanner, typename Log> | |
| 788 Expression PreParser<Scanner, Log>::ParseExpression(bool accept_IN, bool* ok) { | |
| 789 // Expression :: | |
| 790 // AssignmentExpression | |
| 791 // Expression ',' AssignmentExpression | |
| 792 | |
| 793 Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 794 while (peek() == Token::COMMA) { | |
| 795 Expect(Token::COMMA, CHECK_OK); | |
| 796 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 797 result = kUnknownExpression; | |
| 798 } | |
| 799 return result; | |
| 800 } | |
| 801 | |
| 802 | |
| 803 // Precedence = 2 | |
| 804 template <typename Scanner, typename Log> | |
| 805 Expression PreParser<Scanner, Log>::ParseAssignmentExpression(bool accept_IN, | |
| 806 bool* ok) { | |
| 807 // AssignmentExpression :: | |
| 808 // ConditionalExpression | |
| 809 // LeftHandSideExpression AssignmentOperator AssignmentExpression | |
| 810 | |
| 811 Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK); | |
| 812 | |
| 813 if (!Token::IsAssignmentOp(peek())) { | |
| 814 // Parsed conditional expression only (no assignment). | |
| 815 return expression; | |
| 816 } | |
| 817 | |
| 818 Token::Value op = Next(); // Get assignment operator. | |
| 819 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 820 | |
| 821 if ((op == Token::ASSIGN) && (expression == kThisPropertyExpression)) { | |
| 822 scope_->AddProperty(); | |
| 823 } | |
| 824 | |
| 825 return kUnknownExpression; | |
| 826 } | |
| 827 | |
| 828 | |
| 829 // Precedence = 3 | |
| 830 template <typename Scanner, typename Log> | |
| 831 Expression PreParser<Scanner, Log>::ParseConditionalExpression(bool accept_IN, | |
| 832 bool* ok) { | |
| 833 // ConditionalExpression :: | |
| 834 // LogicalOrExpression | |
| 835 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression | |
| 836 | |
| 837 // We start using the binary expression parser for prec >= 4 only! | |
| 838 Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK); | |
| 839 if (peek() != Token::CONDITIONAL) return expression; | |
| 840 Consume(Token::CONDITIONAL); | |
| 841 // In parsing the first assignment expression in conditional | |
| 842 // expressions we always accept the 'in' keyword; see ECMA-262, | |
| 843 // section 11.12, page 58. | |
| 844 ParseAssignmentExpression(true, CHECK_OK); | |
| 845 Expect(Token::COLON, CHECK_OK); | |
| 846 ParseAssignmentExpression(accept_IN, CHECK_OK); | |
| 847 return kUnknownExpression; | |
| 848 } | |
| 849 | |
| 850 | |
| 851 template <typename Scanner, typename Log> | |
| 852 int PreParser<Scanner, Log>::Precedence(Token::Value tok, bool accept_IN) { | |
| 853 if (tok == Token::IN && !accept_IN) | |
| 854 return 0; // 0 precedence will terminate binary expression parsing | |
| 855 | |
| 856 return Token::Precedence(tok); | |
| 857 } | |
| 858 | |
| 859 | |
| 860 // Precedence >= 4 | |
| 861 template <typename Scanner, typename Log> | |
| 862 Expression PreParser<Scanner, Log>::ParseBinaryExpression(int prec, | |
| 863 bool accept_IN, | |
| 864 bool* ok) { | |
| 865 Expression result = ParseUnaryExpression(CHECK_OK); | |
| 866 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { | |
| 867 // prec1 >= 4 | |
| 868 while (Precedence(peek(), accept_IN) == prec1) { | |
| 869 Next(); | |
| 870 ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK); | |
| 871 result = kUnknownExpression; | |
| 872 } | |
| 873 } | |
| 874 return result; | |
| 875 } | |
| 876 | |
| 877 | |
| 878 template <typename Scanner, typename Log> | |
| 879 Expression PreParser<Scanner, Log>::ParseUnaryExpression(bool* ok) { | |
| 880 // UnaryExpression :: | |
| 881 // PostfixExpression | |
| 882 // 'delete' UnaryExpression | |
| 883 // 'void' UnaryExpression | |
| 884 // 'typeof' UnaryExpression | |
| 885 // '++' UnaryExpression | |
| 886 // '--' UnaryExpression | |
| 887 // '+' UnaryExpression | |
| 888 // '-' UnaryExpression | |
| 889 // '~' UnaryExpression | |
| 890 // '!' UnaryExpression | |
| 891 | |
| 892 Token::Value op = peek(); | |
| 893 if (Token::IsUnaryOp(op) || Token::IsCountOp(op)) { | |
| 894 op = Next(); | |
| 895 ParseUnaryExpression(ok); | |
| 896 return kUnknownExpression; | |
| 897 } else { | |
| 898 return ParsePostfixExpression(ok); | |
| 899 } | |
| 900 } | |
| 901 | |
| 902 | |
| 903 template <typename Scanner, typename Log> | |
| 904 Expression PreParser<Scanner, Log>::ParsePostfixExpression(bool* ok) { | |
| 905 // PostfixExpression :: | |
| 906 // LeftHandSideExpression ('++' | '--')? | |
| 907 | |
| 908 Expression expression = ParseLeftHandSideExpression(CHECK_OK); | |
| 909 if (!scanner_->has_line_terminator_before_next() && | |
| 910 Token::IsCountOp(peek())) { | |
| 911 Next(); | |
| 912 return kUnknownExpression; | |
| 913 } | |
| 914 return expression; | |
| 915 } | |
| 916 | |
| 917 | |
| 918 template <typename Scanner, typename Log> | |
| 919 Expression PreParser<Scanner, Log>::ParseLeftHandSideExpression(bool* ok) { | |
| 920 // LeftHandSideExpression :: | |
| 921 // (NewExpression | MemberExpression) ... | |
| 922 | |
| 923 Expression result; | |
| 924 if (peek() == Token::NEW) { | |
| 925 result = ParseNewExpression(CHECK_OK); | |
| 926 } else { | |
| 927 result = ParseMemberExpression(CHECK_OK); | |
| 928 } | |
| 929 | |
| 930 while (true) { | |
| 931 switch (peek()) { | |
| 932 case Token::LBRACK: { | |
| 933 Consume(Token::LBRACK); | |
| 934 ParseExpression(true, CHECK_OK); | |
| 935 Expect(Token::RBRACK, CHECK_OK); | |
| 936 if (result == kThisExpression) { | |
| 937 result = kThisPropertyExpression; | |
| 938 } else { | |
| 939 result = kUnknownExpression; | |
| 940 } | |
| 941 break; | |
| 942 } | |
| 943 | |
| 944 case Token::LPAREN: { | |
| 945 ParseArguments(CHECK_OK); | |
| 946 result = kUnknownExpression; | |
| 947 break; | |
| 948 } | |
| 949 | |
| 950 case Token::PERIOD: { | |
| 951 Consume(Token::PERIOD); | |
| 952 ParseIdentifierName(CHECK_OK); | |
| 953 if (result == kThisExpression) { | |
| 954 result = kThisPropertyExpression; | |
| 955 } else { | |
| 956 result = kUnknownExpression; | |
| 957 } | |
| 958 break; | |
| 959 } | |
| 960 | |
| 961 default: | |
| 962 return result; | |
| 963 } | |
| 964 } | |
| 965 } | |
| 966 | |
| 967 | |
| 968 | |
| 969 template <typename Scanner, typename Log> | |
| 970 Expression PreParser<Scanner, Log>::ParseNewPrefix(int* new_count, bool* ok) { | |
| 971 // NewExpression :: | |
| 972 // ('new')+ MemberExpression | |
| 973 | |
| 974 // The grammar for new expressions is pretty warped. The keyword | |
| 975 // 'new' can either be a part of the new expression (where it isn't | |
| 976 // followed by an argument list) or a part of the member expression, | |
| 977 // where it must be followed by an argument list. To accommodate | |
| 978 // this, we parse the 'new' keywords greedily and keep track of how | |
| 979 // many we have parsed. This information is then passed on to the | |
| 980 // member expression parser, which is only allowed to match argument | |
| 981 // lists as long as it has 'new' prefixes left | |
| 982 Expect(Token::NEW, CHECK_OK); | |
| 983 *new_count++; | |
| 984 | |
| 985 if (peek() == Token::NEW) { | |
| 986 ParseNewPrefix(new_count, CHECK_OK); | |
| 987 } else { | |
| 988 ParseMemberWithNewPrefixesExpression(new_count, CHECK_OK); | |
| 989 } | |
| 990 | |
| 991 if (*new_count > 0) { | |
| 992 *new_count--; | |
| 993 } | |
| 994 return kUnknownExpression; | |
| 995 } | |
| 996 | |
| 997 | |
| 998 template <typename Scanner, typename Log> | |
| 999 Expression PreParser<Scanner, Log>::ParseNewExpression(bool* ok) { | |
| 1000 int new_count = 0; | |
| 1001 return ParseNewPrefix(&new_count, ok); | |
| 1002 } | |
| 1003 | |
| 1004 | |
| 1005 template <typename Scanner, typename Log> | |
| 1006 Expression PreParser<Scanner, Log>::ParseMemberExpression(bool* ok) { | |
| 1007 return ParseMemberWithNewPrefixesExpression(NULL, ok); | |
| 1008 } | |
| 1009 | |
| 1010 | |
| 1011 template <typename Scanner, typename Log> | |
| 1012 Expression PreParser<Scanner, Log>::ParseMemberWithNewPrefixesExpression( | |
| 1013 int* new_count, bool* ok) { | |
| 1014 // MemberExpression :: | |
| 1015 // (PrimaryExpression | FunctionLiteral) | |
| 1016 // ('[' Expression ']' | '.' Identifier | Arguments)* | |
| 1017 | |
| 1018 // Parse the initial primary or function expression. | |
| 1019 Expression result = NULL; | |
| 1020 if (peek() == Token::FUNCTION) { | |
| 1021 Consume(Token::FUNCTION); | |
| 1022 if (peek() == Token::IDENTIFIER) { | |
| 1023 ParseIdentifier(CHECK_OK); | |
| 1024 } | |
| 1025 result = ParseFunctionLiteral(CHECK_OK); | |
| 1026 } else { | |
| 1027 result = ParsePrimaryExpression(CHECK_OK); | |
| 1028 } | |
| 1029 | |
| 1030 while (true) { | |
| 1031 switch (peek()) { | |
| 1032 case Token::LBRACK: { | |
| 1033 Consume(Token::LBRACK); | |
| 1034 ParseExpression(true, CHECK_OK); | |
| 1035 Expect(Token::RBRACK, CHECK_OK); | |
| 1036 if (result == kThisExpression) { | |
| 1037 result = kThisPropertyExpression; | |
| 1038 } else { | |
| 1039 result = kUnknownExpression; | |
| 1040 } | |
| 1041 break; | |
| 1042 } | |
| 1043 case Token::PERIOD: { | |
| 1044 Consume(Token::PERIOD); | |
| 1045 ParseIdentifierName(CHECK_OK); | |
| 1046 if (result == kThisExpression) { | |
| 1047 result = kThisPropertyExpression; | |
| 1048 } else { | |
| 1049 result = kUnknownExpression; | |
| 1050 } | |
| 1051 break; | |
| 1052 } | |
| 1053 case Token::LPAREN: { | |
| 1054 if ((new_count == NULL) || *new_count == 0) return result; | |
| 1055 // Consume one of the new prefixes (already parsed). | |
| 1056 ParseArguments(CHECK_OK); | |
| 1057 *new_count--; | |
| 1058 result = kUnknownExpression; | |
| 1059 break; | |
| 1060 } | |
| 1061 default: | |
| 1062 return result; | |
| 1063 } | |
| 1064 } | |
| 1065 } | |
| 1066 | |
| 1067 | |
| 1068 template <typename Scanner, typename Log> | |
| 1069 Expression PreParser<Scanner, Log>::ParsePrimaryExpression(bool* ok) { | |
| 1070 // PrimaryExpression :: | |
| 1071 // 'this' | |
| 1072 // 'null' | |
| 1073 // 'true' | |
| 1074 // 'false' | |
| 1075 // Identifier | |
| 1076 // Number | |
| 1077 // String | |
| 1078 // ArrayLiteral | |
| 1079 // ObjectLiteral | |
| 1080 // RegExpLiteral | |
| 1081 // '(' Expression ')' | |
| 1082 | |
| 1083 Expression result = kUnknownExpression; | |
| 1084 switch (peek()) { | |
| 1085 case Token::THIS: { | |
| 1086 Next(); | |
| 1087 result = kThisExpression; | |
| 1088 break; | |
| 1089 } | |
| 1090 | |
| 1091 case Token::IDENTIFIER: { | |
| 1092 ParseIdentifier(CHECK_OK); | |
| 1093 result = kIdentifierExpression; | |
| 1094 break; | |
| 1095 } | |
| 1096 | |
| 1097 case Token::NULL_LITERAL: | |
| 1098 case Token::TRUE_LITERAL: | |
| 1099 case Token::FALSE_LITERAL: | |
| 1100 case Token::NUMBER: { | |
| 1101 Next(); | |
| 1102 break; | |
| 1103 } | |
| 1104 case Token::STRING: { | |
| 1105 Next(); | |
| 1106 result = GetStringSymbol(); | |
| 1107 break; | |
| 1108 } | |
| 1109 | |
| 1110 case Token::ASSIGN_DIV: | |
| 1111 result = ParseRegExpLiteral(true, CHECK_OK); | |
| 1112 break; | |
| 1113 | |
| 1114 case Token::DIV: | |
| 1115 result = ParseRegExpLiteral(false, CHECK_OK); | |
| 1116 break; | |
| 1117 | |
| 1118 case Token::LBRACK: | |
| 1119 result = ParseArrayLiteral(CHECK_OK); | |
| 1120 break; | |
| 1121 | |
| 1122 case Token::LBRACE: | |
| 1123 result = ParseObjectLiteral(CHECK_OK); | |
| 1124 break; | |
| 1125 | |
| 1126 case Token::LPAREN: | |
| 1127 Consume(Token::LPAREN); | |
| 1128 result = ParseExpression(true, CHECK_OK); | |
| 1129 Expect(Token::RPAREN, CHECK_OK); | |
| 1130 if (result == kIdentifierExpression) result = kUnknownExpression; | |
| 1131 break; | |
| 1132 | |
| 1133 case Token::MOD: | |
| 1134 result = ParseV8Intrinsic(CHECK_OK); | |
| 1135 break; | |
| 1136 | |
| 1137 default: { | |
| 1138 Next(); | |
| 1139 *ok = false; | |
| 1140 return kUnknownExpression; | |
| 1141 } | |
| 1142 } | |
| 1143 | |
| 1144 return result; | |
| 1145 } | |
| 1146 | |
| 1147 | |
| 1148 template <typename Scanner, typename Log> | |
| 1149 Expression PreParser<Scanner, Log>::ParseArrayLiteral(bool* ok) { | |
| 1150 // ArrayLiteral :: | |
| 1151 // '[' Expression? (',' Expression?)* ']' | |
| 1152 Expect(Token::LBRACK, CHECK_OK); | |
| 1153 while (peek() != Token::RBRACK) { | |
| 1154 if (peek() != Token::COMMA) { | |
| 1155 ParseAssignmentExpression(true, CHECK_OK); | |
| 1156 } | |
| 1157 if (peek() != Token::RBRACK) { | |
| 1158 Expect(Token::COMMA, CHECK_OK); | |
| 1159 } | |
| 1160 } | |
| 1161 Expect(Token::RBRACK, CHECK_OK); | |
| 1162 | |
| 1163 scope_->NextMaterializedLiteralIndex(); | |
| 1164 return kUnknownExpression; | |
| 1165 } | |
| 1166 | |
| 1167 | |
| 1168 template <typename Scanner, typename Log> | |
| 1169 Expression PreParser<Scanner, Log>::ParseObjectLiteral(bool* ok) { | |
| 1170 // ObjectLiteral :: | |
| 1171 // '{' ( | |
| 1172 // ((IdentifierName | String | Number) ':' AssignmentExpression) | |
| 1173 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) | |
| 1174 // )*[','] '}' | |
| 1175 | |
| 1176 Expect(Token::LBRACE, CHECK_OK); | |
| 1177 while (peek() != Token::RBRACE) { | |
| 1178 Token::Value next = peek(); | |
| 1179 switch (next) { | |
| 1180 case Token::IDENTIFIER: { | |
| 1181 bool is_getter = false; | |
| 1182 bool is_setter = false; | |
| 1183 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); | |
| 1184 if ((is_getter || is_setter) && peek() != Token::COLON) { | |
| 1185 Token::Value name = Next(); | |
| 1186 if (name != Token::IDENTIFIER && | |
| 1187 name != Token::NUMBER && | |
| 1188 name != Token::STRING && | |
| 1189 !Token::IsKeyword(name)) { | |
| 1190 *ok = false; | |
| 1191 return kUnknownExpression; | |
| 1192 } | |
| 1193 ParseFunctionLiteral(CHECK_OK); | |
| 1194 if (peek() != Token::RBRACE) { | |
| 1195 Expect(Token::COMMA, CHECK_OK); | |
| 1196 } | |
| 1197 continue; // restart the while | |
| 1198 } | |
| 1199 break; | |
| 1200 } | |
| 1201 case Token::STRING: | |
| 1202 Consume(next); | |
| 1203 GetStringSymbol(); | |
| 1204 break; | |
| 1205 case Token::NUMBER: | |
| 1206 Consume(next); | |
| 1207 break; | |
| 1208 default: | |
| 1209 if (Token::IsKeyword(next)) { | |
| 1210 Consume(next); | |
| 1211 } else { | |
| 1212 // Unexpected token. | |
| 1213 *ok = false; | |
| 1214 return kUnknownExpression; | |
| 1215 } | |
| 1216 } | |
| 1217 | |
| 1218 Expect(Token::COLON, CHECK_OK); | |
| 1219 ParseAssignmentExpression(true, CHECK_OK); | |
| 1220 | |
| 1221 // TODO(1240767): Consider allowing trailing comma. | |
| 1222 if (peek() != Token::RBRACE) Expect(Token::COMMA, CHECK_OK); | |
| 1223 } | |
| 1224 Expect(Token::RBRACE, CHECK_OK); | |
| 1225 | |
| 1226 scope_->NextMaterializedLiteralIndex(); | |
| 1227 return kUnknownExpression; | |
| 1228 } | |
| 1229 | |
| 1230 | |
| 1231 template <typename Scanner, typename Log> | |
| 1232 Expression PreParser<Scanner, Log>::ParseRegExpLiteral(bool seen_equal, | |
| 1233 bool* ok) { | |
| 1234 if (!scanner_->ScanRegExpPattern(seen_equal)) { | |
| 1235 Next(); | |
| 1236 typename Scanner::Location location = scanner_->location(); | |
| 1237 ReportMessageAt(location.beg_pos, location.end_pos, | |
| 1238 "unterminated_regexp", NULL); | |
| 1239 *ok = false; | |
| 1240 return kUnknownExpression; | |
| 1241 } | |
| 1242 | |
| 1243 scope_->NextMaterializedLiteralIndex(); | |
| 1244 | |
| 1245 if (!scanner_->ScanRegExpFlags()) { | |
| 1246 Next(); | |
| 1247 typename Scanner::Location location = scanner_->location(); | |
| 1248 ReportMessageAt(location.beg_pos, location.end_pos, | |
| 1249 "invalid_regexp_flags", NULL); | |
| 1250 *ok = false; | |
| 1251 return kUnknownExpression; | |
| 1252 } | |
| 1253 Next(); | |
| 1254 return kUnknownExpression; | |
| 1255 } | |
| 1256 | |
| 1257 | |
| 1258 template <typename Scanner, typename Log> | |
| 1259 Arguments PreParser<Scanner, Log>::ParseArguments(bool* ok) { | |
| 1260 // Arguments :: | |
| 1261 // '(' (AssignmentExpression)*[','] ')' | |
| 1262 | |
| 1263 Expect(Token::LPAREN, CHECK_OK); | |
| 1264 bool done = (peek() == Token::RPAREN); | |
| 1265 int argc = 0; | |
| 1266 while (!done) { | |
| 1267 ParseAssignmentExpression(true, CHECK_OK); | |
| 1268 argc++; | |
| 1269 done = (peek() == Token::RPAREN); | |
| 1270 if (!done) Expect(Token::COMMA, CHECK_OK); | |
| 1271 } | |
| 1272 Expect(Token::RPAREN, CHECK_OK); | |
| 1273 return argc; | |
| 1274 } | |
| 1275 | |
| 1276 | |
| 1277 template <typename Scanner, typename Log> | |
| 1278 Expression PreParser<Scanner, Log>::ParseFunctionLiteral(bool* ok) { | |
| 1279 // Function :: | |
| 1280 // '(' FormalParameterList? ')' '{' FunctionBody '}' | |
| 1281 | |
| 1282 // Parse function body. | |
| 1283 ScopeType outer_scope_type = scope_->type(); | |
| 1284 bool inside_with = scope_->IsInsideWith(); | |
| 1285 Scope function_scope(&scope_, kFunctionScope); | |
| 1286 | |
| 1287 // FormalParameterList :: | |
| 1288 // '(' (Identifier)*[','] ')' | |
| 1289 Expect(Token::LPAREN, CHECK_OK); | |
| 1290 bool done = (peek() == Token::RPAREN); | |
| 1291 while (!done) { | |
| 1292 ParseIdentifier(CHECK_OK); | |
| 1293 done = (peek() == Token::RPAREN); | |
| 1294 if (!done) { | |
| 1295 Expect(Token::COMMA, CHECK_OK); | |
| 1296 } | |
| 1297 } | |
| 1298 Expect(Token::RPAREN, CHECK_OK); | |
| 1299 | |
| 1300 Expect(Token::LBRACE, CHECK_OK); | |
| 1301 int function_block_pos = scanner_->location().beg_pos; | |
| 1302 | |
| 1303 // Determine if the function will be lazily compiled. | |
| 1304 // Currently only happens to top-level functions. | |
| 1305 // Optimistically assume that all top-level functions are lazily compiled. | |
| 1306 bool is_lazily_compiled = | |
| 1307 (outer_scope_type == kTopLevelScope && !inside_with && allow_lazy_); | |
| 1308 | |
| 1309 if (is_lazily_compiled) { | |
| 1310 log_->PauseRecording(); | |
| 1311 ParseSourceElements(Token::RBRACE, ok); | |
| 1312 log_->ResumeRecording(); | |
| 1313 if (!*ok) return kUnknownExpression; | |
| 1314 | |
| 1315 Expect(Token::RBRACE, CHECK_OK); | |
| 1316 | |
| 1317 int end_pos = scanner_->location().end_pos; | |
| 1318 log_->LogFunction(function_block_pos, end_pos, | |
| 1319 function_scope.materialized_literal_count(), | |
| 1320 function_scope.expected_properties()); | |
| 1321 } else { | |
| 1322 ParseSourceElements(Token::RBRACE, CHECK_OK); | |
| 1323 Expect(Token::RBRACE, CHECK_OK); | |
| 1324 } | |
| 1325 return kUnknownExpression; | |
| 1326 } | |
| 1327 | |
| 1328 | |
| 1329 template <typename Scanner, typename Log> | |
| 1330 Expression PreParser<Scanner, Log>::ParseV8Intrinsic(bool* ok) { | |
| 1331 // CallRuntime :: | |
| 1332 // '%' Identifier Arguments | |
| 1333 | |
| 1334 Expect(Token::MOD, CHECK_OK); | |
| 1335 ParseIdentifier(CHECK_OK); | |
| 1336 ParseArguments(CHECK_OK); | |
| 1337 | |
| 1338 return kUnknownExpression; | |
| 1339 } | |
| 1340 | |
| 1341 | |
| 1342 template <typename Scanner, typename Log> | |
| 1343 void PreParser<Scanner, Log>::ExpectSemicolon(bool* ok) { | |
| 1344 // Check for automatic semicolon insertion according to | |
| 1345 // the rules given in ECMA-262, section 7.9, page 21. | |
| 1346 Token::Value tok = peek(); | |
| 1347 if (tok == Token::SEMICOLON) { | |
| 1348 Next(); | |
| 1349 return; | |
| 1350 } | |
| 1351 if (scanner_->has_line_terminator_before_next() || | |
| 1352 tok == Token::RBRACE || | |
| 1353 tok == Token::EOS) { | |
| 1354 return; | |
| 1355 } | |
| 1356 Expect(Token::SEMICOLON, ok); | |
| 1357 } | |
| 1358 | |
| 1359 | |
| 1360 template <typename Scanner, typename Log> | |
| 1361 Identifier PreParser<Scanner, Log>::GetIdentifierSymbol() { | |
| 1362 const char* literal_chars = scanner_->literal_string(); | |
| 1363 int literal_length = scanner_->literal_length(); | |
| 1364 int identifier_pos = scanner_->location().beg_pos; | |
| 1365 | |
| 1366 log_->LogSymbol(identifier_pos, literal_chars, literal_length); | |
| 1367 | |
| 1368 return kUnknownExpression; | |
| 1369 } | |
| 1370 | |
| 1371 | |
| 1372 template <typename Scanner, typename Log> | |
| 1373 Expression PreParser<Scanner, Log>::GetStringSymbol() { | |
| 1374 const char* literal_chars = scanner_->literal_string(); | |
| 1375 int literal_length = scanner_->literal_length(); | |
| 1376 | |
| 1377 int literal_position = scanner_->location().beg_pos; | |
| 1378 log_->LogSymbol(literal_position, literal_chars, literal_length); | |
| 1379 | |
| 1380 return kUnknownExpression; | |
| 1381 } | |
| 1382 | |
| 1383 | |
| 1384 template <typename Scanner, typename Log> | |
| 1385 Identifier PreParser<Scanner, Log>::ParseIdentifier(bool* ok) { | |
| 1386 Expect(Token::IDENTIFIER, ok); | |
| 1387 return GetIdentifierSymbol(); | |
| 1388 } | |
| 1389 | |
| 1390 | |
| 1391 template <typename Scanner, typename Log> | |
| 1392 Identifier PreParser<Scanner, Log>::ParseIdentifierName(bool* ok) { | |
| 1393 Token::Value next = Next(); | |
| 1394 if (Token::IsKeyword(next)) { | |
| 1395 int pos = scanner_->location().beg_pos; | |
| 1396 const char* keyword = Token::String(next); | |
| 1397 log_->LogSymbol(pos, keyword, strlen(keyword)); | |
| 1398 return kUnknownExpression; | |
| 1399 } | |
| 1400 if (next == Token::IDENTIFIER) { | |
| 1401 return GetIdentifierSymbol(); | |
| 1402 } | |
| 1403 *ok = false; | |
| 1404 return kUnknownIdentifier; | |
| 1405 } | |
| 1406 | |
| 1407 | |
| 1408 // This function reads an identifier and determines whether or not it | |
| 1409 // is 'get' or 'set'. The reason for not using ParseIdentifier and | |
| 1410 // checking on the output is that this involves heap allocation which | |
| 1411 // we can't do during preparsing. | |
| 1412 template <typename Scanner, typename Log> | |
| 1413 Identifier PreParser<Scanner, Log>::ParseIdentifierOrGetOrSet(bool* is_get, | |
| 1414 bool* is_set, | |
| 1415 bool* ok) { | |
| 1416 Expect(Token::IDENTIFIER, CHECK_OK); | |
| 1417 if (scanner_->literal_length() == 3) { | |
| 1418 const char* token = scanner_->literal_string(); | |
| 1419 *is_get = strncmp(token, "get", 3) == 0; | |
| 1420 *is_set = !*is_get && strncmp(token, "set", 3) == 0; | |
| 1421 } | |
| 1422 return GetIdentifierSymbol(); | |
| 1423 } | |
| 1424 | |
| 1425 #undef CHECK_OK | |
| 1426 } } } // v8::internal::preparser | |
| 1427 | |
| 1428 #endif // V8_PREPARSER_H | |
| OLD | NEW |