Chromium Code Reviews| Index: src/preparser.h |
| diff --git a/src/preparser.h b/src/preparser.h |
| index 499240e63acc6b43bdcefd74edc183113600f432..bcb5ef215f3d1d3990a4c2a9c80846cdffdeedc9 100644 |
| --- a/src/preparser.h |
| +++ b/src/preparser.h |
| @@ -62,6 +62,7 @@ class ParserBase : public Traits { |
| // Shorten type names defined by Traits. |
| typedef typename Traits::Type::Expression ExpressionT; |
| typedef typename Traits::Type::Identifier IdentifierT; |
| + typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; |
| ParserBase(Scanner* scanner, uintptr_t stack_limit, |
| v8::Extension* extension, |
| @@ -83,6 +84,7 @@ class ParserBase : public Traits { |
| allow_natives_syntax_(false), |
| allow_generators_(false), |
| allow_for_of_(false), |
| + allow_arrow_functions_(false), |
| zone_(zone) { } |
| // Getters that indicate whether certain syntactical constructs are |
| @@ -91,6 +93,7 @@ class ParserBase : public Traits { |
| bool allow_natives_syntax() const { return allow_natives_syntax_; } |
| bool allow_generators() const { return allow_generators_; } |
| bool allow_for_of() const { return allow_for_of_; } |
| + bool allow_arrow_functions() const { return allow_arrow_functions_; } |
| bool allow_modules() const { return scanner()->HarmonyModules(); } |
| bool allow_harmony_scoping() const { return scanner()->HarmonyScoping(); } |
| bool allow_harmony_numeric_literals() const { |
| @@ -103,6 +106,7 @@ class ParserBase : public Traits { |
| void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; } |
| void set_allow_generators(bool allow) { allow_generators_ = allow; } |
| void set_allow_for_of(bool allow) { allow_for_of_ = allow; } |
| + void set_allow_arrow_functions(bool allow) { allow_arrow_functions_ = allow; } |
| void set_allow_modules(bool allow) { scanner()->SetHarmonyModules(allow); } |
| void set_allow_harmony_scoping(bool allow) { |
| scanner()->SetHarmonyScoping(allow); |
| @@ -150,8 +154,14 @@ class ParserBase : public Traits { |
| FunctionState** function_state_stack, |
| typename Traits::Type::Scope** scope_stack, |
| typename Traits::Type::Scope* scope, |
| - typename Traits::Type::Zone* zone = NULL, |
| - AstValueFactory* ast_value_factory = NULL); |
| + typename Traits::Type::Zone* zone, |
| + AstValueFactory* ast_value_factory); |
| + FunctionState( |
| + FunctionState** function_state_stack, |
| + typename Traits::Type::Scope** scope_stack, |
| + typename Traits::Type::Scope** scope, |
| + typename Traits::Type::Zone* zone, |
| + AstValueFactory* ast_value_factory); |
| ~FunctionState(); |
| int NextMaterializedLiteralIndex() { |
| @@ -443,6 +453,31 @@ class ParserBase : public Traits { |
| ExpressionT ParseMemberExpressionContinuation(ExpressionT expression, |
| bool* ok); |
| + // There are two ways of parsing arrow functions: if the beginning of an |
| + // arrow function can be determined prior to process the parameter list |
| + // (e.g. the current scanning position is known to be an arrow function |
| + // and not an AssignmentExpression) then the first version is used. In |
| + // most cases, we parse the parameter list as an AssignmentExpression |
| + // and interpret the AST when the arrow "=>" token is found, using the |
| + // second version. |
| + // The overloaded ParseArrowFunctionLiteral() functions mainly deal with |
| + // parsing/interpreting the parameter list, and then they both call |
| + // ParseArrowFunctionLiteralBody() before consuming the arrow token. |
| + ExpressionT ParseArrowFunctionLiteral(bool* ok); |
|
marja
2014/06/26 14:38:13
Isn't this one dead code? (And isn't the comment a
|
| + ExpressionT ParseArrowFunctionLiteral(int start_pos, |
| + ExpressionT params_ast, |
| + bool* ok); |
| + ExpressionT ParseArrowFunctionLiteralBody( |
| + FunctionState* function_state, |
| + typename Traits::Type::ScopePtr scope, |
| + int num_parameters, |
| + const Scanner::Location& eval_args_error_loc, |
| + const Scanner::Location& dupe_error_loc, |
| + const Scanner::Location& reserved_loc, |
| + FunctionLiteral::IsParenthesizedFlag parenthesized, |
| + int start_pos, |
| + bool* ok); |
| + |
| // Checks if the expression is a valid reference expression (e.g., on the |
| // left-hand side of assignments). Although ruled out by ECMA as early errors, |
| // we allow calls for web compatibility and rewrite them to a runtime throw. |
| @@ -526,6 +561,7 @@ class ParserBase : public Traits { |
| bool allow_natives_syntax_; |
| bool allow_generators_; |
| bool allow_for_of_; |
| + bool allow_arrow_functions_; |
| typename Traits::Type::Zone* zone_; // Only used by Parser. |
| }; |
| @@ -552,16 +588,32 @@ class PreParserIdentifier { |
| static PreParserIdentifier Yield() { |
| return PreParserIdentifier(kYieldIdentifier); |
| } |
| - bool IsEval() { return type_ == kEvalIdentifier; } |
| - bool IsArguments() { return type_ == kArgumentsIdentifier; } |
| + bool IsEval() const { return type_ == kEvalIdentifier; } |
| + bool IsArguments() const { return type_ == kArgumentsIdentifier; } |
| bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; } |
| - bool IsYield() { return type_ == kYieldIdentifier; } |
| + bool IsYield() const { return type_ == kYieldIdentifier; } |
| bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; } |
| - bool IsFutureStrictReserved() { |
| + bool IsFutureStrictReserved() const { |
| return type_ == kFutureStrictReservedIdentifier; |
| } |
| bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; } |
| + // Allow identifier->name()[->length()] to work. The preparser |
| + // does not need the actual positions/lengths of the identifiers. |
| + const PreParserIdentifier* operator->() const { return this; } |
| + const PreParserIdentifier raw_name() const { return *this; } |
| + |
| + int position() const { |
| + return 0; |
| + } |
| + |
| + int length() const { |
|
marja
2014/06/26 14:38:13
This is used for duplicate parameter error message
|
| + if (IsEval()) return 4; |
| + if (IsArguments()) return 9; |
| + if (IsYield()) return 5; |
| + return 0; |
| + } |
| + |
| private: |
| enum Type { |
| kUnknownIdentifier, |
| @@ -575,6 +627,7 @@ class PreParserIdentifier { |
| Type type_; |
| friend class PreParserExpression; |
| + friend class PreParserScope; |
| }; |
| @@ -590,10 +643,26 @@ class PreParserExpression { |
| } |
| static PreParserExpression FromIdentifier(PreParserIdentifier id) { |
| - return PreParserExpression(kIdentifierFlag | |
| + return PreParserExpression(kTypeIdentifier | |
| (id.type_ << kIdentifierShift)); |
| } |
| + static PreParserExpression BinaryOperation(PreParserExpression left, |
| + Token::Value op, |
| + PreParserExpression right) { |
| + int code = ((op == Token::COMMA) && |
| + !left.is_parenthesized() && |
| + !right.is_parenthesized()) |
| + ? left.ArrowParamListBit() & right.ArrowParamListBit() : 0; |
| + return PreParserExpression(kTypeBinaryOperation | code); |
| + } |
| + |
| + static PreParserExpression EmptyArrowParamList() { |
| + // Any expression for which IsValidArrowParamList() returns true |
| + // will work here. |
| + return FromIdentifier(PreParserIdentifier::Default()); |
| + } |
| + |
| static PreParserExpression StringLiteral() { |
| return PreParserExpression(kUnknownStringLiteral); |
| } |
| @@ -618,18 +687,22 @@ class PreParserExpression { |
| return PreParserExpression(kCallExpression); |
| } |
| - bool IsIdentifier() { return (code_ & kIdentifierFlag) != 0; } |
| + bool IsIdentifier() const { |
| + return (code_ & kTypeMask) == kTypeIdentifier; |
| + } |
| - PreParserIdentifier AsIdentifier() { |
| + PreParserIdentifier AsIdentifier() const { |
| ASSERT(IsIdentifier()); |
| return PreParserIdentifier( |
| static_cast<PreParserIdentifier::Type>(code_ >> kIdentifierShift)); |
| } |
| - bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; } |
| + bool IsStringLiteral() const { |
| + return (code_ & kTypeMask) == kTypeStringLiteral; |
| + } |
| bool IsUseStrictLiteral() { |
| - return (code_ & kStringLiteralMask) == kUseStrictString; |
| + return (code_ & kUseStrictString) == kUseStrictString; |
| } |
| bool IsThis() { return code_ == kThisExpression; } |
| @@ -646,12 +719,34 @@ class PreParserExpression { |
| return IsIdentifier() || IsProperty(); |
| } |
| + bool IsValidArrowParamList() const { |
| + return (ArrowParamListBit() & kBinaryOperationArrowParamList) != 0 |
| + && (code_ & kMultiParenthesizedExpression) == 0; |
| + } |
| + |
| // At the moment PreParser doesn't track these expression types. |
| bool IsFunctionLiteral() const { return false; } |
| bool IsCallNew() const { return false; } |
| PreParserExpression AsFunctionLiteral() { return *this; } |
| + bool IsBinaryOperation() const { |
| + return (code_ & kTypeMask) == kTypeBinaryOperation; |
| + } |
| + |
| + bool is_parenthesized() const { |
| + return (code_ & kParenthesizedExpression) != 0; |
| + } |
| + void set_is_parenthesized(bool value) { |
| + if (value) { |
| + code_ |= is_parenthesized() |
| + ? kMultiParenthesizedExpression |
| + : kParenthesizedExpression; |
| + } else { |
| + code_ &= ~kParenthesizedExpression; |
| + } |
| + } |
| + |
| // Dummy implementation for making expression->somefunc() work in both Parser |
| // and PreParser. |
| PreParserExpression* operator->() { return this; } |
| @@ -660,33 +755,72 @@ class PreParserExpression { |
| void set_index(int index) {} // For YieldExpressions |
| void set_parenthesized() {} |
| + int position() const { return RelocInfo::kNoPosition; } |
| + void set_function_token_position(int position) {} |
| + void set_ast_properties(int* ast_properties) {} |
| + void set_dont_optimize_reason(BailoutReason dont_optimize_reason) {} |
| + |
| + bool operator==(const PreParserExpression& other) const { |
| + return code_ == other.code_; |
| + } |
| + bool operator!=(const PreParserExpression& other) const { |
| + return code_ != other.code_; |
| + } |
| + |
| private: |
| - // Least significant 2 bits are used as flags. Bits 0 and 1 represent |
| - // identifiers or strings literals, and are mutually exclusive, but can both |
| - // be absent. If the expression is an identifier or a string literal, the |
| - // other bits describe the type (see PreParserIdentifier::Type and string |
| - // literal constants below). |
| + // Least significant 2 bits are used as expression type. The third least |
| + // significant bit tracks whether an expression is parenthesized. If the |
| + // expression is an identifier or a string literal, the other bits |
| + // describe the type/ (see PreParserIdentifier::Type and string literal |
| + // constants below). For binary operations, the other bits are flags |
| + // which further describe the contents of the expression. |
| enum { |
| kUnknownExpression = 0, |
| + |
| + kTypeMask = 1 | 2, |
| + kParenthesizedExpression = (1 << 2), |
| + kMultiParenthesizedExpression = (1 << 3), |
| + |
| // Identifiers |
| - kIdentifierFlag = 1, // Used to detect labels. |
| - kIdentifierShift = 3, |
| + kTypeIdentifier = 1, // Used to detect labels. |
| + kIdentifierShift = 5, |
| - kStringLiteralFlag = 2, // Used to detect directive prologue. |
| - kUnknownStringLiteral = kStringLiteralFlag, |
| - kUseStrictString = kStringLiteralFlag | 8, |
| + kTypeStringLiteral = 2, // Used to detect directive prologue. |
| + kUnknownStringLiteral = kTypeStringLiteral, |
| + kUseStrictString = kTypeStringLiteral | 32, |
| kStringLiteralMask = kUseStrictString, |
| + // Binary operations. Those are needed to detect certain keywords and |
| + // duplicated identifier in parameter lists for arrow functions, because |
| + // they are initially parsed as comma-separated expressions. |
| + kTypeBinaryOperation = 3, |
| + kBinaryOperationArrowParamList = (1 << 4), |
| + |
| // Below here applies if neither identifier nor string literal. Reserve the |
| // 2 least significant bits for flags. |
| - kThisExpression = 1 << 2, |
| - kThisPropertyExpression = 2 << 2, |
| - kPropertyExpression = 3 << 2, |
| - kCallExpression = 4 << 2 |
| + kThisExpression = (1 << 4), |
| + kThisPropertyExpression = (2 << 4), |
| + kPropertyExpression = (3 << 4), |
| + kCallExpression = (4 << 4) |
| }; |
| explicit PreParserExpression(int expression_code) : code_(expression_code) {} |
| + V8_INLINE int ArrowParamListBit() const { |
| + if (IsBinaryOperation()) |
| + return code_ & kBinaryOperationArrowParamList; |
| + if (IsIdentifier()) { |
| + const PreParserIdentifier ident = AsIdentifier(); |
| + // A valid identifier can be an arrow function parameter list |
| + // except for eval, arguments, yield, and reserved keywords. |
| + if (ident.IsEval() || ident.IsArguments() || ident.IsYield() |
| + || ident.IsFutureStrictReserved()) |
| + return 0; |
| + return kBinaryOperationArrowParamList; |
| + } |
| + return 0; |
| + } |
| + |
| int code_; |
| }; |
| @@ -768,8 +902,10 @@ class PreParserStatementList { |
| class PreParserScope { |
| public: |
| - explicit PreParserScope(PreParserScope* outer_scope, ScopeType scope_type) |
| - : scope_type_(scope_type) { |
| + explicit PreParserScope(PreParserScope* outer_scope, |
| + ScopeType scope_type, |
| + void* = NULL) |
| + : scope_type_(scope_type), declared_parameters_(0) { |
| strict_mode_ = outer_scope ? outer_scope->strict_mode() : SLOPPY; |
| } |
| @@ -777,9 +913,27 @@ class PreParserScope { |
| StrictMode strict_mode() const { return strict_mode_; } |
| void SetStrictMode(StrictMode strict_mode) { strict_mode_ = strict_mode; } |
| + // TODO(aperezdc): Would allowing lazy compilation in preparser make sense? |
| + bool AllowsLazyCompilation() const { return false; } |
| + |
| + void set_start_position(int position) {} |
| + void set_end_position(int position) {} |
| + |
| + bool IsDeclared(const PreParserIdentifier& identifier) const { |
| + return (declared_parameters_ & (1 << identifier.type_)) != 0; |
| + } |
| + |
| + void DeclareParameter(const PreParserIdentifier& identifier, VariableMode) { |
| + declared_parameters_ |= (1 << identifier.type_); |
| + } |
| + |
| + // Allow scope->Foo() to work. |
| + PreParserScope* operator->() { return this; } |
| + |
| private: |
| ScopeType scope_type_; |
| StrictMode strict_mode_; |
| + int declared_parameters_; |
| }; |
| @@ -840,7 +994,7 @@ class PreParserFactory { |
| PreParserExpression NewBinaryOperation(Token::Value op, |
| PreParserExpression left, |
| PreParserExpression right, int pos) { |
| - return PreParserExpression::Default(); |
| + return PreParserExpression::BinaryOperation(left, op, right); |
| } |
| PreParserExpression NewCompareOperation(Token::Value op, |
| PreParserExpression left, |
| @@ -881,6 +1035,32 @@ class PreParserFactory { |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| + PreParserStatement NewReturnStatement(PreParserExpression expression, |
| + int pos) { |
| + return PreParserStatement::Default(); |
| + } |
| + PreParserExpression |
| + NewFunctionLiteral(PreParserIdentifier name, |
| + PreParserScope& scope, |
| + PreParserStatementList body, |
| + int materialized_literal_count, |
| + int expected_property_count, |
| + int handler_count, |
| + int parameter_count, |
| + FunctionLiteral::ParameterFlag has_duplicate_parameters, |
| + FunctionLiteral::FunctionType function_type, |
| + FunctionLiteral::IsFunctionFlag is_function, |
| + FunctionLiteral::IsParenthesizedFlag is_parenthesized, |
| + FunctionLiteral::IsGeneratorFlag is_generator, |
| + int position) { |
| + return PreParserExpression::Default(); |
| + } |
| + |
| + // Return the object itself as AstVisitor and implement the needed |
| + // dummy method right in this class. |
| + PreParserFactory* visitor() { return this; } |
| + BailoutReason dont_optimize_reason() { return kNoReason; } |
| + int* ast_properties() { static int dummy = 42; return &dummy; } |
| }; |
| @@ -895,11 +1075,16 @@ class PreParserTraits { |
| // Used by FunctionState and BlockState. |
| typedef PreParserScope Scope; |
| + typedef PreParserScope ScopePtr; |
| + |
| // PreParser doesn't need to store generator variables. |
| typedef void GeneratorVariable; |
| // No interaction with Zones. |
| typedef void Zone; |
| + typedef int AstProperties; |
| + typedef Vector<PreParserIdentifier> ParameterIdentifierVector; |
| + |
| // Return types for traversing functions. |
| typedef PreParserIdentifier Identifier; |
| typedef PreParserExpression Expression; |
| @@ -942,6 +1127,10 @@ class PreParserTraits { |
| return expression.AsIdentifier(); |
| } |
| + static bool IsFutureStrictReserved(PreParserIdentifier identifier) { |
| + return identifier.IsYield() || identifier.IsFutureStrictReserved(); |
| + } |
| + |
| static bool IsBoilerplateProperty(PreParserExpression property) { |
| // PreParser doesn't count boilerplate properties. |
| return false; |
| @@ -962,6 +1151,11 @@ class PreParserTraits { |
| // PreParser should not use FuncNameInferrer. |
| UNREACHABLE(); |
| } |
| + static void InferFunctionName(FuncNameInferrer* fni, |
| + PreParserExpression expression) { |
| + // PreParser should not use FuncNameInferrer. |
| + UNREACHABLE(); |
| + } |
| static void CheckFunctionLiteralInsideTopLevelObjectLiteral( |
| PreParserScope* scope, PreParserExpression value, bool* has_function) {} |
| @@ -1005,6 +1199,10 @@ class PreParserTraits { |
| const char* type, Handle<Object> arg, int pos) { |
| return PreParserExpression::Default(); |
| } |
| + PreParserScope NewScope(PreParserScope* outer_scope, |
| + ScopeType scope_type) { |
| + return PreParserScope(outer_scope, scope_type); |
| + } |
| // Reporting errors. |
| void ReportMessageAt(Scanner::Location location, |
| @@ -1021,9 +1219,15 @@ class PreParserTraits { |
| static PreParserIdentifier EmptyIdentifier() { |
| return PreParserIdentifier::Default(); |
| } |
| + static PreParserIdentifier EmptyIdentifierString() { |
| + return PreParserIdentifier::Default(); |
| + } |
| static PreParserExpression EmptyExpression() { |
| return PreParserExpression::Default(); |
| } |
| + static PreParserExpression EmptyArrowParamList() { |
| + return PreParserExpression::EmptyArrowParamList(); |
| + } |
| static PreParserExpression EmptyLiteral() { |
| return PreParserExpression::Default(); |
| } |
| @@ -1045,7 +1249,8 @@ class PreParserTraits { |
| } |
| static PreParserExpression ThisExpression(PreParserScope* scope, |
| - PreParserFactory* factory) { |
| + PreParserFactory* factory, |
| + int pos) { |
| return PreParserExpression::This(); |
| } |
| @@ -1077,6 +1282,37 @@ class PreParserTraits { |
| return PreParserExpressionList(); |
| } |
| + V8_INLINE void SkipLazyFunctionBody( |
| + PreParserIdentifier function_name, |
| + int* materialized_literal_count, |
| + int* expected_property_count, |
| + bool* ok) { |
| + UNREACHABLE(); |
| + } |
| + |
| + V8_INLINE PreParserStatementList ParseEagerFunctionBody( |
| + PreParserIdentifier function_name, |
| + int pos, |
| + Variable* fvar, |
| + Token::Value fvar_init_op, |
| + bool is_generator, |
| + bool* ok); |
| + |
| + // Utility functions |
| + Vector<PreParserIdentifier> ParameterListFromExpression( |
| + PreParserExpression expression) { |
| + return Vector<PreParserIdentifier>::empty(); |
| + } |
| + bool IsValidArrowFunctionParameterList(PreParserExpression expression) { |
| + // TODO(aperez): Detect duplicated identifiers in paramlists. |
| + return expression.IsValidArrowParamList(); |
| + } |
| + static AstValueFactory* ast_value_factory() { return NULL; } |
| + |
| + void CheckConflictingVarDeclarations( |
| + PreParserScope scope, |
| + bool* ok) {} |
| + |
| // Temporary glue; these functions will move to ParserBase. |
| PreParserExpression ParseV8Intrinsic(bool* ok); |
| PreParserExpression ParseFunctionLiteral( |
| @@ -1127,7 +1363,8 @@ class PreParser : public ParserBase<PreParserTraits> { |
| // during parsing. |
| PreParseResult PreParseProgram() { |
| PreParserScope scope(scope_, GLOBAL_SCOPE); |
| - FunctionState top_scope(&function_state_, &scope_, &scope, NULL); |
| + FunctionState top_scope(&function_state_, &scope_, &scope, |
| + zone(), this->ast_value_factory()); |
| bool ok = true; |
| int start_position = scanner()->peek_location().beg_pos; |
| ParseSourceElements(Token::EOS, &ok); |
| @@ -1209,6 +1446,19 @@ class PreParser : public ParserBase<PreParserTraits> { |
| Expression ParseObjectLiteral(bool* ok); |
| Expression ParseV8Intrinsic(bool* ok); |
| + V8_INLINE void SkipLazyFunctionBody( |
| + PreParserIdentifier function_name, |
| + int* materialized_literal_count, |
| + int* expected_property_count, |
| + bool* ok); |
| + V8_INLINE PreParserStatementList ParseEagerFunctionBody( |
| + PreParserIdentifier function_name, |
| + int pos, |
| + Variable* fvar, |
| + Token::Value fvar_init_op, |
| + bool is_generator, |
| + bool* ok); |
| + |
| Expression ParseFunctionLiteral( |
| Identifier name, |
| Scanner::Location function_name_location, |
| @@ -1223,6 +1473,36 @@ class PreParser : public ParserBase<PreParserTraits> { |
| bool CheckInOrOf(bool accept_OF); |
| }; |
| + |
| +PreParserStatementList PreParser::ParseEagerFunctionBody( |
| + PreParserIdentifier function_name, |
| + int pos, |
| + Variable* fvar, |
| + Token::Value fvar_init_op, |
| + bool is_generator, |
| + bool* ok) { |
| + ParsingModeScope parsing_mode(this, PARSE_EAGERLY); |
| + |
| + ParseSourceElements(Token::RBRACE, ok); |
| + if (!*ok) return PreParserStatementList(); |
| + |
| + Expect(Token::RBRACE, ok); |
| + return PreParserStatementList(); |
| +} |
| + |
| + |
| +PreParserStatementList PreParserTraits::ParseEagerFunctionBody( |
| + PreParserIdentifier function_name, |
| + int pos, |
| + Variable* fvar, |
| + Token::Value fvar_init_op, |
| + bool is_generator, |
| + bool* ok) { |
| + return pre_parser_->ParseEagerFunctionBody(function_name, |
| + pos, fvar, fvar_init_op, is_generator, ok); |
| +} |
| + |
| + |
| template<class Traits> |
| ParserBase<Traits>::FunctionState::FunctionState( |
| FunctionState** function_state_stack, |
| @@ -1249,6 +1529,31 @@ ParserBase<Traits>::FunctionState::FunctionState( |
| template<class Traits> |
| +ParserBase<Traits>::FunctionState::FunctionState( |
| + FunctionState** function_state_stack, |
| + typename Traits::Type::Scope** scope_stack, |
| + typename Traits::Type::Scope** scope, |
| + typename Traits::Type::Zone* extra_param, |
| + AstValueFactory* ast_value_factory) |
| + : next_materialized_literal_index_(JSFunction::kLiteralsPrefixSize), |
| + next_handler_index_(0), |
| + expected_property_count_(0), |
| + is_generator_(false), |
| + generator_object_variable_(NULL), |
| + function_state_stack_(function_state_stack), |
| + outer_function_state_(*function_state_stack), |
| + scope_stack_(scope_stack), |
| + outer_scope_(*scope_stack), |
| + saved_ast_node_id_(0), |
| + extra_param_(extra_param), |
| + factory_(extra_param, ast_value_factory) { |
| + *scope_stack_ = *scope; |
| + *function_state_stack = this; |
| + Traits::SetUpFunctionState(this, extra_param); |
| +} |
| + |
| + |
| +template<class Traits> |
| ParserBase<Traits>::FunctionState::~FunctionState() { |
| *scope_stack_ = outer_scope_; |
| *function_state_stack_ = outer_function_state_; |
| @@ -1415,7 +1720,7 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
| switch (token) { |
| case Token::THIS: { |
| Consume(Token::THIS); |
| - result = this->ThisExpression(scope_, factory()); |
| + result = this->ThisExpression(scope_, factory(), position()); |
| break; |
| } |
| @@ -1460,11 +1765,21 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
| case Token::LPAREN: |
| Consume(Token::LPAREN); |
| - // Heuristically try to detect immediately called functions before |
| - // seeing the call parentheses. |
| - parenthesized_function_ = (peek() == Token::FUNCTION); |
| - result = this->ParseExpression(true, CHECK_OK); |
| - Expect(Token::RPAREN, CHECK_OK); |
| + if (allow_arrow_functions() && peek() == Token::RPAREN) { |
| + // Arrow functions are the only expression type constructions |
| + // for which an empty parameter list "()" is valid input. |
| + Consume(Token::RPAREN); |
| + return this->ParseArrowFunctionLiteral(pos, |
| + this->EmptyArrowParamList(), |
| + CHECK_OK); |
| + } else { |
| + // Heuristically try to detect immediately called functions before |
| + // seeing the call parentheses. |
| + parenthesized_function_ = (peek() == Token::FUNCTION); |
| + result = this->ParseExpression(true, CHECK_OK); |
| + result->set_is_parenthesized(true); |
| + Expect(Token::RPAREN, CHECK_OK); |
| + } |
| break; |
| case Token::MOD: |
| @@ -1732,6 +2047,7 @@ typename ParserBase<Traits>::ExpressionT |
| ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, bool* ok) { |
| // AssignmentExpression :: |
| // ConditionalExpression |
| + // ArrowFunction |
| // YieldExpression |
| // LeftHandSideExpression AssignmentOperator AssignmentExpression |
| @@ -1745,6 +2061,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, bool* ok) { |
| ExpressionT expression = |
| this->ParseConditionalExpression(accept_IN, CHECK_OK); |
| + if (allow_arrow_functions() && peek() == Token::ARROW) |
| + return this->ParseArrowFunctionLiteral(lhs_location.beg_pos, |
| + expression, |
| + CHECK_OK); |
| + |
| if (!Token::IsAssignmentOp(peek())) { |
| if (fni_ != NULL) fni_->Leave(); |
| // Parsed conditional expression only (no assignment). |
| @@ -2150,6 +2471,216 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression, |
| } |
| +template <class Traits> |
| +typename ParserBase<Traits>::ExpressionT |
| +ParserBase<Traits>::ParseArrowFunctionLiteralBody( |
|
marja
2014/06/26 14:38:13
Nit: reorder the functions here to match the order
|
| + FunctionState* function_state, |
| + typename Traits::Type::ScopePtr scope, |
| + int num_parameters, |
| + const Scanner::Location& eval_args_error_loc, |
| + const Scanner::Location& dupe_error_loc, |
| + const Scanner::Location& reserved_loc, |
| + FunctionLiteral::IsParenthesizedFlag parenthesized, |
| + int start_pos, |
| + bool* ok) { |
| + |
| + typename Traits::Type::StatementList body; |
| + int materialized_literal_count = -1; |
| + int expected_property_count = -1; |
| + |
| + Expect(Token::ARROW, CHECK_OK); |
| + |
| + if (peek() == Token::LBRACE) { |
| + // Multiple statemente body |
| + Consume(Token::LBRACE); |
| + |
| + bool is_lazily_parsed = (mode() == PARSE_LAZILY && |
| + scope_->AllowsLazyCompilation() && |
| + !parenthesized_function_); |
| + parenthesized_function_ = false; // This Was set for this funciton only. |
|
marja
2014/06/26 14:38:13
1) Why do you need to set parenthesized_function_
|
| + |
| + if (is_lazily_parsed) { |
| + this->SkipLazyFunctionBody(this->EmptyIdentifier(), |
| + &materialized_literal_count, |
| + &expected_property_count, |
| + CHECK_OK); |
| + } else { |
| + body = this->ParseEagerFunctionBody(this->EmptyIdentifier(), |
| + RelocInfo::kNoPosition, |
| + NULL, |
| + Token::INIT_VAR, |
| + false, // Not a generator. |
| + CHECK_OK); |
| + } |
| + } else { |
| + // Single-expression body |
| + parenthesized_function_ = false; |
| + ParseAssignmentExpression(true, CHECK_OK); |
| + } |
| + |
| + scope->set_start_position(start_pos); |
| + scope->set_end_position(scanner()->location().end_pos); |
| + |
| + this->CheckStrictFunctionNameAndParameters(this->EmptyIdentifier(), |
| + false, |
| + Scanner::Location::invalid(), |
| + Scanner::Location::invalid(), |
| + dupe_error_loc, |
| + Scanner::Location::invalid(), |
| + CHECK_OK); |
| + |
| + // Validate strict mode. |
| + if (strict_mode() == STRICT) { |
| + CheckOctalLiteral(start_pos, |
| + scanner()->location().end_pos, |
| + CHECK_OK); |
| + } |
| + |
| + if (allow_harmony_scoping() && strict_mode() == STRICT) |
| + this->CheckConflictingVarDeclarations(scope, CHECK_OK); |
| + |
| + return this->EmptyExpression(); |
| +} |
| + |
| + |
| +template <class Traits> |
| +typename ParserBase<Traits>::ExpressionT |
| +ParserBase<Traits>::ParseArrowFunctionLiteral(bool* ok) { |
| + // TODO(aperez): Change this to use ARROW_SCOPE |
| + typename Traits::Type::ScopePtr scope = |
| + this->NewScope(scope_, FUNCTION_SCOPE); |
| + |
| + FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ |
| + ? FunctionLiteral::kIsParenthesized |
| + : FunctionLiteral::kNotParenthesized; |
| + parenthesized_function_ = false; |
| + |
| + int start_pos = position(); |
| + int num_parameters = 0; |
| + FunctionState function_state(&function_state_, &scope_, &scope, |
| + zone(), this->ast_value_factory()); |
| + |
| + Scanner::Location eval_args_error_loc = Scanner::Location::invalid(); |
| + Scanner::Location dupe_error_loc = Scanner::Location::invalid(); |
| + Scanner::Location reserved_loc = Scanner::Location::invalid(); |
| + |
| + if (peek() == Token::LPAREN) { |
| + // Parse a parenthesized parameter list. |
| + Consume(Token::LPAREN); |
| + bool done = (peek() == Token::RPAREN); |
| + while (!done) { |
| + bool is_strict_reserved = false; |
| + IdentifierT param_name = |
| + ParseIdentifierOrStrictReservedWord(&is_strict_reserved, |
| + CHECK_OK); |
| + |
| + // Store locations for possible future error reports. |
| + if (!eval_args_error_loc.IsValid() && |
| + this->IsEvalOrArguments(param_name)) { |
| + eval_args_error_loc = scanner()->location(); |
| + } |
| + if (!reserved_loc.IsValid() && is_strict_reserved) { |
| + reserved_loc = scanner()->location(); |
| + } |
| + if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { |
| + dupe_error_loc = scanner()->location(); |
| + } |
| + |
| + scope_->DeclareParameter(param_name, VAR); |
| + num_parameters++; |
| + if (num_parameters > Code::kMaxArguments) { |
| + this->ReportMessageAt(scanner()->location(), "too_many_parameters"); |
| + *ok = false; |
| + return this->EmptyExpression(); |
| + } |
| + done = (peek() == Token::RPAREN); |
| + if (!done) Expect(Token::COMMA, CHECK_OK); |
| + } |
| + Expect(Token::RPAREN, CHECK_OK); |
| + } else { |
| + // Parse a single parameter identifier. |
| + bool is_strict_reserved = false; |
| + IdentifierT param_name = |
| + ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| + |
| + // Store locations for possible future error reports. |
| + if (this->IsEvalOrArguments(param_name)) |
| + eval_args_error_loc = scanner()->location(); |
| + if (is_strict_reserved) |
| + reserved_loc = scanner()->location(); |
| + |
| + scope_->DeclareParameter(param_name, VAR); |
| + } |
| + |
| + return ParseArrowFunctionLiteralBody(&function_state, |
| + scope, |
| + num_parameters, |
| + eval_args_error_loc, |
| + dupe_error_loc, |
| + reserved_loc, |
| + parenthesized, |
| + start_pos, |
| + CHECK_OK); |
| +} |
| + |
| + |
| +template <class Traits> |
| +typename ParserBase<Traits>::ExpressionT |
| +ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
| + ExpressionT params_ast, |
| + bool* ok) { |
| + if (!this->IsValidArrowFunctionParameterList(params_ast)) { |
| + ReportMessageAt( |
| + Scanner::Location(start_pos, scanner()->location().beg_pos), |
| + "strict_parameter_list"); |
| + *ok = false; |
| + return this->EmptyExpression(); |
| + } |
| + |
| + // TODO(aperez): Change this to use ARROW_SCOPE |
| + typename Traits::Type::ScopePtr scope = |
| + this->NewScope(scope_, FUNCTION_SCOPE); |
| + |
| + FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_ |
| + ? FunctionLiteral::kIsParenthesized |
| + : FunctionLiteral::kNotParenthesized; |
| + parenthesized_function_ = false; |
| + FunctionState function_state(&function_state_, &scope_, &scope, |
| + zone(), this->ast_value_factory()); |
| + typename Traits::Type::ParameterIdentifierVector params = |
| + Traits::ParameterListFromExpression(params_ast); |
| + Scanner::Location dupe_error_loc = Scanner::Location::invalid(); |
| + |
| + if (params.length() > Code::kMaxArguments) { |
| + ReportMessageAt(Scanner::Location(params_ast->position(), position()), |
| + "too_many_parameters"); |
| + *ok = false; |
| + return this->EmptyExpression(); |
| + } |
| + |
| + // The vector has the items in reverse order. |
| + for (int i = params.length() - 1; i >= 0; --i) { |
| + const IdentifierT param_name = params.at(i)->raw_name(); |
| + if (!dupe_error_loc.IsValid() && scope_->IsDeclared(param_name)) { |
| + int param_pos = params.at(i)->position(); |
| + dupe_error_loc = Scanner::Location(param_pos, |
| + param_pos + param_name->length()); |
| + } |
| + scope_->DeclareParameter(param_name, VAR); |
| + } |
| + |
| + return ParseArrowFunctionLiteralBody(&function_state, |
| + scope, |
| + params.length(), |
| + Scanner::Location::invalid(), |
| + dupe_error_loc, |
| + Scanner::Location::invalid(), |
| + parenthesized, |
| + start_pos, |
| + CHECK_OK); |
| +} |
| + |
| + |
| template <typename Traits> |
| typename ParserBase<Traits>::ExpressionT |
| ParserBase<Traits>::CheckAndRewriteReferenceExpression( |