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); |