Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 0440d831eea5105552c2c268534faead9ff44f0e..b46d41f2331f9bd3fd3a6bd1810fc5ed5ec2a9a6 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -17,6 +17,26 @@ |
namespace v8 { |
namespace internal { |
+ |
+// When parsing the formal parameters of a function, we usually don't yet know |
+// if the function will be strict, so we cannot yet produce errors for |
+// parameter names or duplicates. Instead, we remember the locations of these |
+// errors if they occur and produce the errors later. |
+class FormalParameterErrorLocations BASE_EMBEDDED { |
+ public: |
+ FormalParameterErrorLocations() |
+ : eval_or_arguments(Scanner::Location::invalid()), |
+ undefined(Scanner::Location::invalid()), |
+ duplicate(Scanner::Location::invalid()), |
+ reserved(Scanner::Location::invalid()) {} |
+ |
+ Scanner::Location eval_or_arguments; |
+ Scanner::Location undefined; |
+ Scanner::Location duplicate; |
+ Scanner::Location reserved; |
+}; |
+ |
+ |
// Common base class shared between parser and pre-parser. Traits encapsulate |
// the differences between Parser and PreParser: |
@@ -51,6 +71,8 @@ namespace internal { |
// typedef Literal; |
// typedef ExpressionList; |
// typedef PropertyList; |
+// typedef FormalParameter; |
+// typedef FormalParameterScope; |
// // For constructing objects returned by the traversing functions. |
// typedef Factory; |
// }; |
@@ -63,6 +85,8 @@ 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::FormalParameter FormalParameterT; |
+ typedef typename Traits::Type::FormalParameterScope FormalParameterScopeT; |
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT; |
typedef typename Traits::Type::Literal LiteralT; |
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT; |
@@ -495,31 +519,28 @@ class ParserBase : public Traits { |
// after parsing the function, since the function can declare itself strict. |
void CheckFunctionParameterNames(LanguageMode language_mode, |
bool strict_params, |
- const Scanner::Location& eval_args_loc, |
- const Scanner::Location& undefined_loc, |
- const Scanner::Location& dupe_loc, |
- const Scanner::Location& reserved_loc, |
+ const FormalParameterErrorLocations& locs, |
bool* ok) { |
if (is_sloppy(language_mode) && !strict_params) return; |
- if (is_strict(language_mode) && eval_args_loc.IsValid()) { |
- Traits::ReportMessageAt(eval_args_loc, "strict_eval_arguments"); |
+ if (is_strict(language_mode) && locs.eval_or_arguments.IsValid()) { |
+ Traits::ReportMessageAt(locs.eval_or_arguments, "strict_eval_arguments"); |
*ok = false; |
return; |
} |
- if (is_strong(language_mode) && undefined_loc.IsValid()) { |
- Traits::ReportMessageAt(undefined_loc, "strong_undefined"); |
+ if (is_strong(language_mode) && locs.undefined.IsValid()) { |
+ Traits::ReportMessageAt(locs.undefined, "strong_undefined"); |
*ok = false; |
return; |
} |
// TODO(arv): When we add support for destructuring in setters we also need |
// to check for duplicate names. |
- if (dupe_loc.IsValid()) { |
- Traits::ReportMessageAt(dupe_loc, "strict_param_dupe"); |
+ if (locs.duplicate.IsValid()) { |
+ Traits::ReportMessageAt(locs.duplicate, "strict_param_dupe"); |
*ok = false; |
return; |
} |
- if (reserved_loc.IsValid()) { |
- Traits::ReportMessageAt(reserved_loc, "unexpected_strict_reserved"); |
+ if (locs.reserved.IsValid()) { |
+ Traits::ReportMessageAt(locs.reserved, "unexpected_strict_reserved"); |
*ok = false; |
return; |
} |
@@ -606,6 +627,16 @@ class ParserBase : public Traits { |
void AddTemplateExpression(ExpressionT); |
ExpressionT ParseSuperExpression(bool is_new, bool* ok); |
+ void ParseFormalParameter(FormalParameterScopeT* scope, |
+ FormalParameterErrorLocations* locs, bool is_rest, |
+ bool* ok); |
+ int ParseFormalParameterList(FormalParameterScopeT* scope, |
+ FormalParameterErrorLocations* locs, |
+ bool* has_rest, bool* ok); |
+ void CheckArityRestrictions( |
+ int param_count, FunctionLiteral::ArityRestriction arity_restriction, |
+ int formals_start_pos, int formals_end_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. |
@@ -911,7 +942,7 @@ class PreParserExpression { |
return IsIdentifier() || IsProperty(); |
} |
- bool IsValidArrowParamList(Scanner::Location* undefined_loc) const { |
+ bool IsValidArrowParamList(FormalParameterErrorLocations* locs) const { |
ValidArrowParam valid = ValidateArrowParams(); |
if (ParenthesizationField::decode(code_) == kMultiParenthesizedExpression) { |
return false; |
@@ -921,7 +952,7 @@ class PreParserExpression { |
} else if (valid == kInvalidStrongArrowParam) { |
// Return true for now regardless of strong mode for compatibility with |
// parser. |
- *undefined_loc = Scanner::Location(); |
+ locs->undefined = Scanner::Location(); |
return true; |
} else { |
return false; |
@@ -1040,20 +1071,24 @@ class PreParserExpression { |
}; |
-// PreParserExpressionList doesn't actually store the expressions because |
-// PreParser doesn't need to. |
-class PreParserExpressionList { |
+// The pre-parser doesn't need to build lists of expressions, identifiers, or |
+// the like. |
+template <typename T> |
+class PreParserList { |
public: |
// These functions make list->Add(some_expression) work (and do nothing). |
- PreParserExpressionList() : length_(0) {} |
- PreParserExpressionList* operator->() { return this; } |
- void Add(PreParserExpression, void*) { ++length_; } |
+ PreParserList() : length_(0) {} |
+ PreParserList* operator->() { return this; } |
+ void Add(T, void*) { ++length_; } |
int length() const { return length_; } |
private: |
int length_; |
}; |
+typedef PreParserList<PreParserExpression> PreParserExpressionList; |
+ |
+ |
class PreParserStatement { |
public: |
static PreParserStatement Default() { |
@@ -1118,16 +1153,7 @@ class PreParserStatement { |
}; |
- |
-// PreParserStatementList doesn't actually store the statements because |
-// the PreParser does not need them. |
-class PreParserStatementList { |
- public: |
- // These functions make list->Add(some_expression) work as no-ops. |
- PreParserStatementList() {} |
- PreParserStatementList* operator->() { return this; } |
- void Add(PreParserStatement, void*) {} |
-}; |
+typedef PreParserList<PreParserStatement> PreParserStatementList; |
class PreParserFactory { |
@@ -1292,6 +1318,8 @@ class PreParserTraits { |
typedef PreParserExpression Literal; |
typedef PreParserExpressionList ExpressionList; |
typedef PreParserExpressionList PropertyList; |
+ typedef PreParserIdentifier FormalParameter; |
+ typedef DuplicateFinder FormalParameterScope; |
typedef PreParserStatementList StatementList; |
// For constructing objects returned by the traversing functions. |
@@ -1526,13 +1554,12 @@ class PreParserTraits { |
FunctionKind kind, bool* ok); |
// Utility functions |
- int DeclareArrowParametersFromExpression(PreParserExpression expression, |
- Scope* scope, |
- Scanner::Location* undefined_loc, |
- Scanner::Location* dupe_loc, |
- bool* ok) { |
- // TODO(aperez): Detect duplicated identifiers in paramlists. |
- *ok = expression.IsValidArrowParamList(undefined_loc); |
+ V8_INLINE int DeclareArrowParametersFromExpression( |
+ PreParserExpression expression, Scope* scope, |
+ FormalParameterErrorLocations* locs, bool* ok) { |
+ // TODO(wingo): Detect duplicated identifiers in paramlists. Detect eval or |
+ // arguments. Detect reserved words. |
+ *ok = expression.IsValidArrowParamList(locs); |
return 0; |
} |
@@ -1560,6 +1587,10 @@ class PreParserTraits { |
return !tag.IsNoTemplateTag(); |
} |
+ V8_INLINE bool DeclareFormalParameter(DuplicateFinder* scope, |
+ PreParserIdentifier param, |
+ bool is_rest); |
+ |
void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {} |
// Temporary glue; these functions will move to ParserBase. |
@@ -1748,6 +1779,13 @@ PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function, |
} |
+bool PreParserTraits::DeclareFormalParameter( |
+ DuplicateFinder* duplicate_finder, PreParserIdentifier current_identifier, |
+ bool is_rest) { |
+ return pre_parser_->scanner()->FindSymbol(duplicate_finder, 1) != 0; |
+} |
+ |
+ |
PreParserStatementList PreParser::ParseEagerFunctionBody( |
PreParserIdentifier function_name, int pos, Variable* fvar, |
Token::Value fvar_init_op, FunctionKind kind, bool* ok) { |
@@ -3041,6 +3079,101 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(ExpressionT expression, |
template <class Traits> |
+void ParserBase<Traits>::ParseFormalParameter( |
+ FormalParameterScopeT* scope, FormalParameterErrorLocations* locs, |
+ bool is_rest, bool* ok) { |
+ // FormalParameter[Yield,GeneratorParameter] : |
+ // BindingElement[?Yield, ?GeneratorParameter] |
+ bool is_strict_reserved; |
+ IdentifierT name = |
+ ParseIdentifierOrStrictReservedWord(&is_strict_reserved, ok); |
+ if (!*ok) return; |
+ |
+ // Store locations for possible future error reports. |
+ if (!locs->eval_or_arguments.IsValid() && this->IsEvalOrArguments(name)) { |
+ locs->eval_or_arguments = scanner()->location(); |
+ } |
+ if (!locs->undefined.IsValid() && this->IsUndefined(name)) { |
+ locs->undefined = scanner()->location(); |
+ } |
+ if (!locs->reserved.IsValid() && is_strict_reserved) { |
+ locs->reserved = scanner()->location(); |
+ } |
+ bool was_declared = Traits::DeclareFormalParameter(scope, name, is_rest); |
+ if (!locs->duplicate.IsValid() && was_declared) { |
+ locs->duplicate = scanner()->location(); |
+ } |
+} |
+ |
+ |
+template <class Traits> |
+int ParserBase<Traits>::ParseFormalParameterList( |
+ FormalParameterScopeT* scope, FormalParameterErrorLocations* locs, |
+ bool* is_rest, bool* ok) { |
+ // FormalParameters[Yield,GeneratorParameter] : |
+ // [empty] |
+ // FormalParameterList[?Yield, ?GeneratorParameter] |
+ // |
+ // FormalParameterList[Yield,GeneratorParameter] : |
+ // FunctionRestParameter[?Yield] |
+ // FormalsList[?Yield, ?GeneratorParameter] |
+ // FormalsList[?Yield, ?GeneratorParameter] , FunctionRestParameter[?Yield] |
+ // |
+ // FormalsList[Yield,GeneratorParameter] : |
+ // FormalParameter[?Yield, ?GeneratorParameter] |
+ // FormalsList[?Yield, ?GeneratorParameter] , |
+ // FormalParameter[?Yield,?GeneratorParameter] |
+ |
+ int parameter_count = 0; |
+ |
+ if (peek() != Token::RPAREN) { |
+ do { |
+ if (++parameter_count > Code::kMaxArguments) { |
+ ReportMessage("too_many_parameters"); |
+ *ok = false; |
+ return -1; |
+ } |
+ *is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS); |
+ ParseFormalParameter(scope, locs, *is_rest, ok); |
+ if (!*ok) return -1; |
+ } while (!*is_rest && Check(Token::COMMA)); |
+ |
+ if (*is_rest && peek() == Token::COMMA) { |
+ ReportMessageAt(scanner()->peek_location(), "param_after_rest"); |
+ *ok = false; |
+ return -1; |
+ } |
+ } |
+ |
+ return parameter_count; |
+} |
+ |
+ |
+template <class Traits> |
+void ParserBase<Traits>::CheckArityRestrictions( |
+ int param_count, FunctionLiteral::ArityRestriction arity_restriction, |
+ int formals_start_pos, int formals_end_pos, bool* ok) { |
+ switch (arity_restriction) { |
+ case FunctionLiteral::GETTER_ARITY: |
+ if (param_count != 0) { |
+ ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos), |
+ "bad_getter_arity"); |
+ *ok = false; |
+ } |
+ break; |
+ case FunctionLiteral::SETTER_ARITY: |
+ if (param_count != 1) { |
+ ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos), |
+ "bad_setter_arity"); |
+ *ok = false; |
+ } |
+ break; |
+ default: |
+ break; |
+ } |
+} |
+ |
+template <class Traits> |
typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
ExpressionT params_ast, |
@@ -3066,11 +3199,9 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
typename Traits::Type::Factory function_factory(ast_value_factory()); |
FunctionState function_state(&function_state_, &scope_, scope, |
kArrowFunction, &function_factory); |
- Scanner::Location undefined_loc = Scanner::Location::invalid(); |
- Scanner::Location dupe_loc = Scanner::Location::invalid(); |
- // TODO(arv): Pass in eval_args_loc and reserved_loc here. |
+ FormalParameterErrorLocations error_locs; |
num_parameters = Traits::DeclareArrowParametersFromExpression( |
- params_ast, scope_, &undefined_loc, &dupe_loc, ok); |
+ params_ast, scope_, &error_locs, ok); |
if (!*ok) { |
ReportMessageAt( |
Scanner::Location(start_pos, scanner()->location().beg_pos), |
@@ -3078,10 +3209,10 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
return this->EmptyExpression(); |
} |
- if (undefined_loc.IsValid()) { |
+ if (error_locs.undefined.IsValid()) { |
// Workaround for preparser not keeping track of positions. |
- undefined_loc = Scanner::Location(start_pos, |
- scanner()->location().end_pos); |
+ error_locs.undefined = |
+ Scanner::Location(start_pos, scanner()->location().end_pos); |
} |
if (num_parameters > Code::kMaxArguments) { |
ReportMessageAt(Scanner::Location(params_ast->position(), position()), |
@@ -3127,15 +3258,13 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(int start_pos, |
scope->set_start_position(start_pos); |
scope->set_end_position(scanner()->location().end_pos); |
- // Arrow function *parameter lists* are always checked as in strict mode. |
- // TODO(arv): eval_args_loc and reserved_loc needs to be set by |
- // DeclareArrowParametersFromExpression. |
- Scanner::Location eval_args_loc = Scanner::Location::invalid(); |
- Scanner::Location reserved_loc = Scanner::Location::invalid(); |
+ // Arrow function formal parameters are parsed as StrictFormalParameterList, |
+ // which is not the same as "parameters of a strict function"; it only means |
+ // that duplicates are not allowed. Of course, the arrow function may |
+ // itself be strict as well. |
const bool use_strict_params = true; |
this->CheckFunctionParameterNames(language_mode(), use_strict_params, |
- eval_args_loc, undefined_loc, dupe_loc, |
- reserved_loc, CHECK_OK); |
+ error_locs, CHECK_OK); |
// Validate strict mode. |
if (is_strict(language_mode())) { |