| 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(
|
|
|