Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(875)

Unified Diff: src/parser.cc

Issue 160073006: Implement handling of arrow functions in the parser (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Implement handling of arrow functions in the parser Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | src/preparser.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | src/preparser.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698