Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index 9724ec74c59f008b65b99ab1fcca5bc0adeb28a4..575d4942c30e57ee48a04017b18600befd558d16 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -751,13 +751,15 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral( |
| Handle<String> name, |
| Scanner::Location function_name_location, |
| bool name_is_strict_reserved, |
| - bool is_generator, |
| + FunctionParsingMode parsing_mode, |
| + Expression* params_ast, |
| int function_token_position, |
| FunctionLiteral::FunctionType type, |
| bool* ok) { |
| return parser_->ParseFunctionLiteral(name, function_name_location, |
| - name_is_strict_reserved, is_generator, |
| - function_token_position, type, ok); |
| + name_is_strict_reserved, parsing_mode, |
| + params_ast, function_token_position, |
| + type, ok); |
| } |
| @@ -786,6 +788,7 @@ Parser::Parser(CompilationInfo* info) |
| set_allow_lazy(false); // Must be explicitly enabled. |
| set_allow_generators(FLAG_harmony_generators); |
| set_allow_for_of(FLAG_harmony_iteration); |
| + set_allow_arrow_functions(FLAG_harmony_arrow_functions); |
| set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); |
| } |
| @@ -921,6 +924,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, |
| FunctionLiteral::kGlobalOrEval, |
| FunctionLiteral::kNotParenthesized, |
| FunctionLiteral::kNotGenerator, |
| + FunctionLiteral::kNotArrow, |
| 0); |
| result->set_ast_properties(factory()->visitor()->ast_properties()); |
| result->set_slot_processor(factory()->visitor()->slot_processor()); |
| @@ -1006,11 +1010,15 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) { |
| ? FunctionLiteral::ANONYMOUS_EXPRESSION |
| : FunctionLiteral::NAMED_EXPRESSION) |
| : FunctionLiteral::DECLARATION; |
| + FunctionParsingMode parsing_mode = shared_info->is_generator() |
|
rossberg
2014/03/25 12:35:34
Nit: I'd prefer formatting this like
FunctionPars
|
| + ? kGeneratorFunction |
| + : (shared_info->is_arrow() ? kArrowFunction : kNormalFunction); |
| bool ok = true; |
| result = ParseFunctionLiteral(name, |
| Scanner::Location::invalid(), |
| false, // Strict mode name already checked. |
| - shared_info->is_generator(), |
| + parsing_mode, |
| + EmptyExpression(), |
| RelocInfo::kNoPosition, |
| function_type, |
| &ok); |
| @@ -1859,14 +1867,17 @@ Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) { |
| // '{' FunctionBody '}' |
| Expect(Token::FUNCTION, CHECK_OK); |
| int pos = position(); |
| - bool is_generator = allow_generators() && Check(Token::MUL); |
| + FunctionParsingMode parsing_mode = (allow_generators() && Check(Token::MUL)) |
| + ? kGeneratorFunction |
| + : kNormalFunction; |
| bool is_strict_reserved = false; |
| Handle<String> name = ParseIdentifierOrStrictReservedWord( |
| &is_strict_reserved, CHECK_OK); |
| FunctionLiteral* fun = ParseFunctionLiteral(name, |
| scanner()->location(), |
| is_strict_reserved, |
| - is_generator, |
| + parsing_mode, |
| + EmptyExpression(), |
| pos, |
| FunctionLiteral::DECLARATION, |
| CHECK_OK); |
| @@ -3125,11 +3136,79 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { |
| } |
| +Vector<VariableProxy*> Parser::ParameterListFromExpression( |
|
rossberg
2014/03/25 12:35:34
How does this rule out illegal parenthesis? For ex
aperez
2014/04/09 08:47:16
True, this case is tricky to implement when re-int
|
| + Expression* expression, bool* ok) { |
| + if (expression == NULL) |
|
marja
2014/03/24 09:04:06
Normally having expression == NULL would be an err
aperez
2014/04/09 08:47:16
Yes, when the argument list is empty, “expression”
|
| + return Vector<VariableProxy*>::empty(); |
| + |
| + Collector<VariableProxy*> collector; |
| + while (expression->IsBinaryOperation()) { |
| + BinaryOperation* binop = expression->AsBinaryOperation(); |
| + |
| + if (binop->op() != Token::COMMA) { |
| + const char* token_name = Token::String(binop->op()); |
| + int pos = binop->position(); |
| + ParserTraits::ReportMessageAt(Scanner::Location(pos, pos), |
|
rossberg
2014/03/25 12:35:34
Can we refactor this a little to avoid all the err
aperez
2014/04/09 08:47:16
Sure.
|
| + "unexpected_token", |
| + Vector<const char*>(&token_name, 1)); |
| + *ok = false; |
| + return Vector<VariableProxy*>::empty(); |
| + } |
| + |
| + if (!binop->right()->IsVariableProxy()) { |
| + const char* token_name = Token::String(binop->op()); |
| + int pos = binop->position(); |
| + ParserTraits::ReportMessageAt(Scanner::Location(pos, pos), |
| + "unexpected_token", |
| + Vector<const char*>(&token_name, 1)); |
| + *ok = false; |
| + return Vector<VariableProxy*>::empty(); |
| + } |
| + |
| + if (binop->right()->AsVariableProxy()->is_this()) { |
| + const char* token_name = Token::String(Token::THIS); |
| + int pos = binop->right()->position(); |
| + ParserTraits::ReportMessageAt(Scanner::Location(pos, pos + 4), |
| + "unexpected_token", |
| + Vector<const char*>(&token_name, 1)); |
| + *ok = false; |
| + return Vector<VariableProxy*>::empty(); |
| + } |
| + |
| + collector.Add(binop->right()->AsVariableProxy()); |
| + expression = binop->left(); |
| + } |
| + |
| + if (!expression->IsVariableProxy()) { |
| + int pos = expression->position(); |
| + ParserTraits::ReportMessageAt(Scanner::Location(pos, pos), |
| + "unexpected_token", |
| + Vector<const char*>()); |
| + *ok = false; |
| + return Vector<VariableProxy*>::empty(); |
| + } |
| + |
| + if (expression->AsVariableProxy()->is_this()) { |
| + const char* token_name = Token::String(Token::THIS); |
| + int pos = expression->position(); |
| + ParserTraits::ReportMessageAt(Scanner::Location(pos, pos + 4), |
| + "unexpected_token", |
| + Vector<const char*>(&token_name, 1)); |
| + *ok = false; |
| + return Vector<VariableProxy*>::empty(); |
| + } |
| + |
| + collector.Add(expression->AsVariableProxy()); |
| + |
| + return collector.ToVector(); |
| +} |
| + |
| FunctionLiteral* Parser::ParseFunctionLiteral( |
| Handle<String> function_name, |
| Scanner::Location function_name_location, |
| bool name_is_strict_reserved, |
| - bool is_generator, |
| + FunctionParsingMode func_parsing_mode, |
| + Expression* params_ast, |
| int function_token_pos, |
| FunctionLiteral::FunctionType function_type, |
| bool* ok) { |
| @@ -3195,9 +3274,13 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ |
| ? FunctionLiteral::kIsParenthesized |
| : FunctionLiteral::kNotParenthesized; |
| - FunctionLiteral::IsGeneratorFlag generator = is_generator |
| - ? FunctionLiteral::kIsGenerator |
| - : FunctionLiteral::kNotGenerator; |
| + FunctionLiteral::IsGeneratorFlag generator = |
| + (func_parsing_mode == kGeneratorFunction) |
| + ? FunctionLiteral::kIsGenerator |
| + : FunctionLiteral::kNotGenerator; |
| + FunctionLiteral::IsArrowFlag arrow = (func_parsing_mode == kArrowFunction) |
| + ? FunctionLiteral::kIsArrow |
| + : FunctionLiteral::kNotArrow; |
| DeferredFeedbackSlotProcessor* slot_processor; |
| AstProperties ast_properties; |
| BailoutReason dont_optimize_reason = kNoReason; |
| @@ -3205,7 +3288,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| { FunctionState function_state(&function_state_, &scope_, scope, zone()); |
| scope_->SetScopeName(function_name); |
| - if (is_generator) { |
| + if (func_parsing_mode == kGeneratorFunction) { |
| // For generators, allocating variables in contexts is currently a win |
| // because it minimizes the work needed to suspend and resume an |
| // activation. |
| @@ -3219,11 +3302,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| function_state.set_generator_object_variable(temp); |
| } |
| - // FormalParameterList :: |
| - // '(' (Identifier)*[','] ')' |
| - Expect(Token::LPAREN, CHECK_OK); |
| - scope->set_start_position(scanner()->location().beg_pos); |
| - |
| // We don't yet know if the function will be strict, so we cannot yet |
| // produce errors for parameter names or duplicates. However, we remember |
| // the locations of these errors if they occur and produce the errors later. |
| @@ -3231,236 +3309,318 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| Scanner::Location dupe_error_loc = Scanner::Location::invalid(); |
| Scanner::Location reserved_loc = Scanner::Location::invalid(); |
| - bool done = (peek() == Token::RPAREN); |
| - while (!done) { |
| - bool is_strict_reserved = false; |
| - Handle<String> param_name = |
| - ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| + // FormalParameterList :: |
|
marja
2014/03/24 09:04:06
This ParseFunctionLiteral is pretty monstrous as i
rossberg
2014/03/25 12:35:34
+1. The arrow function case is parsing quite diffe
aperez
2014/04/09 08:47:16
I am in the process of moving parsing of arrow fun
|
| + // '(' (Identifier)*[','] ')' |
| - // Store locations for possible future error reports. |
| - if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) { |
| - eval_args_error_log = scanner()->location(); |
| - } |
| - if (!reserved_loc.IsValid() && is_strict_reserved) { |
| - reserved_loc = scanner()->location(); |
| - } |
| - if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { |
| - duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; |
| - dupe_error_loc = scanner()->location(); |
| - } |
| + if (func_parsing_mode == kArrowFunction && peek() == Token::ARROW) { |
|
rossberg
2014/03/25 12:35:34
Can it ever happen that the first condition is tru
aperez
2014/04/09 08:47:16
It could happen when the function is parsed lazily
|
| + // The parameter list has already been scanned and turned into an AST |
| + // and it is passed as "params_ast". Re-interpreting the AST avoids |
| + // needing to rewind and re-parse the parameter list. The starting |
| + // position of the parameter list is passed as "function_token_pos". |
| + scope->set_start_position(function_token_pos); |
| + Vector<VariableProxy*> params = ParameterListFromExpression(params_ast, |
| + CHECK_OK); |
| - scope_->DeclareParameter(param_name, VAR); |
| - num_parameters++; |
| - if (num_parameters > Code::kMaxArguments) { |
| - ReportMessageAt(scanner()->location(), "too_many_parameters"); |
| + if ((num_parameters = params.length()) > Code::kMaxArguments) { |
| + ReportMessageAt(Scanner::Location(params_ast->position(), position()), |
| + "too_many_parameters"); |
| *ok = false; |
| return NULL; |
| } |
| - done = (peek() == Token::RPAREN); |
| - if (!done) Expect(Token::COMMA, CHECK_OK); |
| + |
| + // The vector has the items in reverse order |
| + for (int i = params.length() - 1; i >= 0; --i) { |
| + Handle<String> param_name = params.at(i)->name(); |
| + int param_pos = params.at(i)->position(); |
| + |
| + if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) { |
| + eval_args_error_log = |
| + Scanner::Location(param_pos, param_pos + param_name->length()); |
| + } |
| + if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { |
| + dupe_error_loc = |
| + Scanner::Location(param_pos, param_pos + param_name->length()); |
| + duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; |
| + } |
| + |
| + scope_->DeclareParameter(param_name, VAR); |
| + } |
| + } else { |
| + bool arrow_single_param = |
| + (func_parsing_mode == kArrowFunction && peek() != Token::LPAREN); |
| + |
| + if (!arrow_single_param) { |
| + Expect(Token::LPAREN, CHECK_OK); |
| + } |
| + |
| + scope->set_start_position(scanner()->location().beg_pos); |
| + |
| + bool done = (peek() == Token::RPAREN); |
| + while (!done) { |
| + bool is_strict_reserved = false; |
| + Handle<String> param_name = |
| + ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| + |
| + // Store locations for possible future error reports. |
| + if (!eval_args_error_log.IsValid() && IsEvalOrArguments(param_name)) { |
| + eval_args_error_log = scanner()->location(); |
| + } |
| + if (!reserved_loc.IsValid() && is_strict_reserved) { |
| + reserved_loc = scanner()->location(); |
| + } |
| + if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { |
| + duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; |
| + dupe_error_loc = scanner()->location(); |
| + } |
| + |
| + scope_->DeclareParameter(param_name, VAR); |
| + num_parameters++; |
| + if (num_parameters > Code::kMaxArguments) { |
| + ReportMessageAt(scanner()->location(), "too_many_parameters"); |
| + *ok = false; |
| + return NULL; |
| + } |
| + |
| + done = (peek() == Token::RPAREN); |
| + if (arrow_single_param) break; |
| + if (!done) Expect(Token::COMMA, CHECK_OK); |
| + } |
| + |
| + if (!arrow_single_param) { |
| + Expect(Token::RPAREN, CHECK_OK); |
| + } |
| } |
| - Expect(Token::RPAREN, CHECK_OK); |
| - |
| - Expect(Token::LBRACE, CHECK_OK); |
| - |
| - // If we have a named function expression, we add a local variable |
| - // declaration to the body of the function with the name of the |
| - // function and let it refer to the function itself (closure). |
| - // NOTE: We create a proxy and resolve it here so that in the |
| - // future we can change the AST to only refer to VariableProxies |
| - // instead of Variables and Proxis as is the case now. |
| - Variable* fvar = NULL; |
| - Token::Value fvar_init_op = Token::INIT_CONST_LEGACY; |
| - if (function_type == FunctionLiteral::NAMED_EXPRESSION) { |
| - if (FLAG_harmony_scoping && strict_mode() == STRICT) { |
| - fvar_init_op = Token::INIT_CONST; |
| + |
| + if (func_parsing_mode == kArrowFunction) { |
| + Expect(Token::ARROW, CHECK_OK); |
| + |
| + // The arrow function has a single-expression body |
| + if (peek() != Token::LBRACE) { |
| + int pos = position(); |
| + Expression* expression = ParseExpression(true, CHECK_OK); |
|
rossberg
2014/03/25 12:35:34
Shouldn't this be ParseAssignmentExpression?
aperez
2014/04/09 08:47:16
Indeed.
|
| + body = new(zone()) ZoneList<Statement*>(1, zone()); |
| + body->Add(factory()->NewReturnStatement(expression, pos), zone()); |
| + |
| + materialized_literal_count = |
| + function_state.materialized_literal_count(); |
| + expected_property_count = function_state.expected_property_count(); |
| + handler_count = function_state.handler_count(); |
| + |
| + scope->set_end_position(scanner()->location().end_pos); |
| } |
| - VariableMode fvar_mode = FLAG_harmony_scoping && strict_mode() == STRICT |
| - ? CONST : CONST_LEGACY; |
| - fvar = new(zone()) Variable(scope_, |
| - function_name, fvar_mode, true /* is valid LHS */, |
| - Variable::NORMAL, kCreatedInitialized, Interface::NewConst()); |
| - VariableProxy* proxy = factory()->NewVariableProxy(fvar); |
| - VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration( |
| - proxy, fvar_mode, scope_, RelocInfo::kNoPosition); |
| - scope_->DeclareFunctionVar(fvar_declaration); |
| } |
| - // Determine if the function can be parsed lazily. Lazy parsing is different |
| - // from lazy compilation; we need to parse more eagerly than we compile. |
| - |
| - // We can only parse lazily if we also compile lazily. The heuristics for |
| - // lazy compilation are: |
| - // - It must not have been prohibited by the caller to Parse (some callers |
| - // need a full AST). |
| - // - The outer scope must allow lazy compilation of inner functions. |
| - // - The function mustn't be a function expression with an open parenthesis |
| - // before; we consider that a hint that the function will be called |
| - // immediately, and it would be a waste of time to make it lazily |
| - // compiled. |
| - // These are all things we can know at this point, without looking at the |
| - // function itself. |
| - |
| - // In addition, we need to distinguish between these cases: |
| - // (function foo() { |
| - // bar = function() { return 1; } |
| - // })(); |
| - // and |
| - // (function foo() { |
| - // var a = 1; |
| - // bar = function() { return a; } |
| - // })(); |
| - |
| - // Now foo will be parsed eagerly and compiled eagerly (optimization: assume |
| - // parenthesis before the function means that it will be called |
| - // immediately). The inner function *must* be parsed eagerly to resolve the |
| - // possible reference to the variable in foo's scope. However, it's possible |
| - // that it will be compiled lazily. |
| - |
| - // To make this additional case work, both Parser and PreParser implement a |
| - // logic where only top-level functions will be parsed lazily. |
| - bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
| - scope_->AllowsLazyCompilation() && |
| - !parenthesized_function_); |
| - parenthesized_function_ = false; // The bit was set for this function only. |
| - |
| - if (is_lazily_parsed) { |
| - int function_block_pos = position(); |
| - FunctionEntry entry; |
| - if (cached_data_mode_ == CONSUME_CACHED_DATA) { |
| - // If we have cached data, we use it to skip parsing the function body. |
| - // The data contains the information we need to construct the lazy |
| - // function. |
| - entry = (*cached_data())->GetFunctionEntry(function_block_pos); |
| - if (entry.is_valid()) { |
| - if (entry.end_pos() <= function_block_pos) { |
| - // End position greater than end of stream is safe, and hard |
| - // to check. |
| - ReportInvalidPreparseData(function_name, CHECK_OK); |
| - } |
| - scanner()->SeekForward(entry.end_pos() - 1); |
| + // If an arrow function has a single-expression body, |
| + // it was already parsed above and "body" is non-NULL. |
| + if (body == NULL) { |
| + Expect(Token::LBRACE, CHECK_OK); |
| + |
| + // If we have a named function expression, we add a local variable |
| + // declaration to the body of the function with the name of the |
| + // function and let it refer to the function itself (closure). |
| + // NOTE: We create a proxy and resolve it here so that in the |
| + // future we can change the AST to only refer to VariableProxies |
| + // instead of Variables and Proxis as is the case now. |
| + Variable* fvar = NULL; |
| + Token::Value fvar_init_op = Token::INIT_CONST_LEGACY; |
| + if (function_type == FunctionLiteral::NAMED_EXPRESSION) { |
| + if (FLAG_harmony_scoping && strict_mode() == STRICT) { |
| + fvar_init_op = Token::INIT_CONST; |
| + } |
| + VariableMode fvar_mode = FLAG_harmony_scoping && strict_mode() == STRICT |
| + ? CONST : CONST_LEGACY; |
| + fvar = new(zone()) Variable(scope_, |
| + function_name, fvar_mode, true /* is valid LHS */, |
| + Variable::NORMAL, kCreatedInitialized, Interface::NewConst()); |
| + VariableProxy* proxy = factory()->NewVariableProxy(fvar); |
| + VariableDeclaration* fvar_declaration = |
| + factory()->NewVariableDeclaration(proxy, fvar_mode, scope_, |
| + RelocInfo::kNoPosition); |
| + scope_->DeclareFunctionVar(fvar_declaration); |
| + } |
| + |
| + // Determine if the function can be parsed lazily. Lazy parsing is |
| + // different from lazy compilation; we need to parse more eagerly than |
| + // we compile. |
| + |
| + // We can only parse lazily if we also compile lazily. The heuristics for |
| + // lazy compilation are: |
| + // - It must not have been prohibited by the caller to Parse (some |
| + // callers need a full AST). |
| + // - The outer scope must allow lazy compilation of inner functions. |
| + // - The function mustn't be a function expression with an open |
| + // parenthesis before; we consider that a hint that the function will |
| + // be called immediately, and it would be a waste of time to make it |
| + // lazily compiled. |
| + // These are all things we can know at this point, without looking at |
| + // the function itself. |
| + |
| + // In addition, we need to distinguish between these cases: |
| + // (function foo() { |
| + // bar = function() { return 1; } |
| + // })(); |
| + // and |
| + // (function foo() { |
| + // var a = 1; |
| + // bar = function() { return a; } |
| + // })(); |
| - scope->set_end_position(entry.end_pos()); |
| + // Now foo will be parsed eagerly and compiled eagerly (optimization: |
| + // assume parenthesis before the function means that it will be called |
| + // immediately). The inner function *must* be parsed eagerly to resolve |
| + // the possible reference to the variable in foo's scope. However, it's |
| + // possible that it will be compiled lazily. |
| + |
| + // To make this additional case work, both Parser and PreParser implement |
| + // a logic where only top-level functions will be parsed lazily. |
| + bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
| + scope_->AllowsLazyCompilation() && |
| + !parenthesized_function_ && |
| + (func_parsing_mode != kArrowFunction)); |
| + |
| + // The bit was set for this function only. |
| + parenthesized_function_ = false; |
| + |
| + if (is_lazily_parsed) { |
| + int function_block_pos = position(); |
| + FunctionEntry entry; |
| + if (cached_data_mode_ == CONSUME_CACHED_DATA) { |
| + // If we have cached data, we use it to skip parsing the function |
| + // body. The data contains the information we need to construct the |
| + // lazy function. |
| + entry = (*cached_data())->GetFunctionEntry(function_block_pos); |
| + if (entry.is_valid()) { |
| + if (entry.end_pos() <= function_block_pos) { |
| + // End position greater than end of stream is safe, and hard |
| + // to check. |
| + ReportInvalidPreparseData(function_name, CHECK_OK); |
| + } |
| + scanner()->SeekForward(entry.end_pos() - 1); |
| + |
| + scope->set_end_position(entry.end_pos()); |
| + Expect(Token::RBRACE, CHECK_OK); |
| + isolate()->counters()->total_preparse_skipped()->Increment( |
| + scope->end_position() - function_block_pos); |
| + materialized_literal_count = entry.literal_count(); |
| + expected_property_count = entry.property_count(); |
| + scope_->SetStrictMode(entry.strict_mode()); |
| + } else { |
| + // This case happens when we have preparse data but it doesn't |
| + // contain an entry for the function. As a safety net, fall back |
| + // to eager parsing. It is unclear whether PreParser's laziness |
| + // analysis can produce different results than the Parser's |
| + // laziness analysis (see https://codereview.chromium.org/7565003). |
| + // In this case, we must discard all the preparse data, since the |
| + // symbol data will be wrong. |
| + is_lazily_parsed = false; |
| + cached_data_mode_ = NO_CACHED_DATA; |
| + } |
| + } else { |
| + // With no cached data, we partially parse the function, without |
| + // building an AST. This gathers the data needed to build a lazy |
| + // function. |
| + // FIXME(marja): Now the PreParser doesn't need to log functions / |
| + // symbols; only errors -> clean that up. |
| + SingletonLogger logger; |
| + PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger); |
| + if (result == PreParser::kPreParseStackOverflow) { |
| + // Propagate stack overflow. |
| + set_stack_overflow(); |
| + *ok = false; |
| + return NULL; |
| + } |
| + if (logger.has_error()) { |
| + const char* arg = logger.argument_opt(); |
| + Vector<const char*> args; |
| + if (arg != NULL) { |
| + args = Vector<const char*>(&arg, 1); |
| + } |
| + ParserTraits::ReportMessageAt( |
| + Scanner::Location(logger.start(), logger.end()), |
| + logger.message(), |
| + args); |
| + *ok = false; |
| + return NULL; |
| + } |
| + scope->set_end_position(logger.end()); |
| Expect(Token::RBRACE, CHECK_OK); |
| isolate()->counters()->total_preparse_skipped()->Increment( |
| scope->end_position() - function_block_pos); |
| - materialized_literal_count = entry.literal_count(); |
| - expected_property_count = entry.property_count(); |
| - scope_->SetStrictMode(entry.strict_mode()); |
| - } else { |
| - // This case happens when we have preparse data but it doesn't contain |
| - // an entry for the function. As a safety net, fall back to eager |
| - // parsing. It is unclear whether PreParser's laziness analysis can |
| - // produce different results than the Parser's laziness analysis (see |
| - // https://codereview.chromium.org/7565003 ). In this case, we must |
| - // discard all the preparse data, since the symbol data will be wrong. |
| - is_lazily_parsed = false; |
| - cached_data_mode_ = NO_CACHED_DATA; |
| - } |
| - } else { |
| - // With no cached data, we partially parse the function, without |
| - // building an AST. This gathers the data needed to build a lazy |
| - // function. |
| - // FIXME(marja): Now the PreParser doesn't need to log functions / |
| - // symbols; only errors -> clean that up. |
| - SingletonLogger logger; |
| - PreParser::PreParseResult result = LazyParseFunctionLiteral(&logger); |
| - if (result == PreParser::kPreParseStackOverflow) { |
| - // Propagate stack overflow. |
| - set_stack_overflow(); |
| - *ok = false; |
| - return NULL; |
| - } |
| - if (logger.has_error()) { |
| - const char* arg = logger.argument_opt(); |
| - Vector<const char*> args; |
| - if (arg != NULL) { |
| - args = Vector<const char*>(&arg, 1); |
| + materialized_literal_count = logger.literals(); |
| + expected_property_count = logger.properties(); |
| + scope_->SetStrictMode(logger.strict_mode()); |
| + if (cached_data_mode_ == PRODUCE_CACHED_DATA) { |
| + ASSERT(log_); |
| + // Position right after terminal '}'. |
| + int body_end = scanner()->location().end_pos; |
| + log_->LogFunction(function_block_pos, body_end, |
| + materialized_literal_count, |
| + expected_property_count, |
| + scope_->strict_mode()); |
| } |
| - ParserTraits::ReportMessageAt( |
| - Scanner::Location(logger.start(), logger.end()), |
| - logger.message(), |
| - args); |
| - *ok = false; |
| - return NULL; |
| - } |
| - scope->set_end_position(logger.end()); |
| + } |
| + } |
| + |
| + if (!is_lazily_parsed) { |
| + // Everything inside an eagerly parsed function will be parsed eagerly |
| + // (see comment above). |
| + ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
| + body = new(zone()) ZoneList<Statement*>(8, zone()); |
| + if (fvar != NULL) { |
| + VariableProxy* fproxy = scope_->NewUnresolved( |
| + factory(), function_name, Interface::NewConst()); |
| + fproxy->BindTo(fvar); |
| + body->Add(factory()->NewExpressionStatement( |
| + factory()->NewAssignment(fvar_init_op, |
| + fproxy, |
| + factory()->NewThisFunction(pos), |
| + RelocInfo::kNoPosition), |
| + RelocInfo::kNoPosition), zone()); |
| + } |
| + |
| + // For generators, allocate and yield an iterator on function entry. |
| + if (func_parsing_mode == kGeneratorFunction) { |
| + ZoneList<Expression*>* arguments = |
| + new(zone()) ZoneList<Expression*>(0, zone()); |
| + CallRuntime* allocation = factory()->NewCallRuntime( |
| + isolate()->factory()->empty_string(), |
| + Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject), |
| + arguments, pos); |
| + VariableProxy* init_proxy = factory()->NewVariableProxy( |
| + function_state_->generator_object_variable()); |
| + Assignment* assignment = factory()->NewAssignment( |
| + Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition); |
| + VariableProxy* get_proxy = factory()->NewVariableProxy( |
| + function_state_->generator_object_variable()); |
| + Yield* yield = factory()->NewYield( |
| + get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition); |
| + body->Add(factory()->NewExpressionStatement( |
| + yield, RelocInfo::kNoPosition), zone()); |
| + } |
| + |
| + ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); |
| + |
| + if (func_parsing_mode == kGeneratorFunction) { |
| + VariableProxy* get_proxy = factory()->NewVariableProxy( |
| + function_state_->generator_object_variable()); |
| + Expression *undefined = factory()->NewLiteral( |
| + isolate()->factory()->undefined_value(), RelocInfo::kNoPosition); |
| + Yield* yield = factory()->NewYield( |
| + get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition); |
| + body->Add(factory()->NewExpressionStatement( |
| + yield, RelocInfo::kNoPosition), zone()); |
| + } |
| + |
| + materialized_literal_count = |
| + function_state.materialized_literal_count(); |
| + expected_property_count = function_state.expected_property_count(); |
| + handler_count = function_state.handler_count(); |
| + |
| Expect(Token::RBRACE, CHECK_OK); |
| - isolate()->counters()->total_preparse_skipped()->Increment( |
| - scope->end_position() - function_block_pos); |
| - materialized_literal_count = logger.literals(); |
| - expected_property_count = logger.properties(); |
| - scope_->SetStrictMode(logger.strict_mode()); |
| - if (cached_data_mode_ == PRODUCE_CACHED_DATA) { |
| - ASSERT(log_); |
| - // Position right after terminal '}'. |
| - int body_end = scanner()->location().end_pos; |
| - log_->LogFunction(function_block_pos, body_end, |
| - materialized_literal_count, |
| - expected_property_count, |
| - scope_->strict_mode()); |
| - } |
| + scope->set_end_position(scanner()->location().end_pos); |
| } |
| } |
| - if (!is_lazily_parsed) { |
| - // Everything inside an eagerly parsed function will be parsed eagerly |
| - // (see comment above). |
| - ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
| - body = new(zone()) ZoneList<Statement*>(8, zone()); |
| - if (fvar != NULL) { |
| - VariableProxy* fproxy = scope_->NewUnresolved( |
| - factory(), function_name, Interface::NewConst()); |
| - fproxy->BindTo(fvar); |
| - body->Add(factory()->NewExpressionStatement( |
| - factory()->NewAssignment(fvar_init_op, |
| - fproxy, |
| - factory()->NewThisFunction(pos), |
| - RelocInfo::kNoPosition), |
| - RelocInfo::kNoPosition), zone()); |
| - } |
| - |
| - // For generators, allocate and yield an iterator on function entry. |
| - if (is_generator) { |
| - ZoneList<Expression*>* arguments = |
| - new(zone()) ZoneList<Expression*>(0, zone()); |
| - CallRuntime* allocation = factory()->NewCallRuntime( |
| - isolate()->factory()->empty_string(), |
| - Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject), |
| - arguments, pos); |
| - VariableProxy* init_proxy = factory()->NewVariableProxy( |
| - function_state_->generator_object_variable()); |
| - Assignment* assignment = factory()->NewAssignment( |
| - Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition); |
| - VariableProxy* get_proxy = factory()->NewVariableProxy( |
| - function_state_->generator_object_variable()); |
| - Yield* yield = factory()->NewYield( |
| - get_proxy, assignment, Yield::INITIAL, RelocInfo::kNoPosition); |
| - body->Add(factory()->NewExpressionStatement( |
| - yield, RelocInfo::kNoPosition), zone()); |
| - } |
| - |
| - ParseSourceElements(body, Token::RBRACE, false, false, CHECK_OK); |
| - |
| - if (is_generator) { |
| - VariableProxy* get_proxy = factory()->NewVariableProxy( |
| - function_state_->generator_object_variable()); |
| - Expression *undefined = factory()->NewLiteral( |
| - isolate()->factory()->undefined_value(), RelocInfo::kNoPosition); |
| - Yield* yield = factory()->NewYield( |
| - get_proxy, undefined, Yield::FINAL, RelocInfo::kNoPosition); |
| - body->Add(factory()->NewExpressionStatement( |
| - yield, RelocInfo::kNoPosition), zone()); |
| - } |
| - |
| - materialized_literal_count = function_state.materialized_literal_count(); |
| - expected_property_count = function_state.expected_property_count(); |
| - handler_count = function_state.handler_count(); |
| - |
| - Expect(Token::RBRACE, CHECK_OK); |
| - scope->set_end_position(scanner()->location().end_pos); |
| - } |
| - |
| // Validate strict mode. We can do this only after parsing the function, |
| // since the function can declare itself strict. |
| if (strict_mode() == STRICT) { |
| @@ -3515,6 +3675,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| FunctionLiteral::kIsFunction, |
| parenthesized, |
| generator, |
| + arrow, |
| pos); |
| function_literal->set_function_token_position(function_token_pos); |
| function_literal->set_ast_properties(&ast_properties); |
| @@ -3540,6 +3701,7 @@ PreParser::PreParseResult Parser::LazyParseFunctionLiteral( |
| reusable_preparser_->set_allow_lazy(true); |
| reusable_preparser_->set_allow_generators(allow_generators()); |
| reusable_preparser_->set_allow_for_of(allow_for_of()); |
| + reusable_preparser_->set_allow_arrow_functions(allow_arrow_functions()); |
| reusable_preparser_->set_allow_harmony_numeric_literals( |
| allow_harmony_numeric_literals()); |
| } |
| @@ -4624,6 +4786,7 @@ ScriptDataImpl* PreParserApi::PreParse(Isolate* isolate, |
| preparser.set_allow_lazy(true); |
| preparser.set_allow_generators(FLAG_harmony_generators); |
| preparser.set_allow_for_of(FLAG_harmony_iteration); |
| + preparser.set_allow_arrow_functions(FLAG_harmony_arrow_functions); |
| preparser.set_allow_harmony_scoping(FLAG_harmony_scoping); |
| preparser.set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); |
| scanner.Initialize(source); |