| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index c60318be3e35b02e965becaac68f05ec40007840..571fbf03a540e6b06266cd3561788fdeb96ebef1 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -581,66 +581,125 @@ class ParserBase : public Traits {
|
| void ReportUnexpectedToken(Token::Value token);
|
| void ReportUnexpectedTokenAt(Scanner::Location location, Token::Value token);
|
|
|
| - // Recursive descent functions:
|
| + class ExpressionClassifier {
|
| + public:
|
| + struct Error {
|
| + Error()
|
| + : location(Scanner::Location::invalid()),
|
| + message(nullptr),
|
| + arg(nullptr) {}
|
|
|
| - // Parses an identifier that is valid for the current scope, in particular it
|
| - // fails on strict mode future reserved keywords in a strict scope. If
|
| - // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
|
| - // "arguments" as identifier even in strict mode (this is needed in cases like
|
| - // "var foo = eval;").
|
| - IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok);
|
| - // Parses an identifier or a strict mode future reserved word, and indicate
|
| - // whether it is strict mode future reserved.
|
| - IdentifierT ParseIdentifierOrStrictReservedWord(
|
| - bool* is_strict_reserved,
|
| - bool* ok);
|
| - IdentifierT ParseIdentifierName(bool* ok);
|
| - // Parses an identifier and determines whether or not it is 'get' or 'set'.
|
| - IdentifierT ParseIdentifierNameOrGetOrSet(bool* is_get,
|
| - bool* is_set,
|
| - bool* ok);
|
| + Scanner::Location location;
|
| + const char* message;
|
| + const char* arg;
|
|
|
| + bool HasError() const { return location.IsValid(); }
|
| + };
|
|
|
| - class ExpressionClassifier {
|
| - public:
|
| - ExpressionClassifier()
|
| - : expression_error_(Scanner::Location::invalid()),
|
| - binding_pattern_error_(Scanner::Location::invalid()),
|
| - assignment_pattern_error_(Scanner::Location::invalid()) {}
|
| + ExpressionClassifier() {}
|
|
|
| - bool is_valid_expression() const {
|
| - return expression_error_ == Scanner::Location::invalid();
|
| - }
|
| + bool is_valid_expression() const { return !expression_error_.HasError(); }
|
|
|
| bool is_valid_binding_pattern() const {
|
| - return binding_pattern_error_ == Scanner::Location::invalid();
|
| + return !binding_pattern_error_.HasError();
|
| }
|
|
|
| - bool is_valid_assignmnent_pattern() const {
|
| - return assignment_pattern_error_ == Scanner::Location::invalid();
|
| + bool is_valid_assignment_pattern() const {
|
| + return !assignment_pattern_error_.HasError();
|
| }
|
|
|
| - void RecordExpressionError(const Scanner::Location& loc) {
|
| + const Error& expression_error() const { return expression_error_; }
|
| +
|
| + const Error& binding_pattern_error() const {
|
| + return binding_pattern_error_;
|
| + }
|
| +
|
| + const Error& assignment_pattern_error() const {
|
| + return assignment_pattern_error_;
|
| + }
|
| +
|
| + void RecordExpressionError(const Scanner::Location& loc,
|
| + const char* message, const char* arg = nullptr) {
|
| if (!is_valid_expression()) return;
|
| - expression_error_ = loc;
|
| + expression_error_.location = loc;
|
| + expression_error_.message = message;
|
| + expression_error_.arg = arg;
|
| }
|
|
|
| - void RecordBindingPatternError(const Scanner::Location& loc) {
|
| + void RecordBindingPatternError(const Scanner::Location& loc,
|
| + const char* message,
|
| + const char* arg = nullptr) {
|
| if (!is_valid_binding_pattern()) return;
|
| - binding_pattern_error_ = loc;
|
| + binding_pattern_error_.location = loc;
|
| + binding_pattern_error_.message = message;
|
| + binding_pattern_error_.arg = arg;
|
| }
|
|
|
| - void RecordAssignmentPatternError(const Scanner::Location& loc) {
|
| - if (!is_valid_assignmnent_pattern()) return;
|
| - assignment_pattern_error_ = loc;
|
| + void RecordAssignmentPatternError(const Scanner::Location& loc,
|
| + const char* message,
|
| + const char* arg = nullptr) {
|
| + if (!is_valid_assignment_pattern()) return;
|
| + assignment_pattern_error_.location = loc;
|
| + assignment_pattern_error_.message = message;
|
| + assignment_pattern_error_.arg = arg;
|
| }
|
|
|
| private:
|
| - Scanner::Location expression_error_;
|
| - Scanner::Location binding_pattern_error_;
|
| - Scanner::Location assignment_pattern_error_;
|
| + Error expression_error_;
|
| + Error binding_pattern_error_;
|
| + Error assignment_pattern_error_;
|
| };
|
|
|
| + void ReportClassifierError(
|
| + const typename ExpressionClassifier::Error& error) {
|
| + Traits::ReportMessageAt(error.location, error.message, error.arg,
|
| + kSyntaxError);
|
| + }
|
| +
|
| + void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) {
|
| + if (!classifier->is_valid_expression()) {
|
| + ReportClassifierError(classifier->expression_error());
|
| + *ok = false;
|
| + }
|
| + }
|
| +
|
| + void ValidateBindingPattern(const ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + if (!classifier->is_valid_binding_pattern()) {
|
| + ReportClassifierError(classifier->binding_pattern_error());
|
| + *ok = false;
|
| + }
|
| + }
|
| +
|
| + void ValidateAssignmentPattern(const ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + if (!classifier->is_valid_assignment_pattern()) {
|
| + ReportClassifierError(classifier->assignment_pattern_error());
|
| + *ok = false;
|
| + }
|
| + }
|
| +
|
| +
|
| + // Recursive descent functions:
|
| +
|
| + // Parses an identifier that is valid for the current scope, in particular it
|
| + // fails on strict mode future reserved keywords in a strict scope. If
|
| + // allow_eval_or_arguments is kAllowEvalOrArguments, we allow "eval" or
|
| + // "arguments" as identifier even in strict mode (this is needed in cases like
|
| + // "var foo = eval;").
|
| + IdentifierT ParseIdentifier(AllowRestrictedIdentifiers, bool* ok);
|
| + IdentifierT ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
| + bool* ok);
|
| + // Parses an identifier or a strict mode future reserved word, and indicate
|
| + // whether it is strict mode future reserved.
|
| + IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
|
| + bool* ok);
|
| + IdentifierT ParseIdentifierName(bool* ok);
|
| + // Parses an identifier and determines whether or not it is 'get' or 'set'.
|
| + IdentifierT ParseIdentifierNameOrGetOrSet(bool* is_get, bool* is_set,
|
| + bool* ok);
|
| +
|
| +
|
| ExpressionT ParseRegExpLiteral(bool seen_equal,
|
| ExpressionClassifier* classifier, bool* ok);
|
|
|
| @@ -1960,23 +2019,45 @@ void ParserBase<Traits>::ReportUnexpectedTokenAt(
|
| template <class Traits>
|
| typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
|
| AllowRestrictedIdentifiers allow_restricted_identifiers, bool* ok) {
|
| + ExpressionClassifier classifier;
|
| + auto result = ParseAndClassifyIdentifier(&classifier, ok);
|
| + if (!*ok) return Traits::EmptyIdentifier();
|
| +
|
| + if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
|
| + ValidateAssignmentPattern(&classifier, ok);
|
| + if (!*ok) return Traits::EmptyIdentifier();
|
| + ValidateBindingPattern(&classifier, ok);
|
| + if (!*ok) return Traits::EmptyIdentifier();
|
| + } else {
|
| + ValidateExpression(&classifier, ok);
|
| + if (!*ok) return Traits::EmptyIdentifier();
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +
|
| +template <class Traits>
|
| +typename ParserBase<Traits>::IdentifierT
|
| +ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| Token::Value next = Next();
|
| if (next == Token::IDENTIFIER) {
|
| IdentifierT name = this->GetSymbol(scanner());
|
| - if (allow_restricted_identifiers == kDontAllowRestrictedIdentifiers) {
|
| - if (is_strict(language_mode()) && this->IsEvalOrArguments(name)) {
|
| - ReportMessage("strict_eval_arguments");
|
| - *ok = false;
|
| - }
|
| - if (is_strong(language_mode()) && this->IsUndefined(name)) {
|
| - ReportMessage("strong_undefined");
|
| - *ok = false;
|
| - }
|
| - } else {
|
| - if (is_strong(language_mode()) && this->IsArguments(name)) {
|
| - ReportMessage("strong_arguments");
|
| - *ok = false;
|
| - }
|
| + if (is_strict(language_mode()) && this->IsEvalOrArguments(name)) {
|
| + classifier->RecordBindingPatternError(scanner()->location(),
|
| + "strict_eval_arguments");
|
| + }
|
| + if (is_strong(language_mode()) && this->IsUndefined(name)) {
|
| + // TODO(dslomov): allow 'undefined' in nested patterns.
|
| + classifier->RecordBindingPatternError(scanner()->location(),
|
| + "strong_undefined");
|
| + classifier->RecordAssignmentPatternError(scanner()->location(),
|
| + "strong_undefined");
|
| + }
|
| + if (is_strong(language_mode()) && this->IsArguments(name)) {
|
| + classifier->RecordExpressionError(scanner()->location(),
|
| + "strong_arguments");
|
| }
|
| if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
|
| return name;
|
| @@ -1992,6 +2073,7 @@ typename ParserBase<Traits>::IdentifierT ParserBase<Traits>::ParseIdentifier(
|
| }
|
| }
|
|
|
| +
|
| template <class Traits>
|
| typename ParserBase<Traits>::IdentifierT ParserBase<
|
| Traits>::ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
|
| @@ -2141,7 +2223,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
| case Token::YIELD:
|
| case Token::FUTURE_STRICT_RESERVED_WORD: {
|
| // Using eval or arguments in this context is OK even in strict mode.
|
| - IdentifierT name = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
|
| + IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
|
| result = this->ExpressionFromIdentifier(name, beg_pos, end_pos, scope_,
|
| factory());
|
| break;
|
| @@ -2171,6 +2253,10 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|
|
| case Token::LPAREN:
|
| Consume(Token::LPAREN);
|
| + classifier->RecordBindingPatternError(scanner()->location(),
|
| + "unexpected_token", "(");
|
| + classifier->RecordAssignmentPatternError(scanner()->location(),
|
| + "unexpected_token", "(");
|
| if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) {
|
| // As a primary expression, the only thing that can follow "()" is "=>".
|
| Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
| @@ -2241,7 +2327,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| bool accept_IN, bool* ok) {
|
| ExpressionClassifier classifier;
|
| ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK);
|
| - // TODO(dslomov): report error if not a valid expression.
|
| + ValidateExpression(&classifier, CHECK_OK);
|
| return result;
|
| }
|
|
|
|
|