| Index: src/parser.cc
|
| ===================================================================
|
| --- src/parser.cc (revision 7006)
|
| +++ src/parser.cc (working copy)
|
| @@ -622,7 +622,8 @@
|
|
|
|
|
| FunctionLiteral* Parser::ParseProgram(Handle<String> source,
|
| - bool in_global_context) {
|
| + bool in_global_context,
|
| + StrictModeFlag strict_mode) {
|
| CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
|
|
| HistogramTimerScope timer(COUNTERS->parse());
|
| @@ -638,17 +639,18 @@
|
| ExternalTwoByteStringUC16CharacterStream stream(
|
| Handle<ExternalTwoByteString>::cast(source), 0, source->length());
|
| scanner_.Initialize(&stream);
|
| - return DoParseProgram(source, in_global_context, &zone_scope);
|
| + return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
|
| } else {
|
| GenericStringUC16CharacterStream stream(source, 0, source->length());
|
| scanner_.Initialize(&stream);
|
| - return DoParseProgram(source, in_global_context, &zone_scope);
|
| + return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
|
| }
|
| }
|
|
|
|
|
| FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
|
| bool in_global_context,
|
| + StrictModeFlag strict_mode,
|
| ZoneScope* zone_scope) {
|
| ASSERT(target_stack_ == NULL);
|
| if (pre_data_ != NULL) pre_data_->Initialize();
|
| @@ -668,6 +670,9 @@
|
| LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
|
| scope);
|
| TemporaryScope temp_scope(&this->temp_scope_);
|
| + if (strict_mode == kStrictMode) {
|
| + temp_scope.EnableStrictMode();
|
| + }
|
| ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
|
| bool ok = true;
|
| int beg_loc = scanner().location().beg_pos;
|
| @@ -753,14 +758,18 @@
|
| scope);
|
| TemporaryScope temp_scope(&this->temp_scope_);
|
|
|
| + if (info->strict_mode()) {
|
| + temp_scope.EnableStrictMode();
|
| + }
|
| +
|
| FunctionLiteralType type =
|
| info->is_expression() ? EXPRESSION : DECLARATION;
|
| bool ok = true;
|
| - result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok);
|
| + result = ParseFunctionLiteral(name,
|
| + false, // Strict mode name already checked.
|
| + RelocInfo::kNoPosition, type, &ok);
|
| // Make sure the results agree.
|
| ASSERT(ok == (result != NULL));
|
| - // The only errors should be stack overflows.
|
| - ASSERT(ok || stack_overflow_);
|
| }
|
|
|
| // Make sure the target stack is empty.
|
| @@ -769,8 +778,8 @@
|
| // If there was a stack overflow we have to get rid of AST and it is
|
| // not safe to do before scope has been deleted.
|
| if (result == NULL) {
|
| - isolate()->StackOverflow();
|
| zone_scope->DeleteOnExit();
|
| + if (stack_overflow_) isolate()->StackOverflow();
|
| } else {
|
| Handle<String> inferred_name(info->inferred_name());
|
| result->set_inferred_name(inferred_name);
|
| @@ -1446,8 +1455,10 @@
|
| // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
|
| Expect(Token::FUNCTION, CHECK_OK);
|
| int function_token_position = scanner().location().beg_pos;
|
| - Handle<String> name = ParseIdentifier(CHECK_OK);
|
| + bool is_reserved = false;
|
| + Handle<String> name = ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
|
| FunctionLiteral* fun = ParseFunctionLiteral(name,
|
| + is_reserved,
|
| function_token_position,
|
| DECLARATION,
|
| CHECK_OK);
|
| @@ -1706,7 +1717,7 @@
|
| // ExpressionStatement | LabelledStatement ::
|
| // Expression ';'
|
| // Identifier ':' Statement
|
| - bool starts_with_idenfifier = (peek() == Token::IDENTIFIER);
|
| + bool starts_with_idenfifier = peek_any_identifier();
|
| Expression* expr = ParseExpression(true, CHECK_OK);
|
| if (peek() == Token::COLON && starts_with_idenfifier && expr &&
|
| expr->AsVariableProxy() != NULL &&
|
| @@ -2302,6 +2313,11 @@
|
| expression = NewThrowReferenceError(type);
|
| }
|
|
|
| + if (temp_scope_->StrictMode()) {
|
| + // Assignment to eval or arguments is disallowed in strict mode.
|
| + CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
|
| + }
|
| +
|
| Token::Value op = Next(); // Get assignment operator.
|
| int pos = scanner().location().beg_pos;
|
| Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
| @@ -2529,6 +2545,12 @@
|
| isolate()->factory()->invalid_lhs_in_prefix_op_symbol();
|
| expression = NewThrowReferenceError(type);
|
| }
|
| +
|
| + if (temp_scope_->StrictMode()) {
|
| + // Prefix expression operand in strict mode may not be eval or arguments.
|
| + CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
|
| + }
|
| +
|
| int position = scanner().location().beg_pos;
|
| IncrementOperation* increment = new IncrementOperation(op, expression);
|
| return new CountOperation(true /* prefix */, increment, position);
|
| @@ -2555,6 +2577,12 @@
|
| isolate()->factory()->invalid_lhs_in_postfix_op_symbol();
|
| expression = NewThrowReferenceError(type);
|
| }
|
| +
|
| + if (temp_scope_->StrictMode()) {
|
| + // Postfix expression operand in strict mode may not be eval or arguments.
|
| + CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
|
| + }
|
| +
|
| Token::Value next = Next();
|
| int position = scanner().location().beg_pos;
|
| IncrementOperation* increment = new IncrementOperation(next, expression);
|
| @@ -2684,9 +2712,12 @@
|
| Expect(Token::FUNCTION, CHECK_OK);
|
| int function_token_position = scanner().location().beg_pos;
|
| Handle<String> name;
|
| - if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK);
|
| - result = ParseFunctionLiteral(name, function_token_position,
|
| - NESTED, CHECK_OK);
|
| + bool is_reserved_name = false;
|
| + if (peek_any_identifier()) {
|
| + name = ParseIdentifierOrReservedWord(&is_reserved_name, CHECK_OK);
|
| + }
|
| + result = ParseFunctionLiteral(name, is_reserved_name,
|
| + function_token_position, NESTED, CHECK_OK);
|
| } else {
|
| result = ParsePrimaryExpression(CHECK_OK);
|
| }
|
| @@ -2755,6 +2786,11 @@
|
| case Token::IDENTIFIER:
|
| return ReportMessage("unexpected_token_identifier",
|
| Vector<const char*>::empty());
|
| + case Token::FUTURE_RESERVED_WORD:
|
| + return ReportMessage(temp_scope_->StrictMode() ?
|
| + "unexpected_strict_reserved" :
|
| + "unexpected_token_identifier",
|
| + Vector<const char*>::empty());
|
| default:
|
| const char* name = Token::String(token);
|
| ASSERT(name != NULL);
|
| @@ -2810,7 +2846,8 @@
|
| result = new Literal(isolate()->factory()->false_value());
|
| break;
|
|
|
| - case Token::IDENTIFIER: {
|
| + case Token::IDENTIFIER:
|
| + case Token::FUTURE_RESERVED_WORD: {
|
| Handle<String> name = ParseIdentifier(CHECK_OK);
|
| if (fni_ != NULL) fni_->PushVariableName(name);
|
| result = top_scope_->NewUnresolved(name, inside_with());
|
| @@ -3031,7 +3068,7 @@
|
|
|
| // Defined in ast.cc
|
| bool IsEqualString(void* first, void* second);
|
| -bool IsEqualSmi(void* first, void* second);
|
| +bool IsEqualNumber(void* first, void* second);
|
|
|
|
|
| // Validation per 11.1.5 Object Initialiser
|
| @@ -3039,7 +3076,7 @@
|
| public:
|
| ObjectLiteralPropertyChecker(Parser* parser, bool strict) :
|
| props(&IsEqualString),
|
| - elems(&IsEqualSmi),
|
| + elems(&IsEqualNumber),
|
| parser_(parser),
|
| strict_(strict) {
|
| }
|
| @@ -3088,13 +3125,12 @@
|
| uint32_t hash;
|
| HashMap* map;
|
| void* key;
|
| - Smi* smi_key_location;
|
|
|
| if (handle->IsSymbol()) {
|
| Handle<String> name(String::cast(*handle));
|
| if (name->AsArrayIndex(&hash)) {
|
| - smi_key_location = Smi::FromInt(hash);
|
| - key = &smi_key_location;
|
| + Handle<Object> key_handle = FACTORY->NewNumberFromUint(hash);
|
| + key = key_handle.location();
|
| map = &elems;
|
| } else {
|
| key = handle.location();
|
| @@ -3218,6 +3254,7 @@
|
| Token::Value next = Next();
|
| bool is_keyword = Token::IsKeyword(next);
|
| if (next == Token::IDENTIFIER || next == Token::NUMBER ||
|
| + next == Token::FUTURE_RESERVED_WORD ||
|
| next == Token::STRING || is_keyword) {
|
| Handle<String> name;
|
| if (is_keyword) {
|
| @@ -3227,6 +3264,7 @@
|
| }
|
| FunctionLiteral* value =
|
| ParseFunctionLiteral(name,
|
| + false, // reserved words are allowed here
|
| RelocInfo::kNoPosition,
|
| DECLARATION,
|
| CHECK_OK);
|
| @@ -3269,6 +3307,7 @@
|
| Scanner::Location loc = scanner().peek_location();
|
|
|
| switch (next) {
|
| + case Token::FUTURE_RESERVED_WORD:
|
| case Token::IDENTIFIER: {
|
| bool is_getter = false;
|
| bool is_setter = false;
|
| @@ -3417,6 +3456,7 @@
|
|
|
|
|
| FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
|
| + bool name_is_reserved,
|
| int function_token_position,
|
| FunctionLiteralType type,
|
| bool* ok) {
|
| @@ -3451,10 +3491,13 @@
|
| int start_pos = scanner().location().beg_pos;
|
| Scanner::Location name_loc = Scanner::NoLocation();
|
| Scanner::Location dupe_loc = Scanner::NoLocation();
|
| + Scanner::Location reserved_loc = Scanner::NoLocation();
|
|
|
| bool done = (peek() == Token::RPAREN);
|
| while (!done) {
|
| - Handle<String> param_name = ParseIdentifier(CHECK_OK);
|
| + bool is_reserved = false;
|
| + Handle<String> param_name =
|
| + ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
|
|
|
| // Store locations for possible future error reports.
|
| if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
|
| @@ -3463,10 +3506,19 @@
|
| if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
|
| dupe_loc = scanner().location();
|
| }
|
| + if (!reserved_loc.IsValid() && is_reserved) {
|
| + reserved_loc = scanner().location();
|
| + }
|
|
|
| Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR);
|
| top_scope_->AddParameter(parameter);
|
| num_parameters++;
|
| + if (num_parameters > kMaxNumFunctionParameters) {
|
| + ReportMessageAt(scanner().location(), "too_many_parameters",
|
| + Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| done = (peek() == Token::RPAREN);
|
| if (!done) Expect(Token::COMMA, CHECK_OK);
|
| }
|
| @@ -3544,7 +3596,8 @@
|
| int position = function_token_position != RelocInfo::kNoPosition
|
| ? function_token_position
|
| : (start_pos > 0 ? start_pos - 1 : start_pos);
|
| - ReportMessageAt(Scanner::Location(position, start_pos),
|
| + Scanner::Location location = Scanner::Location(position, start_pos);
|
| + ReportMessageAt(location,
|
| "strict_function_name", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -3561,6 +3614,22 @@
|
| *ok = false;
|
| return NULL;
|
| }
|
| + if (name_is_reserved) {
|
| + int position = function_token_position != RelocInfo::kNoPosition
|
| + ? function_token_position
|
| + : (start_pos > 0 ? start_pos - 1 : start_pos);
|
| + Scanner::Location location = Scanner::Location(position, start_pos);
|
| + ReportMessageAt(location, "strict_reserved_word",
|
| + Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| + if (reserved_loc.IsValid()) {
|
| + ReportMessageAt(reserved_loc, "strict_reserved_word",
|
| + Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
|
| }
|
|
|
| @@ -3632,6 +3701,13 @@
|
| }
|
|
|
|
|
| +bool Parser::peek_any_identifier() {
|
| + Token::Value next = peek();
|
| + return next == Token::IDENTIFIER ||
|
| + next == Token::FUTURE_RESERVED_WORD;
|
| +}
|
| +
|
| +
|
| void Parser::Consume(Token::Value token) {
|
| Token::Value next = Next();
|
| USE(next);
|
| @@ -3691,7 +3767,22 @@
|
|
|
|
|
| Handle<String> Parser::ParseIdentifier(bool* ok) {
|
| - Expect(Token::IDENTIFIER, ok);
|
| + bool is_reserved;
|
| + return ParseIdentifierOrReservedWord(&is_reserved, ok);
|
| +}
|
| +
|
| +
|
| +Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
|
| + bool* ok) {
|
| + *is_reserved = false;
|
| + if (temp_scope_->StrictMode()) {
|
| + Expect(Token::IDENTIFIER, ok);
|
| + } else {
|
| + if (!Check(Token::IDENTIFIER)) {
|
| + Expect(Token::FUTURE_RESERVED_WORD, ok);
|
| + *is_reserved = true;
|
| + }
|
| + }
|
| if (!*ok) return Handle<String>();
|
| return GetSymbol(ok);
|
| }
|
| @@ -3699,7 +3790,9 @@
|
|
|
| Handle<String> Parser::ParseIdentifierName(bool* ok) {
|
| Token::Value next = Next();
|
| - if (next != Token::IDENTIFIER && !Token::IsKeyword(next)) {
|
| + if (next != Token::IDENTIFIER &&
|
| + next != Token::FUTURE_RESERVED_WORD &&
|
| + !Token::IsKeyword(next)) {
|
| ReportUnexpectedToken(next);
|
| *ok = false;
|
| return Handle<String>();
|
| @@ -3707,6 +3800,24 @@
|
| return GetSymbol(ok);
|
| }
|
|
|
| +
|
| +// Checks LHS expression for assignment and prefix/postfix increment/decrement
|
| +// in strict mode.
|
| +void Parser::CheckStrictModeLValue(Expression* expression,
|
| + const char* error,
|
| + bool* ok) {
|
| + ASSERT(temp_scope_->StrictMode());
|
| + VariableProxy* lhs = expression != NULL
|
| + ? expression->AsVariableProxy()
|
| + : NULL;
|
| +
|
| + if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
|
| + ReportMessage(error, Vector<const char*>::empty());
|
| + *ok = false;
|
| + }
|
| +}
|
| +
|
| +
|
| // Checks whether octal literal last seen is between beg_pos and end_pos.
|
| // If so, reports an error.
|
| void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
| @@ -3721,20 +3832,18 @@
|
|
|
|
|
| // This function reads an identifier and determines whether or not it
|
| -// is 'get' or 'set'. The reason for not using ParseIdentifier and
|
| -// checking on the output is that this involves heap allocation which
|
| -// we can't do during preparsing.
|
| +// is 'get' or 'set'.
|
| Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
|
| bool* is_set,
|
| bool* ok) {
|
| - Expect(Token::IDENTIFIER, ok);
|
| + Handle<String> result = ParseIdentifier(ok);
|
| if (!*ok) return Handle<String>();
|
| 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 GetSymbol(ok);
|
| + return result;
|
| }
|
|
|
|
|
| @@ -3878,6 +3987,7 @@
|
| message = "unexpected_token_string";
|
| break;
|
| case Token::IDENTIFIER:
|
| + case Token::FUTURE_RESERVED_WORD:
|
| message = "unexpected_token_identifier";
|
| break;
|
| default:
|
| @@ -3928,16 +4038,10 @@
|
| Handle<Object> JsonParser::ParseJsonValue() {
|
| Token::Value token = scanner_.Next();
|
| switch (token) {
|
| - case Token::STRING: {
|
| + case Token::STRING:
|
| return GetString();
|
| - }
|
| - case Token::NUMBER: {
|
| - ASSERT(scanner_.is_literal_ascii());
|
| - double value = StringToDouble(scanner_.literal_ascii_string(),
|
| - NO_FLAGS, // Hex, octal or trailing junk.
|
| - OS::nan_value());
|
| - return isolate()->factory()->NewNumber(value);
|
| - }
|
| + case Token::NUMBER:
|
| + return isolate()->factory()->NewNumber(scanner_.number());
|
| case Token::FALSE_LITERAL:
|
| return isolate()->factory()->false_value();
|
| case Token::TRUE_LITERAL:
|
| @@ -3980,6 +4084,11 @@
|
| uint32_t index;
|
| if (key->AsArrayIndex(&index)) {
|
| SetOwnElement(json_object, index, value);
|
| + } else if (key->Equals(isolate()->heap()->Proto_symbol())) {
|
| + // We can't remove the __proto__ accessor since it's hardcoded
|
| + // in several places. Instead go along and add the value as
|
| + // the prototype of the created object if possible.
|
| + SetPrototype(json_object, value);
|
| } else {
|
| SetLocalPropertyIgnoreAttributes(json_object, key, value, NONE);
|
| }
|
| @@ -4991,7 +5100,9 @@
|
| ASSERT(info->isolate()->has_pending_exception());
|
| } else {
|
| Handle<String> source = Handle<String>(String::cast(script->source()));
|
| - result = parser.ParseProgram(source, info->is_global());
|
| + result = parser.ParseProgram(source,
|
| + info->is_global(),
|
| + info->StrictMode());
|
| }
|
| }
|
|
|
|
|