Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 287c26bf742ecd2ab89fd80945317e6b13f1d592..a6b9462ebb331c73b8f1e6fc2fc5fc4abda20507 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -61,6 +61,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, |
@@ -82,6 +83,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 |
@@ -90,6 +92,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 { |
@@ -102,6 +105,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); |
@@ -151,6 +155,12 @@ class ParserBase : public Traits { |
typename Traits::Type::Scope* scope, |
typename Traits::Type::Zone* zone = NULL, |
AstValueFactory* ast_value_factory = NULL); |
+ 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() { |
@@ -334,6 +344,44 @@ class ParserBase : public Traits { |
} |
} |
+ // Validates strict mode for function parameter lists. This has to be |
+ // done after parsing the function, since the function can declare |
+ // itself strict. |
+ void CheckStrictFunctionNameAndParameters( |
+ IdentifierT function_name, |
+ bool function_name_is_strict_reserved, |
+ const Scanner::Location& function_name_loc, |
+ const Scanner::Location& eval_args_error_loc, |
+ const Scanner::Location& dupe_error_loc, |
+ const Scanner::Location& reserved_loc, |
+ bool* ok) { |
+ if (this->IsEvalOrArguments(function_name)) { |
+ Traits::ReportMessageAt(function_name_loc, "strict_eval_arguments"); |
+ *ok = false; |
+ return; |
+ } |
+ if (function_name_is_strict_reserved) { |
+ Traits::ReportMessageAt(function_name_loc, "unexpected_strict_reserved"); |
+ *ok = false; |
+ return; |
+ } |
+ if (eval_args_error_loc.IsValid()) { |
+ Traits::ReportMessageAt(eval_args_error_loc, "strict_eval_arguments"); |
+ *ok = false; |
+ return; |
+ } |
+ if (dupe_error_loc.IsValid()) { |
+ Traits::ReportMessageAt(dupe_error_loc, "strict_param_dupe"); |
+ *ok = false; |
+ return; |
+ } |
+ if (reserved_loc.IsValid()) { |
+ Traits::ReportMessageAt(reserved_loc, "unexpected_strict_reserved"); |
+ *ok = false; |
+ return; |
+ } |
+ } |
+ |
// Determine precedence of given token. |
static int Precedence(Token::Value token, bool accept_IN) { |
if (token == Token::IN && !accept_IN) |
@@ -404,6 +452,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); |
+ 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. |
@@ -487,6 +560,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. |
}; |
@@ -513,16 +587,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 { |
+ if (IsEval()) return 4; |
+ if (IsArguments()) return 9; |
+ if (IsYield()) return 5; |
+ return 0; |
+ } |
+ |
private: |
enum Type { |
kUnknownIdentifier, |
@@ -536,6 +626,7 @@ class PreParserIdentifier { |
Type type_; |
friend class PreParserExpression; |
+ friend class PreParserScope; |
}; |
@@ -551,10 +642,25 @@ class PreParserExpression { |
} |
static PreParserExpression FromIdentifier(PreParserIdentifier id) { |
- return PreParserExpression(kIdentifierFlag | |
+ return PreParserExpression(kTypeIdentifier | |
(id.type_ << kIdentifierShift)); |
} |
+ static PreParserExpression BinaryOperation(PreParserExpression left, |
+ PreParserExpression right) { |
+ int left_bits = left.BinaryOperationBits(); |
+ int right_bits = right.BinaryOperationBits(); |
+ |
+ int code = left_bits | right_bits; |
+ if (left_bits & right_bits & kBinaryOperationHasEval) |
+ code |= kBinaryOperationHasDuplicatedIdentifier; |
+ else if (left_bits & right_bits & kBinaryOperationHasArguments) |
+ code |= kBinaryOperationHasDuplicatedIdentifier; |
+ // TODO(aperezdc): Handle other duplicate identifier |
+ |
+ return PreParserExpression(kTypeBinaryOperation | code); |
+ } |
+ |
static PreParserExpression StringLiteral() { |
return PreParserExpression(kUnknownStringLiteral); |
} |
@@ -579,18 +685,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; } |
@@ -613,6 +723,10 @@ class PreParserExpression { |
PreParserExpression AsFunctionLiteral() { return *this; } |
+ bool IsBinaryOperation() const { |
+ return (code_ & kTypeMask) == kTypeBinaryOperation; |
+ } |
+ |
// Dummy implementation for making expression->somefunc() work in both Parser |
// and PreParser. |
PreParserExpression* operator->() { return this; } |
@@ -621,23 +735,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 HasEval() const { |
+ if (IsBinaryOperation()) return (code_ & kBinaryOperationHasEval) != 0; |
+ if (IsIdentifier()) return AsIdentifier().IsEval(); |
+ return false; |
+ } |
+ |
+ bool HasArguments() const { |
+ if (IsBinaryOperation()) return (code_ & kBinaryOperationHasArguments) != 0; |
+ if (IsIdentifier()) return AsIdentifier().IsArguments(); |
+ return false; |
+ } |
+ |
+ bool HasFutureStrictReserved() const { |
+ if (IsBinaryOperation()) |
+ return (code_ & kBinaryOperationHasFutureStrictReserved) != 0; |
+ if (IsIdentifier()) |
+ return (AsIdentifier().IsFutureStrictReserved() || |
+ AsIdentifier().IsYield()); |
+ return false; |
+ } |
+ bool HasDuplicatedIdentifier() const { |
+ return IsBinaryOperation() && |
+ (code_ & kBinaryOperationHasDuplicatedIdentifier) != 0; |
+ } |
+ |
+ 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. 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, |
+ |
// Identifiers |
- kIdentifierFlag = 1, // Used to detect labels. |
+ kTypeIdentifier = 1, // Used to detect labels. |
kIdentifierShift = 3, |
- kStringLiteralFlag = 2, // Used to detect directive prologue. |
- kUnknownStringLiteral = kStringLiteralFlag, |
- kUseStrictString = kStringLiteralFlag | 8, |
+ kTypeStringLiteral = 2, // Used to detect directive prologue. |
+ kUnknownStringLiteral = kTypeStringLiteral, |
+ kUseStrictString = kTypeStringLiteral | 8, |
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, |
+ kBinaryOperationHasEval = 1 << 2, |
+ kBinaryOperationHasArguments = 2 << 2, |
+ kBinaryOperationHasFutureStrictReserved = 4 << 2, |
+ kBinaryOperationHasDuplicatedIdentifier = 8 << 2, |
+ |
// Below here applies if neither identifier nor string literal. Reserve the |
// 2 least significant bits for flags. |
kThisExpression = 1 << 2, |
@@ -648,6 +811,18 @@ class PreParserExpression { |
explicit PreParserExpression(int expression_code) : code_(expression_code) {} |
+ V8_INLINE int BinaryOperationBits() const { |
+ if (IsBinaryOperation()) return code_; |
+ if (IsIdentifier()) { |
+ const PreParserIdentifier ident = AsIdentifier(); |
+ if (ident.IsEval()) return kBinaryOperationHasEval; |
+ if (ident.IsArguments()) return kBinaryOperationHasArguments; |
+ if (ident.IsYield() || ident.IsFutureStrictReserved()) |
+ return kBinaryOperationHasFutureStrictReserved; |
+ } |
+ return 0; |
+ } |
+ |
int code_; |
}; |
@@ -729,8 +904,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; |
} |
@@ -738,9 +915,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_; |
}; |
@@ -801,7 +996,7 @@ class PreParserFactory { |
PreParserExpression NewBinaryOperation(Token::Value op, |
PreParserExpression left, |
PreParserExpression right, int pos) { |
- return PreParserExpression::Default(); |
+ return PreParserExpression::BinaryOperation(left, right); |
} |
PreParserExpression NewCompareOperation(Token::Value op, |
PreParserExpression left, |
@@ -842,6 +1037,33 @@ class PreParserFactory { |
int pos) { |
return PreParserExpression::Default(); |
} |
+ PreParserStatement NewReturnStatement(PreParserExpression expression, |
+ int pos) { |
+ return PreParserStatement::Default(); |
+ } |
+ PreParserExpression |
+ NewFunctionLiteral(PreParserIdentifier name, |
+ AstValueFactory* ast_value_factory, |
+ 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; } |
}; |
@@ -856,11 +1078,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; |
@@ -903,6 +1130,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; |
@@ -923,6 +1154,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) {} |
@@ -941,6 +1177,8 @@ class PreParserTraits { |
return expression; |
} |
+ static AstValueFactory* ast_value_factory() { return NULL; } |
+ |
bool ShortcutNumericLiteralBinaryExpression(PreParserExpression* x, |
PreParserExpression y, |
Token::Value op, |
@@ -966,6 +1204,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, |
@@ -982,6 +1224,9 @@ class PreParserTraits { |
static PreParserIdentifier EmptyIdentifier() { |
return PreParserIdentifier::Default(); |
} |
+ static PreParserIdentifier EmptyIdentifierString() { |
+ return PreParserIdentifier::Default(); |
+ } |
static PreParserExpression EmptyExpression() { |
return PreParserExpression::Default(); |
} |
@@ -1006,7 +1251,8 @@ class PreParserTraits { |
} |
static PreParserExpression ThisExpression(PreParserScope* scope, |
- PreParserFactory* factory) { |
+ PreParserFactory* factory, |
+ int pos) { |
return PreParserExpression::This(); |
} |
@@ -1038,6 +1284,30 @@ 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 |
+ V8_INLINE Vector<PreParserIdentifier> ParameterListFromExpression( |
+ PreParserExpression expression, bool* ok); |
+ |
+ void CheckConflictingVarDeclarations( |
+ PreParserScope scope, |
+ bool* ok) {} |
+ |
// Temporary glue; these functions will move to ParserBase. |
PreParserExpression ParseV8Intrinsic(bool* ok); |
PreParserExpression ParseFunctionLiteral( |
@@ -1087,7 +1357,7 @@ 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, NULL, NULL); |
bool ok = true; |
int start_position = scanner()->peek_location().beg_pos; |
ParseSourceElements(Token::EOS, &ok); |
@@ -1169,6 +1439,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, |
@@ -1182,6 +1465,57 @@ 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); |
+} |
+ |
+ |
+Vector<PreParserIdentifier> PreParserTraits::ParameterListFromExpression( |
+ PreParserExpression expression, bool* ok) { |
+ Collector<PreParserIdentifier> collector; |
+ |
+ if (expression.HasEval()) |
+ collector.Add(PreParserIdentifier::Eval()); |
+ if (expression.HasArguments()) |
+ collector.Add(PreParserIdentifier::Arguments()); |
+ if (expression.HasFutureStrictReserved()) |
+ collector.Add(PreParserIdentifier::FutureStrictReserved()); |
+ |
+ if (expression.HasDuplicatedIdentifier() || |
+ pre_parser_->scanner()->parameter_list()->HasDuplicateIdentifiers()) { |
+ collector.Add(PreParserIdentifier::Default()); |
+ collector.Add(PreParserIdentifier::Default()); |
+ } |
+ |
+ return collector.ToVector(); |
+} |
+ |
+ |
template<class Traits> |
ParserBase<Traits>::FunctionState::FunctionState( |
FunctionState** function_state_stack, |
@@ -1208,6 +1542,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_; |
@@ -1374,7 +1733,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; |
} |
@@ -1419,11 +1778,20 @@ 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->EmptyExpression(), |
+ 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); |
+ Expect(Token::RPAREN, CHECK_OK); |
+ } |
break; |
case Token::MOD: |
@@ -1692,6 +2060,7 @@ typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, bool* ok) { |
// AssignmentExpression :: |
// ConditionalExpression |
+ // ArrowFunction |
// YieldExpression |
// LeftHandSideExpression AssignmentOperator AssignmentExpression |
@@ -1705,6 +2074,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). |
@@ -2109,6 +2483,233 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression, |
} |
+template <class Traits> |
+typename ParserBase<Traits>::ExpressionT |
+ParserBase<Traits>::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) { |
+ |
+ 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. |
+ |
+ 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); |
+ |
+ // Validate strict mode. |
+ if (strict_mode() == STRICT) { |
+ CheckStrictFunctionNameAndParameters(this->EmptyIdentifierString(), |
+ false, |
+ Scanner::Location::invalid(), |
+ eval_args_error_loc, |
+ dupe_error_loc, |
+ reserved_loc, |
+ CHECK_OK); |
+ 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); |
+ } |
+ |
+ ExpressionT literal = ParseArrowFunctionLiteralBody(&function_state, |
+ scope, |
+ num_parameters, |
+ eval_args_error_loc, |
+ dupe_error_loc, |
+ reserved_loc, |
+ parenthesized, |
+ start_pos, |
+ CHECK_OK); |
+ return literal; |
+} |
+ |
+ |
+template <class Traits> |
+typename ParserBase<Traits>::ExpressionT |
+ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
+ ExpressionT params_ast, |
+ 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; |
+ |
+ 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 (!scanner()->parameter_list()->IsValid(start_pos)) { |
+ ReportMessageAt(Scanner::Location(start_pos, position()), |
+ "malformed_parameter_list"); |
+ *ok = false; |
+ return this->EmptyExpression(); |
+ } |
+ |
+ // Function parameters are already parsed into an AST |
+ typename Traits::Type::ParameterIdentifierVector params = |
+ Traits::ParameterListFromExpression(params_ast, CHECK_OK); |
+ |
+ 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) { |
+ IdentifierT param_name = params.at(i)->raw_name(); |
+ int param_pos = params.at(i)->position(); |
+ |
+ // Store locations for possible future error reports. |
+ if (!eval_args_error_loc.IsValid() && this->IsEvalOrArguments(param_name)) { |
+ eval_args_error_loc = |
+ 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()); |
+ } |
+ if (!reserved_loc.IsValid() && this->IsFutureStrictReserved(param_name)) { |
+ reserved_loc = |
+ Scanner::Location(param_pos, param_pos + param_name->length()); |
+ } |
+ |
+ scope_->DeclareParameter(param_name, VAR); |
+ } |
+ |
+ ExpressionT literal = ParseArrowFunctionLiteralBody(&function_state, |
+ scope, |
+ params.length(), |
+ eval_args_error_loc, |
+ dupe_error_loc, |
+ reserved_loc, |
+ parenthesized, |
+ start_pos, |
+ CHECK_OK); |
+ return literal; |
+} |
+ |
+ |
template <typename Traits> |
typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::CheckAndRewriteReferenceExpression( |