| Index: src/parser.cc
|
| ===================================================================
|
| --- src/parser.cc (revision 7180)
|
| +++ src/parser.cc (working copy)
|
| @@ -283,11 +283,6 @@
|
| void AddLoop() { loop_count_++; }
|
| bool ContainsLoops() const { return loop_count_ > 0; }
|
|
|
| - bool StrictMode() { return strict_mode_; }
|
| - void EnableStrictMode() {
|
| - strict_mode_ = FLAG_strict_mode;
|
| - }
|
| -
|
| private:
|
| // Captures the number of literals that need materialization in the
|
| // function. Includes regexp literals, and boilerplate for object
|
| @@ -305,9 +300,6 @@
|
| // Captures the number of loops inside the scope.
|
| int loop_count_;
|
|
|
| - // Parsing strict mode code.
|
| - bool strict_mode_;
|
| -
|
| // Bookkeeping
|
| TemporaryScope** variable_;
|
| TemporaryScope* parent_;
|
| @@ -322,8 +314,6 @@
|
| loop_count_(0),
|
| variable_(variable),
|
| parent_(*variable) {
|
| - // Inherit the strict mode from the parent scope.
|
| - strict_mode_ = (parent_ != NULL) && parent_->strict_mode_;
|
| *variable = this;
|
| }
|
|
|
| @@ -665,13 +655,13 @@
|
| scope);
|
| TemporaryScope temp_scope(&this->temp_scope_);
|
| if (strict_mode == kStrictMode) {
|
| - temp_scope.EnableStrictMode();
|
| + top_scope_->EnableStrictMode();
|
| }
|
| ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
|
| bool ok = true;
|
| int beg_loc = scanner().location().beg_pos;
|
| ParseSourceElements(body, Token::EOS, &ok);
|
| - if (ok && temp_scope_->StrictMode()) {
|
| + if (ok && top_scope_->is_strict_mode()) {
|
| CheckOctalLiteral(beg_loc, scanner().location().end_pos, &ok);
|
| }
|
| if (ok) {
|
| @@ -687,8 +677,7 @@
|
| 0,
|
| source->length(),
|
| false,
|
| - temp_scope.ContainsLoops(),
|
| - temp_scope.StrictMode());
|
| + temp_scope.ContainsLoops());
|
| } else if (stack_overflow_) {
|
| Top::StackOverflow();
|
| }
|
| @@ -703,38 +692,40 @@
|
| return result;
|
| }
|
|
|
| -FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
|
| +FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
|
| CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
|
| HistogramTimerScope timer(&Counters::parse_lazy);
|
| Handle<String> source(String::cast(script_->source()));
|
| Counters::total_parse_size.Increment(source->length());
|
|
|
| + Handle<SharedFunctionInfo> shared_info = info->shared_info();
|
| // Initialize parser state.
|
| source->TryFlatten();
|
| if (source->IsExternalTwoByteString()) {
|
| ExternalTwoByteStringUC16CharacterStream stream(
|
| Handle<ExternalTwoByteString>::cast(source),
|
| - info->start_position(),
|
| - info->end_position());
|
| + shared_info->start_position(),
|
| + shared_info->end_position());
|
| FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
|
| return result;
|
| } else {
|
| GenericStringUC16CharacterStream stream(source,
|
| - info->start_position(),
|
| - info->end_position());
|
| + shared_info->start_position(),
|
| + shared_info->end_position());
|
| FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
|
| return result;
|
| }
|
| }
|
|
|
|
|
| -FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info,
|
| +FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
|
| UC16CharacterStream* source,
|
| ZoneScope* zone_scope) {
|
| + Handle<SharedFunctionInfo> shared_info = info->shared_info();
|
| scanner_.Initialize(source);
|
| ASSERT(target_stack_ == NULL);
|
|
|
| - Handle<String> name(String::cast(info->name()));
|
| + Handle<String> name(String::cast(shared_info->name()));
|
| fni_ = new FuncNameInferrer();
|
| fni_->PushEnclosingName(name);
|
|
|
| @@ -746,18 +737,20 @@
|
| {
|
| // Parse the function literal.
|
| Handle<String> no_name = Factory::empty_symbol();
|
| - Scope* scope =
|
| - NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
|
| + Scope* scope = NewScope(top_scope_, Scope::GLOBAL_SCOPE, inside_with());
|
| + if (!info->closure().is_null()) {
|
| + scope = Scope::DeserializeScopeChain(info, scope);
|
| + }
|
| LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
|
| scope);
|
| TemporaryScope temp_scope(&this->temp_scope_);
|
|
|
| - if (info->strict_mode()) {
|
| - temp_scope.EnableStrictMode();
|
| + if (shared_info->strict_mode()) {
|
| + top_scope_->EnableStrictMode();
|
| }
|
|
|
| FunctionLiteralType type =
|
| - info->is_expression() ? EXPRESSION : DECLARATION;
|
| + shared_info->is_expression() ? EXPRESSION : DECLARATION;
|
| bool ok = true;
|
| result = ParseFunctionLiteral(name,
|
| false, // Strict mode name already checked.
|
| @@ -775,7 +768,7 @@
|
| zone_scope->DeleteOnExit();
|
| if (stack_overflow_) Top::StackOverflow();
|
| } else {
|
| - Handle<String> inferred_name(info->inferred_name());
|
| + Handle<String> inferred_name(shared_info->inferred_name());
|
| result->set_inferred_name(inferred_name);
|
| }
|
| return result;
|
| @@ -803,10 +796,12 @@
|
| MessageLocation location(script_,
|
| source_location.beg_pos,
|
| source_location.end_pos);
|
| - Handle<JSArray> array = Factory::NewJSArray(args.length());
|
| + Handle<FixedArray> elements = Factory::NewFixedArray(args.length());
|
| for (int i = 0; i < args.length(); i++) {
|
| - SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i])));
|
| + Handle<String> arg_string = Factory::NewStringFromUtf8(CStrVector(args[i]));
|
| + elements->set(i, *arg_string);
|
| }
|
| + Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
|
| Handle<Object> result = Factory::NewSyntaxError(type, array);
|
| Top::Throw(*result, &location);
|
| }
|
| @@ -818,10 +813,11 @@
|
| MessageLocation location(script_,
|
| source_location.beg_pos,
|
| source_location.end_pos);
|
| - Handle<JSArray> array = Factory::NewJSArray(args.length());
|
| + Handle<FixedArray> elements = Factory::NewFixedArray(args.length());
|
| for (int i = 0; i < args.length(); i++) {
|
| - SetElement(array, i, args[i]);
|
| + elements->set(i, *args[i]);
|
| }
|
| + Handle<JSArray> array = Factory::NewJSArrayWithElements(elements);
|
| Handle<Object> result = Factory::NewSyntaxError(type, array);
|
| Top::Throw(*result, &location);
|
| }
|
| @@ -1106,8 +1102,21 @@
|
| }
|
|
|
| Scanner::Location token_loc = scanner().peek_location();
|
| - Statement* stat = ParseStatement(NULL, CHECK_OK);
|
|
|
| + Statement* stat;
|
| + if (peek() == Token::FUNCTION) {
|
| + // FunctionDeclaration is only allowed in the context of SourceElements
|
| + // (Ecma 262 5th Edition, clause 14):
|
| + // SourceElement:
|
| + // Statement
|
| + // FunctionDeclaration
|
| + // Common language extension is to allow function declaration in place
|
| + // of any statement. This language extension is disabled in strict mode.
|
| + stat = ParseFunctionDeclaration(CHECK_OK);
|
| + } else {
|
| + stat = ParseStatement(NULL, CHECK_OK);
|
| + }
|
| +
|
| if (stat == NULL || stat->IsEmpty()) {
|
| directive_prologue = false; // End of directive prologue.
|
| continue;
|
| @@ -1124,11 +1133,11 @@
|
| Handle<String> directive = Handle<String>::cast(literal->handle());
|
|
|
| // Check "use strict" directive (ES5 14.1).
|
| - if (!temp_scope_->StrictMode() &&
|
| + if (!top_scope_->is_strict_mode() &&
|
| directive->Equals(Heap::use_strict()) &&
|
| token_loc.end_pos - token_loc.beg_pos ==
|
| Heap::use_strict()->length() + 2) {
|
| - temp_scope_->EnableStrictMode();
|
| + top_scope_->EnableStrictMode();
|
| // "use strict" is the only directive for now.
|
| directive_prologue = false;
|
| }
|
| @@ -1263,8 +1272,17 @@
|
| return result;
|
| }
|
|
|
| - case Token::FUNCTION:
|
| + case Token::FUNCTION: {
|
| + // In strict mode, FunctionDeclaration is only allowed in the context
|
| + // of SourceElements.
|
| + if (top_scope_->is_strict_mode()) {
|
| + ReportMessageAt(scanner().peek_location(), "strict_function",
|
| + Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| return ParseFunctionDeclaration(ok);
|
| + }
|
|
|
| case Token::NATIVE:
|
| return ParseNativeDeclaration(ok);
|
| @@ -1515,6 +1533,11 @@
|
| Consume(Token::VAR);
|
| } else if (peek() == Token::CONST) {
|
| Consume(Token::CONST);
|
| + if (top_scope_->is_strict_mode()) {
|
| + ReportMessage("strict_const", Vector<const char*>::empty());
|
| + *ok = false;
|
| + return NULL;
|
| + }
|
| mode = Variable::CONST;
|
| is_const = true;
|
| } else {
|
| @@ -1546,7 +1569,7 @@
|
| if (fni_ != NULL) fni_->PushVariableName(name);
|
|
|
| // Strict mode variables may not be named eval or arguments
|
| - if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
|
| + if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
|
| ReportMessage("strict_var_name", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -1634,34 +1657,49 @@
|
|
|
| if (top_scope_->is_global_scope()) {
|
| // Compute the arguments for the runtime call.
|
| - ZoneList<Expression*>* arguments = new ZoneList<Expression*>(2);
|
| - // Be careful not to assign a value to the global variable if
|
| - // we're in a with. The initialization value should not
|
| - // necessarily be stored in the global object in that case,
|
| - // which is why we need to generate a separate assignment node.
|
| + ZoneList<Expression*>* arguments = new ZoneList<Expression*>(3);
|
| arguments->Add(new Literal(name)); // we have at least 1 parameter
|
| - if (is_const || (value != NULL && !inside_with())) {
|
| + CallRuntime* initialize;
|
| +
|
| + if (is_const) {
|
| arguments->Add(value);
|
| value = NULL; // zap the value to avoid the unnecessary assignment
|
| - }
|
| - // Construct the call to Runtime::DeclareGlobal{Variable,Const}Locally
|
| - // and add it to the initialization statement block. Note that
|
| - // this function does different things depending on if we have
|
| - // 1 or 2 parameters.
|
| - CallRuntime* initialize;
|
| - if (is_const) {
|
| +
|
| + // Construct the call to Runtime_InitializeConstGlobal
|
| + // and add it to the initialization statement block.
|
| + // Note that the function does different things depending on
|
| + // the number of arguments (1 or 2).
|
| initialize =
|
| - new CallRuntime(
|
| - Factory::InitializeConstGlobal_symbol(),
|
| - Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
|
| - arguments);
|
| + new CallRuntime(
|
| + Factory::InitializeConstGlobal_symbol(),
|
| + Runtime::FunctionForId(Runtime::kInitializeConstGlobal),
|
| + arguments);
|
| } else {
|
| + // Add strict mode.
|
| + // We may want to pass singleton to avoid Literal allocations.
|
| + arguments->Add(NewNumberLiteral(
|
| + top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode));
|
| +
|
| + // Be careful not to assign a value to the global variable if
|
| + // we're in a with. The initialization value should not
|
| + // necessarily be stored in the global object in that case,
|
| + // which is why we need to generate a separate assignment node.
|
| + if (value != NULL && !inside_with()) {
|
| + arguments->Add(value);
|
| + value = NULL; // zap the value to avoid the unnecessary assignment
|
| + }
|
| +
|
| + // Construct the call to Runtime_InitializeVarGlobal
|
| + // and add it to the initialization statement block.
|
| + // Note that the function does different things depending on
|
| + // the number of arguments (2 or 3).
|
| initialize =
|
| - new CallRuntime(
|
| - Factory::InitializeVarGlobal_symbol(),
|
| - Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
|
| - arguments);
|
| + new CallRuntime(
|
| + Factory::InitializeVarGlobal_symbol(),
|
| + Runtime::FunctionForId(Runtime::kInitializeVarGlobal),
|
| + arguments);
|
| }
|
| +
|
| block->AddStatement(new ExpressionStatement(initialize));
|
| }
|
|
|
| @@ -1913,7 +1951,7 @@
|
|
|
| Expect(Token::WITH, CHECK_OK);
|
|
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| ReportMessage("strict_mode_with", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -2052,7 +2090,7 @@
|
| Expect(Token::LPAREN, CHECK_OK);
|
| Handle<String> name = ParseIdentifier(CHECK_OK);
|
|
|
| - if (temp_scope_->StrictMode() && IsEvalOrArguments(name)) {
|
| + if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
|
| ReportMessage("strict_catch_variable", Vector<const char*>::empty());
|
| *ok = false;
|
| return NULL;
|
| @@ -2303,7 +2341,7 @@
|
| expression = NewThrowReferenceError(type);
|
| }
|
|
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| // Assignment to eval or arguments is disallowed in strict mode.
|
| CheckStrictModeLValue(expression, "strict_lhs_assignment", CHECK_OK);
|
| }
|
| @@ -2522,7 +2560,7 @@
|
| }
|
|
|
| // "delete identifier" is a syntax error in strict mode.
|
| - if (op == Token::DELETE && temp_scope_->StrictMode()) {
|
| + if (op == Token::DELETE && top_scope_->is_strict_mode()) {
|
| VariableProxy* operand = expression->AsVariableProxy();
|
| if (operand != NULL && !operand->is_this()) {
|
| ReportMessage("strict_delete", Vector<const char*>::empty());
|
| @@ -2545,7 +2583,7 @@
|
| expression = NewThrowReferenceError(type);
|
| }
|
|
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| // Prefix expression operand in strict mode may not be eval or arguments.
|
| CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
|
| }
|
| @@ -2576,7 +2614,7 @@
|
| expression = NewThrowReferenceError(type);
|
| }
|
|
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| // Postfix expression operand in strict mode may not be eval or arguments.
|
| CheckStrictModeLValue(expression, "strict_lhs_prefix", CHECK_OK);
|
| }
|
| @@ -2784,7 +2822,7 @@
|
| return ReportMessage("unexpected_token_identifier",
|
| Vector<const char*>::empty());
|
| case Token::FUTURE_RESERVED_WORD:
|
| - return ReportMessage(temp_scope_->StrictMode() ?
|
| + return ReportMessage(top_scope_->is_strict_mode() ?
|
| "unexpected_strict_reserved" :
|
| "unexpected_token_identifier",
|
| Vector<const char*>::empty());
|
| @@ -3289,7 +3327,7 @@
|
| new ZoneList<ObjectLiteral::Property*>(4);
|
| int number_of_boilerplate_properties = 0;
|
|
|
| - ObjectLiteralPropertyChecker checker(this, temp_scope_->StrictMode());
|
| + ObjectLiteralPropertyChecker checker(this, top_scope_->is_strict_mode());
|
|
|
| Expect(Token::LBRACE, CHECK_OK);
|
| Scanner::Location loc = scanner().location();
|
| @@ -3586,7 +3624,7 @@
|
| }
|
|
|
| // Validate strict mode.
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| if (IsEvalOrArguments(name)) {
|
| int position = function_token_position != RelocInfo::kNoPosition
|
| ? function_token_position
|
| @@ -3640,8 +3678,7 @@
|
| start_pos,
|
| end_pos,
|
| function_name->length() > 0,
|
| - temp_scope.ContainsLoops(),
|
| - temp_scope.StrictMode());
|
| + temp_scope.ContainsLoops());
|
| function_literal->set_function_token_position(function_token_position);
|
|
|
| if (fni_ != NULL && !is_named) fni_->AddFunction(function_literal);
|
| @@ -3770,7 +3807,7 @@
|
| Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
|
| bool* ok) {
|
| *is_reserved = false;
|
| - if (temp_scope_->StrictMode()) {
|
| + if (top_scope_->is_strict_mode()) {
|
| Expect(Token::IDENTIFIER, ok);
|
| } else {
|
| if (!Check(Token::IDENTIFIER)) {
|
| @@ -3801,7 +3838,7 @@
|
| void Parser::CheckStrictModeLValue(Expression* expression,
|
| const char* error,
|
| bool* ok) {
|
| - ASSERT(temp_scope_->StrictMode());
|
| + ASSERT(top_scope_->is_strict_mode());
|
| VariableProxy* lhs = expression != NULL
|
| ? expression->AsVariableProxy()
|
| : NULL;
|
| @@ -3993,12 +4030,14 @@
|
| MessageLocation location(Factory::NewScript(script),
|
| source_location.beg_pos,
|
| source_location.end_pos);
|
| - int argc = (name_opt == NULL) ? 0 : 1;
|
| - Handle<JSArray> array = Factory::NewJSArray(argc);
|
| - if (name_opt != NULL) {
|
| - SetElement(array,
|
| - 0,
|
| - Factory::NewStringFromUtf8(CStrVector(name_opt)));
|
| + Handle<JSArray> array;
|
| + if (name_opt == NULL) {
|
| + array = Factory::NewJSArray(0);
|
| + } else {
|
| + Handle<String> name = Factory::NewStringFromUtf8(CStrVector(name_opt));
|
| + Handle<FixedArray> element = Factory::NewFixedArray(1);
|
| + element->set(0, *name);
|
| + array = Factory::NewJSArrayWithElements(element);
|
| }
|
| Handle<Object> result = Factory::NewSyntaxError(message, array);
|
| Top::Throw(*result, &location);
|
| @@ -4070,7 +4109,7 @@
|
| if (value.is_null()) return Handle<Object>::null();
|
| uint32_t index;
|
| if (key->AsArrayIndex(&index)) {
|
| - SetOwnElement(json_object, index, value);
|
| + SetOwnElement(json_object, index, value, kNonStrictMode);
|
| } else if (key->Equals(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
|
| @@ -4273,6 +4312,8 @@
|
| capture_index);
|
| }
|
| builder->AddAtom(body);
|
| + // For compatability with JSC and ES3, we allow quantifiers after
|
| + // lookaheads, and break in all cases.
|
| break;
|
| }
|
| case '|': {
|
| @@ -4346,7 +4387,7 @@
|
| type,
|
| captures_started());
|
| builder = stored_state->builder();
|
| - break;
|
| + continue;
|
| }
|
| case '[': {
|
| RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
|
| @@ -4369,11 +4410,11 @@
|
| builder->AddAssertion(
|
| new RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
|
| continue;
|
| - // AtomEscape ::
|
| - // CharacterClassEscape
|
| - //
|
| - // CharacterClassEscape :: one of
|
| - // d D s S w W
|
| + // AtomEscape ::
|
| + // CharacterClassEscape
|
| + //
|
| + // CharacterClassEscape :: one of
|
| + // d D s S w W
|
| case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
|
| uc32 c = Next();
|
| Advance(2);
|
| @@ -5089,10 +5130,10 @@
|
| Handle<Script> script = info->script();
|
| if (info->is_lazy()) {
|
| Parser parser(script, true, NULL, NULL);
|
| - result = parser.ParseLazy(info->shared_info());
|
| + result = parser.ParseLazy(info);
|
| } else {
|
| bool allow_natives_syntax =
|
| - FLAG_allow_natives_syntax || Bootstrapper::IsActive();
|
| + info->allows_natives_syntax() || FLAG_allow_natives_syntax;
|
| ScriptDataImpl* pre_data = info->pre_parse_data();
|
| Parser parser(script, allow_natives_syntax, info->extension(), pre_data);
|
| if (pre_data != NULL && pre_data->has_error()) {
|
|
|