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

Unified Diff: src/preparser.h

Issue 160073006: Implement handling of arrow functions in the parser (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Version with parsing code only, tests into test-parsing.cc Created 6 years, 6 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
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(

Powered by Google App Engine
This is Rietveld 408576698