| Index: src/preparser.cc
|
| diff --git a/src/preparser.cc b/src/preparser.cc
|
| index a5de23ebeede10d2b59726f32d0294f6403555f1..fa6f217993e1619fc10e0861ed578550f6a5b788 100644
|
| --- a/src/preparser.cc
|
| +++ b/src/preparser.cc
|
| @@ -55,99 +55,14 @@ int isfinite(double value);
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -void PreParserTraits::ReportMessageAt(Scanner::Location location,
|
| - const char* message,
|
| - Vector<const char*> args) {
|
| - ReportMessageAt(location.beg_pos,
|
| - location.end_pos,
|
| - message,
|
| - args.length() > 0 ? args[0] : NULL);
|
| -}
|
| -
|
| -
|
| -void PreParserTraits::ReportMessageAt(Scanner::Location location,
|
| - const char* type,
|
| - const char* name_opt) {
|
| - pre_parser_->log_
|
| - ->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
| -}
|
| -
|
| -
|
| -void PreParserTraits::ReportMessageAt(int start_pos,
|
| - int end_pos,
|
| - const char* type,
|
| - const char* name_opt) {
|
| - pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt);
|
| -}
|
| -
|
| -
|
| -PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
| - pre_parser_->LogSymbol();
|
| - if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
|
| - return PreParserIdentifier::FutureReserved();
|
| - } else if (scanner->current_token() ==
|
| - Token::FUTURE_STRICT_RESERVED_WORD) {
|
| - return PreParserIdentifier::FutureStrictReserved();
|
| - } else if (scanner->current_token() == Token::YIELD) {
|
| - return PreParserIdentifier::Yield();
|
| - }
|
| - if (scanner->is_literal_ascii()) {
|
| - // Detect strict-mode poison words.
|
| - if (scanner->literal_length() == 4 &&
|
| - !strncmp(scanner->literal_ascii_string().start(), "eval", 4)) {
|
| - return PreParserIdentifier::Eval();
|
| - }
|
| - if (scanner->literal_length() == 9 &&
|
| - !strncmp(scanner->literal_ascii_string().start(), "arguments", 9)) {
|
| - return PreParserIdentifier::Arguments();
|
| - }
|
| - }
|
| - return PreParserIdentifier::Default();
|
| -}
|
| -
|
| -
|
| -PreParserExpression PreParserTraits::ExpressionFromString(
|
| - int pos, Scanner* scanner, PreParserFactory* factory) {
|
| - const int kUseStrictLength = 10;
|
| - const char* kUseStrictChars = "use strict";
|
| - pre_parser_->LogSymbol();
|
| - if (scanner->is_literal_ascii() &&
|
| - scanner->literal_length() == kUseStrictLength &&
|
| - !scanner->literal_contains_escapes() &&
|
| - !strncmp(scanner->literal_ascii_string().start(), kUseStrictChars,
|
| - kUseStrictLength)) {
|
| - return PreParserExpression::UseStrictStringLiteral();
|
| - }
|
| - return PreParserExpression::StringLiteral();
|
| -}
|
| -
|
| -
|
| -PreParserExpression PreParserTraits::ParseObjectLiteral(bool* ok) {
|
| - return pre_parser_->ParseObjectLiteral(ok);
|
| -}
|
| -
|
| -
|
| -PreParserExpression PreParserTraits::ParseAssignmentExpression(bool accept_IN,
|
| - bool* ok) {
|
| - return pre_parser_->ParseAssignmentExpression(accept_IN, ok);
|
| -}
|
| -
|
| -
|
| -PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
|
| - return pre_parser_->ParseV8Intrinsic(ok);
|
| -}
|
| -
|
| -
|
| PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
| LanguageMode mode, bool is_generator, ParserRecorder* log) {
|
| log_ = log;
|
| // Lazy functions always have trivial outer scopes (no with/catch scopes).
|
| - PreParserScope top_scope(scope_, GLOBAL_SCOPE);
|
| - FunctionState top_state(&function_state_, &scope_, &top_scope);
|
| - scope_->SetLanguageMode(mode);
|
| - PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
| - FunctionState function_state(&function_state_, &scope_, &function_scope);
|
| - function_state.set_is_generator(is_generator);
|
| + Scope top_scope(&scope_, kTopLevelScope);
|
| + set_language_mode(mode);
|
| + Scope function_scope(&scope_, kFunctionScope);
|
| + function_scope.set_is_generator(is_generator);
|
| ASSERT_EQ(Token::LBRACE, scanner()->current_token());
|
| bool ok = true;
|
| int start_position = peek_position();
|
| @@ -224,8 +139,8 @@ PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
|
| Statement statement = ParseSourceElement(CHECK_OK);
|
| if (directive_prologue) {
|
| if (statement.IsUseStrictLiteral()) {
|
| - scope_->SetLanguageMode(allow_harmony_scoping() ?
|
| - EXTENDED_MODE : STRICT_MODE);
|
| + set_language_mode(allow_harmony_scoping() ?
|
| + EXTENDED_MODE : STRICT_MODE);
|
| } else if (!statement.IsStringLiteral()) {
|
| directive_prologue = false;
|
| }
|
| @@ -320,10 +235,8 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
|
| Statement statement = ParseFunctionDeclaration(CHECK_OK);
|
| Scanner::Location end_location = scanner()->location();
|
| if (!scope_->is_classic_mode()) {
|
| - PreParserTraits::ReportMessageAt(start_location.beg_pos,
|
| - end_location.end_pos,
|
| - "strict_function",
|
| - NULL);
|
| + ReportMessageAt(start_location.beg_pos, end_location.end_pos,
|
| + "strict_function", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| } else {
|
| @@ -370,7 +283,7 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
|
| //
|
| Expect(Token::LBRACE, CHECK_OK);
|
| while (peek() != Token::RBRACE) {
|
| - if (scope_->is_extended_mode()) {
|
| + if (is_extended_mode()) {
|
| ParseSourceElement(CHECK_OK);
|
| } else {
|
| ParseStatement(CHECK_OK);
|
| @@ -434,19 +347,21 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| // existing pages. Therefore we keep allowing const with the old
|
| // non-harmony semantics in classic mode.
|
| Consume(Token::CONST);
|
| - switch (scope_->language_mode()) {
|
| + switch (language_mode()) {
|
| case CLASSIC_MODE:
|
| break;
|
| case STRICT_MODE: {
|
| Scanner::Location location = scanner()->peek_location();
|
| - ReportMessageAt(location, "strict_const");
|
| + ReportMessageAt(location, "strict_const", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| case EXTENDED_MODE:
|
| if (var_context != kSourceElement &&
|
| var_context != kForStatement) {
|
| - ReportMessageAt(scanner()->peek_location(), "unprotected_const");
|
| + Scanner::Location location = scanner()->peek_location();
|
| + ReportMessageAt(location.beg_pos, location.end_pos,
|
| + "unprotected_const", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| @@ -460,15 +375,19 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
|
| //
|
| // * It is a Syntax Error if the code that matches this production is not
|
| // contained in extended code.
|
| - if (!scope_->is_extended_mode()) {
|
| - ReportMessageAt(scanner()->peek_location(), "illegal_let");
|
| + if (!is_extended_mode()) {
|
| + Scanner::Location location = scanner()->peek_location();
|
| + ReportMessageAt(location.beg_pos, location.end_pos,
|
| + "illegal_let", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| Consume(Token::LET);
|
| if (var_context != kSourceElement &&
|
| var_context != kForStatement) {
|
| - ReportMessageAt(scanner()->peek_location(), "unprotected_let");
|
| + Scanner::Location location = scanner()->peek_location();
|
| + ReportMessageAt(location.beg_pos, location.end_pos,
|
| + "unprotected_let", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| @@ -612,7 +531,8 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
|
| // 'with' '(' Expression ')' Statement
|
| Expect(Token::WITH, CHECK_OK);
|
| if (!scope_->is_classic_mode()) {
|
| - ReportMessageAt(scanner()->location(), "strict_mode_with");
|
| + Scanner::Location location = scanner()->location();
|
| + ReportMessageAt(location, "strict_mode_with", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| @@ -620,8 +540,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
|
| ParseExpression(true, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| - PreParserScope with_scope(scope_, WITH_SCOPE);
|
| - BlockState block_state(&scope_, &with_scope);
|
| + Scope::InsideWith iw(scope_);
|
| ParseStatement(CHECK_OK);
|
| return Statement::Default();
|
| }
|
| @@ -757,7 +676,8 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
|
|
|
| Expect(Token::THROW, CHECK_OK);
|
| if (scanner()->HasAnyLineTerminatorBeforeNext()) {
|
| - ReportMessageAt(scanner()->location(), "newline_after_throw");
|
| + Scanner::Location pos = scanner()->location();
|
| + ReportMessageAt(pos, "newline_after_throw", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| @@ -785,7 +705,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
|
|
|
| Token::Value tok = peek();
|
| if (tok != Token::CATCH && tok != Token::FINALLY) {
|
| - ReportMessageAt(scanner()->location(), "no_catch_or_finally");
|
| + ReportMessageAt(scanner()->location(), "no_catch_or_finally", NULL);
|
| *ok = false;
|
| return Statement::Default();
|
| }
|
| @@ -794,9 +714,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
|
| Expect(Token::LPAREN, CHECK_OK);
|
| ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| Expect(Token::RPAREN, CHECK_OK);
|
| - {
|
| - PreParserScope with_scope(scope_, WITH_SCOPE);
|
| - BlockState block_state(&scope_, &with_scope);
|
| + { Scope::InsideWith iw(scope_);
|
| ParseBlock(CHECK_OK);
|
| }
|
| tok = peek();
|
| @@ -830,6 +748,22 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
|
| #undef DUMMY
|
|
|
|
|
| +// Precedence = 1
|
| +PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
|
| + // Expression ::
|
| + // AssignmentExpression
|
| + // Expression ',' AssignmentExpression
|
| +
|
| + Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
| + while (peek() == Token::COMMA) {
|
| + Expect(Token::COMMA, CHECK_OK);
|
| + ParseAssignmentExpression(accept_IN, CHECK_OK);
|
| + result = Expression::Default();
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| // Precedence = 2
|
| PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
|
| bool* ok) {
|
| @@ -838,7 +772,7 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
|
| // YieldExpression
|
| // LeftHandSideExpression AssignmentOperator AssignmentExpression
|
|
|
| - if (function_state_->is_generator() && peek() == Token::YIELD) {
|
| + if (scope_->is_generator() && peek() == Token::YIELD) {
|
| return ParseYieldExpression(ok);
|
| }
|
|
|
| @@ -854,8 +788,8 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
|
| expression.IsIdentifier() &&
|
| expression.AsIdentifier().IsEvalOrArguments()) {
|
| Scanner::Location after = scanner()->location();
|
| - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
|
| - "strict_eval_arguments", NULL);
|
| + ReportMessageAt(before.beg_pos, after.end_pos,
|
| + "strict_eval_arguments", NULL);
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| @@ -864,7 +798,7 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
|
| ParseAssignmentExpression(accept_IN, CHECK_OK);
|
|
|
| if ((op == Token::ASSIGN) && expression.IsThisProperty()) {
|
| - function_state_->AddProperty();
|
| + scope_->AddProperty();
|
| }
|
|
|
| return Expression::Default();
|
| @@ -948,8 +882,8 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
|
| expression.IsIdentifier() &&
|
| expression.AsIdentifier().IsEvalOrArguments()) {
|
| Scanner::Location after = scanner()->location();
|
| - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
|
| - "strict_eval_arguments", NULL);
|
| + ReportMessageAt(before.beg_pos, after.end_pos,
|
| + "strict_eval_arguments", NULL);
|
| *ok = false;
|
| }
|
| return Expression::Default();
|
| @@ -971,8 +905,8 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
|
| expression.IsIdentifier() &&
|
| expression.AsIdentifier().IsEvalOrArguments()) {
|
| Scanner::Location after = scanner()->location();
|
| - PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
|
| - "strict_eval_arguments", NULL);
|
| + ReportMessageAt(before.beg_pos, after.end_pos,
|
| + "strict_eval_arguments", NULL);
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| @@ -987,7 +921,12 @@ PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
|
| // LeftHandSideExpression ::
|
| // (NewExpression | MemberExpression) ...
|
|
|
| - Expression result = ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
| + Expression result = Expression::Default();
|
| + if (peek() == Token::NEW) {
|
| + result = ParseNewExpression(CHECK_OK);
|
| + } else {
|
| + result = ParseMemberExpression(CHECK_OK);
|
| + }
|
|
|
| while (true) {
|
| switch (peek()) {
|
| @@ -1027,38 +966,39 @@ PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
|
| }
|
|
|
|
|
| -PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
|
| - bool* ok) {
|
| +PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
|
| // NewExpression ::
|
| // ('new')+ MemberExpression
|
|
|
| - // See Parser::ParseNewExpression.
|
| -
|
| - if (peek() == Token::NEW) {
|
| + // The grammar for new expressions is pretty warped. The keyword
|
| + // 'new' can either be a part of the new expression (where it isn't
|
| + // followed by an argument list) or a part of the member expression,
|
| + // where it must be followed by an argument list. To accommodate
|
| + // this, we parse the 'new' keywords greedily and keep track of how
|
| + // many we have parsed. This information is then passed on to the
|
| + // member expression parser, which is only allowed to match argument
|
| + // lists as long as it has 'new' prefixes left
|
| + unsigned new_count = 0;
|
| + do {
|
| Consume(Token::NEW);
|
| - ParseMemberWithNewPrefixesExpression(CHECK_OK);
|
| - if (peek() == Token::LPAREN) {
|
| - // NewExpression with arguments.
|
| - ParseArguments(CHECK_OK);
|
| - // The expression can still continue with . or [ after the arguments.
|
| - ParseMemberExpressionContinuation(Expression::Default(), CHECK_OK);
|
| - }
|
| - return Expression::Default();
|
| - }
|
| - // No 'new' keyword.
|
| - return ParseMemberExpression(ok);
|
| + new_count++;
|
| + } while (peek() == Token::NEW);
|
| +
|
| + return ParseMemberWithNewPrefixesExpression(new_count, ok);
|
| }
|
|
|
|
|
| PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
|
| + return ParseMemberWithNewPrefixesExpression(0, ok);
|
| +}
|
| +
|
| +
|
| +PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
|
| + unsigned new_count, bool* ok) {
|
| // MemberExpression ::
|
| // (PrimaryExpression | FunctionLiteral)
|
| // ('[' Expression ']' | '.' Identifier | Arguments)*
|
|
|
| - // The '[' Expression ']' and '.' Identifier parts are parsed by
|
| - // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
|
| - // caller.
|
| -
|
| // Parse the initial primary or function expression.
|
| Expression result = Expression::Default();
|
| if (peek() == Token::FUNCTION) {
|
| @@ -1081,44 +1021,145 @@ PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
|
| } else {
|
| result = ParsePrimaryExpression(CHECK_OK);
|
| }
|
| - result = ParseMemberExpressionContinuation(result, CHECK_OK);
|
| - return result;
|
| -}
|
|
|
| -
|
| -PreParser::Expression PreParser::ParseMemberExpressionContinuation(
|
| - PreParserExpression expression, bool* ok) {
|
| - // Parses this part of MemberExpression:
|
| - // ('[' Expression ']' | '.' Identifier)*
|
| while (true) {
|
| switch (peek()) {
|
| case Token::LBRACK: {
|
| Consume(Token::LBRACK);
|
| ParseExpression(true, CHECK_OK);
|
| Expect(Token::RBRACK, CHECK_OK);
|
| - if (expression.IsThis()) {
|
| - expression = Expression::ThisProperty();
|
| + if (result.IsThis()) {
|
| + result = Expression::ThisProperty();
|
| } else {
|
| - expression = Expression::Default();
|
| + result = Expression::Default();
|
| }
|
| break;
|
| }
|
| case Token::PERIOD: {
|
| Consume(Token::PERIOD);
|
| ParseIdentifierName(CHECK_OK);
|
| - if (expression.IsThis()) {
|
| - expression = Expression::ThisProperty();
|
| + if (result.IsThis()) {
|
| + result = Expression::ThisProperty();
|
| } else {
|
| - expression = Expression::Default();
|
| + result = Expression::Default();
|
| }
|
| break;
|
| }
|
| + case Token::LPAREN: {
|
| + if (new_count == 0) return result;
|
| + // Consume one of the new prefixes (already parsed).
|
| + ParseArguments(CHECK_OK);
|
| + new_count--;
|
| + result = Expression::Default();
|
| + break;
|
| + }
|
| default:
|
| - return expression;
|
| + return result;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
|
| + // PrimaryExpression ::
|
| + // 'this'
|
| + // 'null'
|
| + // 'true'
|
| + // 'false'
|
| + // Identifier
|
| + // Number
|
| + // String
|
| + // ArrayLiteral
|
| + // ObjectLiteral
|
| + // RegExpLiteral
|
| + // '(' Expression ')'
|
| +
|
| + Expression result = Expression::Default();
|
| + switch (peek()) {
|
| + case Token::THIS: {
|
| + Next();
|
| + result = Expression::This();
|
| + break;
|
| + }
|
| +
|
| + case Token::FUTURE_RESERVED_WORD:
|
| + case Token::FUTURE_STRICT_RESERVED_WORD:
|
| + case Token::YIELD:
|
| + case Token::IDENTIFIER: {
|
| + // Using eval or arguments in this context is OK even in strict mode.
|
| + Identifier id = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
| + result = Expression::FromIdentifier(id);
|
| + break;
|
| + }
|
| +
|
| + case Token::NULL_LITERAL:
|
| + case Token::TRUE_LITERAL:
|
| + case Token::FALSE_LITERAL:
|
| + case Token::NUMBER: {
|
| + Next();
|
| + break;
|
| + }
|
| + case Token::STRING: {
|
| + Next();
|
| + result = GetStringSymbol();
|
| + break;
|
| + }
|
| +
|
| + case Token::ASSIGN_DIV:
|
| + result = ParseRegExpLiteral(true, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::DIV:
|
| + result = ParseRegExpLiteral(false, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LBRACK:
|
| + result = ParseArrayLiteral(CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LBRACE:
|
| + result = ParseObjectLiteral(CHECK_OK);
|
| + break;
|
| +
|
| + case Token::LPAREN:
|
| + Consume(Token::LPAREN);
|
| + parenthesized_function_ = (peek() == Token::FUNCTION);
|
| + result = ParseExpression(true, CHECK_OK);
|
| + Expect(Token::RPAREN, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::MOD:
|
| + result = ParseV8Intrinsic(CHECK_OK);
|
| + break;
|
| +
|
| + default: {
|
| + Token::Value next = Next();
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return Expression::Default();
|
| + }
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| +PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
|
| + // ArrayLiteral ::
|
| + // '[' Expression? (',' Expression?)* ']'
|
| + Expect(Token::LBRACK, CHECK_OK);
|
| + while (peek() != Token::RBRACK) {
|
| + if (peek() != Token::COMMA) {
|
| + ParseAssignmentExpression(true, CHECK_OK);
|
| + }
|
| + if (peek() != Token::RBRACK) {
|
| + Expect(Token::COMMA, CHECK_OK);
|
| }
|
| }
|
| - ASSERT(false);
|
| - return PreParserExpression::Default();
|
| + Expect(Token::RBRACK, CHECK_OK);
|
| +
|
| + scope_->NextMaterializedLiteralIndex();
|
| + return Expression::Default();
|
| }
|
|
|
|
|
| @@ -1129,7 +1170,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
| // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
|
| // )*[','] '}'
|
|
|
| - ObjectLiteralChecker checker(this, scope_->language_mode());
|
| + ObjectLiteralChecker checker(this, language_mode());
|
|
|
| Expect(Token::LBRACE, CHECK_OK);
|
| while (peek() != Token::RBRACE) {
|
| @@ -1174,7 +1215,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
| case Token::STRING:
|
| Consume(next);
|
| checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
| - LogSymbol();
|
| + GetStringSymbol();
|
| break;
|
| case Token::NUMBER:
|
| Consume(next);
|
| @@ -1184,7 +1225,6 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
| if (Token::IsKeyword(next)) {
|
| Consume(next);
|
| checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
| - LogSymbol();
|
| } else {
|
| // Unexpected token.
|
| *ok = false;
|
| @@ -1200,7 +1240,29 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
| }
|
| Expect(Token::RBRACE, CHECK_OK);
|
|
|
| - function_state_->NextMaterializedLiteralIndex();
|
| + scope_->NextMaterializedLiteralIndex();
|
| + return Expression::Default();
|
| +}
|
| +
|
| +
|
| +PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
|
| + bool* ok) {
|
| + if (!scanner()->ScanRegExpPattern(seen_equal)) {
|
| + Next();
|
| + ReportMessageAt(scanner()->location(), "unterminated_regexp", NULL);
|
| + *ok = false;
|
| + return Expression::Default();
|
| + }
|
| +
|
| + scope_->NextMaterializedLiteralIndex();
|
| +
|
| + if (!scanner()->ScanRegExpFlags()) {
|
| + Next();
|
| + ReportMessageAt(scanner()->location(), "invalid_regexp_flags", NULL);
|
| + *ok = false;
|
| + return Expression::Default();
|
| + }
|
| + Next();
|
| return Expression::Default();
|
| }
|
|
|
| @@ -1238,10 +1300,9 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|
|
| // Parse function body.
|
| ScopeType outer_scope_type = scope_->type();
|
| - bool inside_with = scope_->inside_with();
|
| - PreParserScope function_scope(scope_, FUNCTION_SCOPE);
|
| - FunctionState function_state(&function_state_, &scope_, &function_scope);
|
| - function_state.set_is_generator(is_generator);
|
| + bool inside_with = scope_->IsInsideWith();
|
| + Scope function_scope(&scope_, kFunctionScope);
|
| + function_scope.set_is_generator(is_generator);
|
| // FormalParameterList ::
|
| // '(' (Identifier)*[','] ')'
|
| Expect(Token::LPAREN, CHECK_OK);
|
| @@ -1285,15 +1346,16 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
| }
|
| Expect(Token::RPAREN, CHECK_OK);
|
|
|
| - // See Parser::ParseFunctionLiteral for more information about lazy parsing
|
| - // and lazy compilation.
|
| - bool is_lazily_parsed = (outer_scope_type == GLOBAL_SCOPE &&
|
| - !inside_with && allow_lazy() &&
|
| - !parenthesized_function_);
|
| + // Determine if the function will be lazily compiled.
|
| + // Currently only happens to top-level functions.
|
| + // Optimistically assume that all top-level functions are lazily compiled.
|
| + bool is_lazily_compiled = (outer_scope_type == kTopLevelScope &&
|
| + !inside_with && allow_lazy() &&
|
| + !parenthesized_function_);
|
| parenthesized_function_ = false;
|
|
|
| Expect(Token::LBRACE, CHECK_OK);
|
| - if (is_lazily_parsed) {
|
| + if (is_lazily_compiled) {
|
| ParseLazyFunctionLiteralBody(CHECK_OK);
|
| } else {
|
| ParseSourceElements(Token::RBRACE, ok);
|
| @@ -1304,27 +1366,31 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
| // since the function can declare itself strict.
|
| if (!scope_->is_classic_mode()) {
|
| if (function_name.IsEvalOrArguments()) {
|
| - ReportMessageAt(function_name_location, "strict_eval_arguments");
|
| + ReportMessageAt(function_name_location, "strict_eval_arguments", NULL);
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| if (name_is_strict_reserved) {
|
| - ReportMessageAt(function_name_location, "unexpected_strict_reserved");
|
| + ReportMessageAt(
|
| + function_name_location, "unexpected_strict_reserved", NULL);
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| if (eval_args_error_loc.IsValid()) {
|
| - ReportMessageAt(eval_args_error_loc, "strict_eval_arguments");
|
| + ReportMessageAt(eval_args_error_loc, "strict_eval_arguments",
|
| + Vector<const char*>::empty());
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| if (dupe_error_loc.IsValid()) {
|
| - ReportMessageAt(dupe_error_loc, "strict_param_dupe");
|
| + ReportMessageAt(dupe_error_loc, "strict_param_dupe",
|
| + Vector<const char*>::empty());
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| if (reserved_error_loc.IsValid()) {
|
| - ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved");
|
| + ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved",
|
| + Vector<const char*>::empty());
|
| *ok = false;
|
| return Expression::Default();
|
| }
|
| @@ -1349,9 +1415,9 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
|
| ASSERT_EQ(Token::RBRACE, scanner()->peek());
|
| int body_end = scanner()->peek_location().end_pos;
|
| log_->LogFunction(body_start, body_end,
|
| - function_state_->materialized_literal_count(),
|
| - function_state_->expected_property_count(),
|
| - scope_->language_mode());
|
| + scope_->materialized_literal_count(),
|
| + scope_->expected_properties(),
|
| + language_mode());
|
| }
|
|
|
|
|
| @@ -1383,4 +1449,157 @@ void PreParser::LogSymbol() {
|
| }
|
|
|
|
|
| +PreParser::Expression PreParser::GetStringSymbol() {
|
| + const int kUseStrictLength = 10;
|
| + const char* kUseStrictChars = "use strict";
|
| + LogSymbol();
|
| + if (scanner()->is_literal_ascii() &&
|
| + scanner()->literal_length() == kUseStrictLength &&
|
| + !scanner()->literal_contains_escapes() &&
|
| + !strncmp(scanner()->literal_ascii_string().start(), kUseStrictChars,
|
| + kUseStrictLength)) {
|
| + return Expression::UseStrictStringLiteral();
|
| + }
|
| + return Expression::StringLiteral();
|
| +}
|
| +
|
| +
|
| +PreParser::Identifier PreParser::GetIdentifierSymbol() {
|
| + LogSymbol();
|
| + if (scanner()->current_token() == Token::FUTURE_RESERVED_WORD) {
|
| + return Identifier::FutureReserved();
|
| + } else if (scanner()->current_token() ==
|
| + Token::FUTURE_STRICT_RESERVED_WORD) {
|
| + return Identifier::FutureStrictReserved();
|
| + } else if (scanner()->current_token() == Token::YIELD) {
|
| + return Identifier::Yield();
|
| + }
|
| + if (scanner()->is_literal_ascii()) {
|
| + // Detect strict-mode poison words.
|
| + if (scanner()->literal_length() == 4 &&
|
| + !strncmp(scanner()->literal_ascii_string().start(), "eval", 4)) {
|
| + return Identifier::Eval();
|
| + }
|
| + if (scanner()->literal_length() == 9 &&
|
| + !strncmp(scanner()->literal_ascii_string().start(), "arguments", 9)) {
|
| + return Identifier::Arguments();
|
| + }
|
| + }
|
| + return Identifier::Default();
|
| +}
|
| +
|
| +
|
| +// Parses an identifier that is valid for the current scope, in particular it
|
| +// fails on strict mode future reserved keywords in a strict scope. If
|
| +// allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
|
| +// "arguments" as identifier even in strict mode (this is needed in cases like
|
| +// "var foo = eval;").
|
| +PreParser::Identifier PreParser::ParseIdentifier(
|
| + AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
|
| + bool* ok) {
|
| + Token::Value next = Next();
|
| + if (next == Token::IDENTIFIER) {
|
| + PreParser::Identifier name = GetIdentifierSymbol();
|
| + if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
|
| + !scope_->is_classic_mode() && name.IsEvalOrArguments()) {
|
| + ReportMessageAt(scanner()->location(), "strict_eval_arguments", NULL);
|
| + *ok = false;
|
| + }
|
| + return name;
|
| + } else if (scope_->is_classic_mode() &&
|
| + (next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
| + (next == Token::YIELD && !scope_->is_generator()))) {
|
| + return GetIdentifierSymbol();
|
| + } else {
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return Identifier::Default();
|
| + }
|
| +}
|
| +
|
| +
|
| +// Parses and identifier or a strict mode future reserved word, and indicate
|
| +// whether it is strict mode future reserved.
|
| +PreParser::Identifier PreParser::ParseIdentifierOrStrictReservedWord(
|
| + bool* is_strict_reserved, bool* ok) {
|
| + Token::Value next = Next();
|
| + if (next == Token::IDENTIFIER) {
|
| + *is_strict_reserved = false;
|
| + } else if (next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
| + (next == Token::YIELD && !scope_->is_generator())) {
|
| + *is_strict_reserved = true;
|
| + } else {
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return Identifier::Default();
|
| + }
|
| + return GetIdentifierSymbol();
|
| +}
|
| +
|
| +
|
| +PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
|
| + Token::Value next = Next();
|
| + if (next != Token::IDENTIFIER &&
|
| + next != Token::FUTURE_RESERVED_WORD &&
|
| + next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
| + !Token::IsKeyword(next)) {
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + return Identifier::Default();
|
| + }
|
| + return GetIdentifierSymbol();
|
| +}
|
| +
|
| +#undef CHECK_OK
|
| +
|
| +
|
| +// This function reads an identifier and determines whether or not it
|
| +// is 'get' or 'set'.
|
| +PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
|
| + bool* is_set,
|
| + bool* ok) {
|
| + Identifier result = ParseIdentifierName(ok);
|
| + if (!*ok) return Identifier::Default();
|
| + if (scanner()->is_literal_ascii() &&
|
| + scanner()->literal_length() == 3) {
|
| + const char* token = scanner()->literal_ascii_string().start();
|
| + *is_get = strncmp(token, "get", 3) == 0;
|
| + *is_set = !*is_get && strncmp(token, "set", 3) == 0;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +void PreParser::ObjectLiteralChecker::CheckProperty(Token::Value property,
|
| + PropertyKind type,
|
| + bool* ok) {
|
| + int old;
|
| + if (property == Token::NUMBER) {
|
| + old = finder_.AddNumber(scanner()->literal_ascii_string(), type);
|
| + } else if (scanner()->is_literal_ascii()) {
|
| + old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type);
|
| + } else {
|
| + old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type);
|
| + }
|
| + PropertyKind old_type = static_cast<PropertyKind>(old);
|
| + if (HasConflict(old_type, type)) {
|
| + if (IsDataDataConflict(old_type, type)) {
|
| + // Both are data properties.
|
| + if (language_mode_ == CLASSIC_MODE) return;
|
| + parser()->ReportMessageAt(scanner()->location(),
|
| + "strict_duplicate_property");
|
| + } else if (IsDataAccessorConflict(old_type, type)) {
|
| + // Both a data and an accessor property with the same name.
|
| + parser()->ReportMessageAt(scanner()->location(),
|
| + "accessor_data_property");
|
| + } else {
|
| + ASSERT(IsAccessorAccessorConflict(old_type, type));
|
| + // Both accessors of the same type.
|
| + parser()->ReportMessageAt(scanner()->location(),
|
| + "accessor_get_set");
|
| + }
|
| + *ok = false;
|
| + }
|
| +}
|
| +
|
| } } // v8::internal
|
|
|