| Index: src/parsing/preparser.h
|
| diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h
|
| index 7a699670bbdf3b87d01cb465a02ded7cbfdda698..6b39bd987900b5f926792a7c82b78fb70a4f0dcc 100644
|
| --- a/src/parsing/preparser.h
|
| +++ b/src/parsing/preparser.h
|
| @@ -11,6 +11,7 @@
|
| #include "src/messages.h"
|
| #include "src/parsing/expression-classifier.h"
|
| #include "src/parsing/func-name-inferrer.h"
|
| +#include "src/parsing/parser-base.h"
|
| #include "src/parsing/scanner.h"
|
| #include "src/parsing/token.h"
|
|
|
| @@ -18,914 +19,6 @@ namespace v8 {
|
| namespace internal {
|
|
|
|
|
| -enum FunctionNameValidity {
|
| - kFunctionNameIsStrictReserved,
|
| - kSkipFunctionNameCheck,
|
| - kFunctionNameValidityUnknown
|
| -};
|
| -
|
| -
|
| -struct FormalParametersBase {
|
| - explicit FormalParametersBase(Scope* scope) : scope(scope) {}
|
| - Scope* scope;
|
| - bool has_rest = false;
|
| - bool is_simple = true;
|
| - int materialized_literals_count = 0;
|
| - mutable int rest_array_literal_index = -1;
|
| -};
|
| -
|
| -
|
| -// Common base class shared between parser and pre-parser. Traits encapsulate
|
| -// the differences between Parser and PreParser:
|
| -
|
| -// - Return types: For example, Parser functions return Expression* and
|
| -// PreParser functions return PreParserExpression.
|
| -
|
| -// - Creating parse tree nodes: Parser generates an AST during the recursive
|
| -// descent. PreParser doesn't create a tree. Instead, it passes around minimal
|
| -// data objects (PreParserExpression, PreParserIdentifier etc.) which contain
|
| -// just enough data for the upper layer functions. PreParserFactory is
|
| -// responsible for creating these dummy objects. It provides a similar kind of
|
| -// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
|
| -// used.
|
| -
|
| -// - Miscellaneous other tasks interleaved with the recursive descent. For
|
| -// example, Parser keeps track of which function literals should be marked as
|
| -// pretenured, and PreParser doesn't care.
|
| -
|
| -// The traits are expected to contain the following typedefs:
|
| -// struct Traits {
|
| -// // In particular...
|
| -// struct Type {
|
| -// // Used by FunctionState and BlockState.
|
| -// typedef Scope;
|
| -// typedef GeneratorVariable;
|
| -// // Return types for traversing functions.
|
| -// typedef Identifier;
|
| -// typedef Expression;
|
| -// typedef FunctionLiteral;
|
| -// typedef ClassLiteral;
|
| -// typedef ObjectLiteralProperty;
|
| -// typedef Literal;
|
| -// typedef ExpressionList;
|
| -// typedef PropertyList;
|
| -// typedef FormalParameter;
|
| -// typedef FormalParameters;
|
| -// // For constructing objects returned by the traversing functions.
|
| -// typedef Factory;
|
| -// };
|
| -// // ...
|
| -// };
|
| -
|
| -template <typename Traits>
|
| -class ParserBase : public Traits {
|
| - public:
|
| - // 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::FormalParameters FormalParametersT;
|
| - typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
|
| - typedef typename Traits::Type::Literal LiteralT;
|
| - typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
|
| - typedef typename Traits::Type::StatementList StatementListT;
|
| -
|
| - ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
|
| - v8::Extension* extension, AstValueFactory* ast_value_factory,
|
| - ParserRecorder* log, typename Traits::Type::Parser this_object)
|
| - : Traits(this_object),
|
| - parenthesized_function_(false),
|
| - scope_(NULL),
|
| - function_state_(NULL),
|
| - extension_(extension),
|
| - fni_(NULL),
|
| - ast_value_factory_(ast_value_factory),
|
| - log_(log),
|
| - mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
|
| - stack_limit_(stack_limit),
|
| - zone_(zone),
|
| - scanner_(scanner),
|
| - stack_overflow_(false),
|
| - allow_lazy_(false),
|
| - allow_natives_(false),
|
| - allow_harmony_sloppy_(false),
|
| - allow_harmony_sloppy_function_(false),
|
| - allow_harmony_sloppy_let_(false),
|
| - allow_harmony_rest_parameters_(false),
|
| - allow_harmony_default_parameters_(false),
|
| - allow_harmony_destructuring_bind_(false),
|
| - allow_harmony_destructuring_assignment_(false),
|
| - allow_strong_mode_(false),
|
| - allow_legacy_const_(true),
|
| - allow_harmony_do_expressions_(false) {}
|
| -
|
| -#define ALLOW_ACCESSORS(name) \
|
| - bool allow_##name() const { return allow_##name##_; } \
|
| - void set_allow_##name(bool allow) { allow_##name##_ = allow; }
|
| -
|
| - ALLOW_ACCESSORS(lazy);
|
| - ALLOW_ACCESSORS(natives);
|
| - ALLOW_ACCESSORS(harmony_sloppy);
|
| - ALLOW_ACCESSORS(harmony_sloppy_function);
|
| - ALLOW_ACCESSORS(harmony_sloppy_let);
|
| - ALLOW_ACCESSORS(harmony_rest_parameters);
|
| - ALLOW_ACCESSORS(harmony_default_parameters);
|
| - ALLOW_ACCESSORS(harmony_destructuring_bind);
|
| - ALLOW_ACCESSORS(harmony_destructuring_assignment);
|
| - ALLOW_ACCESSORS(strong_mode);
|
| - ALLOW_ACCESSORS(legacy_const);
|
| - ALLOW_ACCESSORS(harmony_do_expressions);
|
| -#undef ALLOW_ACCESSORS
|
| -
|
| - uintptr_t stack_limit() const { return stack_limit_; }
|
| -
|
| - protected:
|
| - enum AllowRestrictedIdentifiers {
|
| - kAllowRestrictedIdentifiers,
|
| - kDontAllowRestrictedIdentifiers
|
| - };
|
| -
|
| - enum Mode {
|
| - PARSE_LAZILY,
|
| - PARSE_EAGERLY
|
| - };
|
| -
|
| - enum VariableDeclarationContext {
|
| - kStatementListItem,
|
| - kStatement,
|
| - kForStatement
|
| - };
|
| -
|
| - class Checkpoint;
|
| - class ObjectLiteralCheckerBase;
|
| -
|
| - // ---------------------------------------------------------------------------
|
| - // FunctionState and BlockState together implement the parser's scope stack.
|
| - // The parser's current scope is in scope_. BlockState and FunctionState
|
| - // constructors push on the scope stack and the destructors pop. They are also
|
| - // used to hold the parser's per-function and per-block state.
|
| - class BlockState BASE_EMBEDDED {
|
| - public:
|
| - BlockState(Scope** scope_stack, Scope* scope)
|
| - : scope_stack_(scope_stack), outer_scope_(*scope_stack) {
|
| - *scope_stack_ = scope;
|
| - }
|
| - ~BlockState() { *scope_stack_ = outer_scope_; }
|
| -
|
| - private:
|
| - Scope** scope_stack_;
|
| - Scope* outer_scope_;
|
| - };
|
| -
|
| - struct DestructuringAssignment {
|
| - public:
|
| - DestructuringAssignment(ExpressionT expression, Scope* scope)
|
| - : assignment(expression), scope(scope) {}
|
| -
|
| - ExpressionT assignment;
|
| - Scope* scope;
|
| - };
|
| -
|
| - class FunctionState BASE_EMBEDDED {
|
| - public:
|
| - FunctionState(FunctionState** function_state_stack, Scope** scope_stack,
|
| - Scope* scope, FunctionKind kind,
|
| - typename Traits::Type::Factory* factory);
|
| - ~FunctionState();
|
| -
|
| - int NextMaterializedLiteralIndex() {
|
| - return next_materialized_literal_index_++;
|
| - }
|
| - int materialized_literal_count() {
|
| - return next_materialized_literal_index_;
|
| - }
|
| -
|
| - void SkipMaterializedLiterals(int count) {
|
| - next_materialized_literal_index_ += count;
|
| - }
|
| -
|
| - void AddProperty() { expected_property_count_++; }
|
| - int expected_property_count() { return expected_property_count_; }
|
| -
|
| - Scanner::Location this_location() const { return this_location_; }
|
| - Scanner::Location super_location() const { return super_location_; }
|
| - Scanner::Location return_location() const { return return_location_; }
|
| - void set_this_location(Scanner::Location location) {
|
| - this_location_ = location;
|
| - }
|
| - void set_super_location(Scanner::Location location) {
|
| - super_location_ = location;
|
| - }
|
| - void set_return_location(Scanner::Location location) {
|
| - return_location_ = location;
|
| - }
|
| -
|
| - bool is_generator() const { return IsGeneratorFunction(kind_); }
|
| -
|
| - FunctionKind kind() const { return kind_; }
|
| - FunctionState* outer() const { return outer_function_state_; }
|
| -
|
| - void set_generator_object_variable(
|
| - typename Traits::Type::GeneratorVariable* variable) {
|
| - DCHECK(variable != NULL);
|
| - DCHECK(is_generator());
|
| - generator_object_variable_ = variable;
|
| - }
|
| - typename Traits::Type::GeneratorVariable* generator_object_variable()
|
| - const {
|
| - return generator_object_variable_;
|
| - }
|
| -
|
| - typename Traits::Type::Factory* factory() { return factory_; }
|
| -
|
| - const List<DestructuringAssignment>& destructuring_assignments_to_rewrite()
|
| - const {
|
| - return destructuring_assignments_to_rewrite_;
|
| - }
|
| -
|
| - void AddDestructuringAssignment(DestructuringAssignment pair) {
|
| - destructuring_assignments_to_rewrite_.Add(pair);
|
| - }
|
| -
|
| - private:
|
| - // Used to assign an index to each literal that needs materialization in
|
| - // the function. Includes regexp literals, and boilerplate for object and
|
| - // array literals.
|
| - int next_materialized_literal_index_;
|
| -
|
| - // Properties count estimation.
|
| - int expected_property_count_;
|
| -
|
| - // Location of most recent use of 'this' (invalid if none).
|
| - Scanner::Location this_location_;
|
| -
|
| - // Location of most recent 'return' statement (invalid if none).
|
| - Scanner::Location return_location_;
|
| -
|
| - // Location of call to the "super" constructor (invalid if none).
|
| - Scanner::Location super_location_;
|
| -
|
| - FunctionKind kind_;
|
| - // For generators, this variable may hold the generator object. It variable
|
| - // is used by yield expressions and return statements. It is not necessary
|
| - // for generator functions to have this variable set.
|
| - Variable* generator_object_variable_;
|
| -
|
| - FunctionState** function_state_stack_;
|
| - FunctionState* outer_function_state_;
|
| - Scope** scope_stack_;
|
| - Scope* outer_scope_;
|
| -
|
| - List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
|
| -
|
| - void RewriteDestructuringAssignments();
|
| -
|
| - typename Traits::Type::Factory* factory_;
|
| -
|
| - friend class ParserTraits;
|
| - friend class Checkpoint;
|
| - };
|
| -
|
| - // Annoyingly, arrow functions first parse as comma expressions, then when we
|
| - // see the => we have to go back and reinterpret the arguments as being formal
|
| - // parameters. To do so we need to reset some of the parser state back to
|
| - // what it was before the arguments were first seen.
|
| - class Checkpoint BASE_EMBEDDED {
|
| - public:
|
| - explicit Checkpoint(ParserBase* parser) {
|
| - function_state_ = parser->function_state_;
|
| - next_materialized_literal_index_ =
|
| - function_state_->next_materialized_literal_index_;
|
| - expected_property_count_ = function_state_->expected_property_count_;
|
| - }
|
| -
|
| - void Restore(int* materialized_literal_index_delta) {
|
| - *materialized_literal_index_delta =
|
| - function_state_->next_materialized_literal_index_ -
|
| - next_materialized_literal_index_;
|
| - function_state_->next_materialized_literal_index_ =
|
| - next_materialized_literal_index_;
|
| - function_state_->expected_property_count_ = expected_property_count_;
|
| - }
|
| -
|
| - private:
|
| - FunctionState* function_state_;
|
| - int next_materialized_literal_index_;
|
| - int expected_property_count_;
|
| - };
|
| -
|
| - class ParsingModeScope BASE_EMBEDDED {
|
| - public:
|
| - ParsingModeScope(ParserBase* parser, Mode mode)
|
| - : parser_(parser),
|
| - old_mode_(parser->mode()) {
|
| - parser_->mode_ = mode;
|
| - }
|
| - ~ParsingModeScope() {
|
| - parser_->mode_ = old_mode_;
|
| - }
|
| -
|
| - private:
|
| - ParserBase* parser_;
|
| - Mode old_mode_;
|
| - };
|
| -
|
| - Scope* NewScope(Scope* parent, ScopeType scope_type) {
|
| - // Must always pass the function kind for FUNCTION_SCOPE.
|
| - DCHECK(scope_type != FUNCTION_SCOPE);
|
| - return NewScope(parent, scope_type, kNormalFunction);
|
| - }
|
| -
|
| - Scope* NewScope(Scope* parent, ScopeType scope_type, FunctionKind kind) {
|
| - DCHECK(ast_value_factory());
|
| - DCHECK(scope_type != MODULE_SCOPE || FLAG_harmony_modules);
|
| - Scope* result = new (zone())
|
| - Scope(zone(), parent, scope_type, ast_value_factory(), kind);
|
| - result->Initialize();
|
| - return result;
|
| - }
|
| -
|
| - Scanner* scanner() const { return scanner_; }
|
| - AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
|
| - int position() { return scanner_->location().beg_pos; }
|
| - int peek_position() { return scanner_->peek_location().beg_pos; }
|
| - bool stack_overflow() const { return stack_overflow_; }
|
| - void set_stack_overflow() { stack_overflow_ = true; }
|
| - Mode mode() const { return mode_; }
|
| - Zone* zone() const { return zone_; }
|
| -
|
| - INLINE(Token::Value peek()) {
|
| - if (stack_overflow_) return Token::ILLEGAL;
|
| - return scanner()->peek();
|
| - }
|
| -
|
| - INLINE(Token::Value PeekAhead()) {
|
| - if (stack_overflow_) return Token::ILLEGAL;
|
| - return scanner()->PeekAhead();
|
| - }
|
| -
|
| - INLINE(Token::Value Next()) {
|
| - if (stack_overflow_) return Token::ILLEGAL;
|
| - {
|
| - if (GetCurrentStackPosition() < stack_limit_) {
|
| - // Any further calls to Next or peek will return the illegal token.
|
| - // The current call must return the next token, which might already
|
| - // have been peek'ed.
|
| - stack_overflow_ = true;
|
| - }
|
| - }
|
| - return scanner()->Next();
|
| - }
|
| -
|
| - void Consume(Token::Value token) {
|
| - Token::Value next = Next();
|
| - USE(next);
|
| - USE(token);
|
| - DCHECK(next == token);
|
| - }
|
| -
|
| - bool Check(Token::Value token) {
|
| - Token::Value next = peek();
|
| - if (next == token) {
|
| - Consume(next);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - void Expect(Token::Value token, bool* ok) {
|
| - Token::Value next = Next();
|
| - if (next != token) {
|
| - ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - void ExpectSemicolon(bool* ok) {
|
| - // Check for automatic semicolon insertion according to
|
| - // the rules given in ECMA-262, section 7.9, page 21.
|
| - Token::Value tok = peek();
|
| - if (tok == Token::SEMICOLON) {
|
| - Next();
|
| - return;
|
| - }
|
| - if (scanner()->HasAnyLineTerminatorBeforeNext() ||
|
| - tok == Token::RBRACE ||
|
| - tok == Token::EOS) {
|
| - return;
|
| - }
|
| - Expect(Token::SEMICOLON, ok);
|
| - }
|
| -
|
| - bool peek_any_identifier() {
|
| - Token::Value next = peek();
|
| - return next == Token::IDENTIFIER || next == Token::FUTURE_RESERVED_WORD ||
|
| - next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
| - next == Token::STATIC || next == Token::YIELD;
|
| - }
|
| -
|
| - bool CheckContextualKeyword(Vector<const char> keyword) {
|
| - if (PeekContextualKeyword(keyword)) {
|
| - Consume(Token::IDENTIFIER);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - bool PeekContextualKeyword(Vector<const char> keyword) {
|
| - return peek() == Token::IDENTIFIER &&
|
| - scanner()->is_next_contextual_keyword(keyword);
|
| - }
|
| -
|
| - void ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
|
| - Expect(Token::IDENTIFIER, ok);
|
| - if (!*ok) return;
|
| - if (!scanner()->is_literal_contextual_keyword(keyword)) {
|
| - ReportUnexpectedToken(scanner()->current_token());
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - bool CheckInOrOf(ForEachStatement::VisitMode* visit_mode, bool* ok) {
|
| - if (Check(Token::IN)) {
|
| - if (is_strong(language_mode())) {
|
| - ReportMessageAt(scanner()->location(), MessageTemplate::kStrongForIn);
|
| - *ok = false;
|
| - } else {
|
| - *visit_mode = ForEachStatement::ENUMERATE;
|
| - }
|
| - return true;
|
| - } else if (CheckContextualKeyword(CStrVector("of"))) {
|
| - *visit_mode = ForEachStatement::ITERATE;
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - // Checks whether an octal literal was last seen between beg_pos and end_pos.
|
| - // If so, reports an error. Only called for strict mode and template strings.
|
| - void CheckOctalLiteral(int beg_pos, int end_pos,
|
| - MessageTemplate::Template message, bool* ok) {
|
| - Scanner::Location octal = scanner()->octal_position();
|
| - if (octal.IsValid() && beg_pos <= octal.beg_pos &&
|
| - octal.end_pos <= end_pos) {
|
| - ReportMessageAt(octal, message);
|
| - scanner()->clear_octal_position();
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
| - CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kStrictOctalLiteral,
|
| - ok);
|
| - }
|
| -
|
| - inline void CheckTemplateOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
| - CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kTemplateOctalLiteral,
|
| - ok);
|
| - }
|
| -
|
| - void CheckDestructuringElement(ExpressionT element,
|
| - ExpressionClassifier* classifier, int beg_pos,
|
| - int end_pos);
|
| -
|
| - // Checking the name of a function literal. This has to be done after parsing
|
| - // the function, since the function can declare itself strict.
|
| - void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name,
|
| - FunctionNameValidity function_name_validity,
|
| - const Scanner::Location& function_name_loc, bool* ok) {
|
| - if (function_name_validity == kSkipFunctionNameCheck) return;
|
| - // The function name needs to be checked in strict mode.
|
| - if (is_sloppy(language_mode)) return;
|
| -
|
| - if (this->IsEvalOrArguments(function_name)) {
|
| - Traits::ReportMessageAt(function_name_loc,
|
| - MessageTemplate::kStrictEvalArguments);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - if (function_name_validity == kFunctionNameIsStrictReserved) {
|
| - Traits::ReportMessageAt(function_name_loc,
|
| - MessageTemplate::kUnexpectedStrictReserved);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - if (is_strong(language_mode) && this->IsUndefined(function_name)) {
|
| - Traits::ReportMessageAt(function_name_loc,
|
| - MessageTemplate::kStrongUndefined);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // Determine precedence of given token.
|
| - static int Precedence(Token::Value token, bool accept_IN) {
|
| - if (token == Token::IN && !accept_IN)
|
| - return 0; // 0 precedence will terminate binary expression parsing
|
| - return Token::Precedence(token);
|
| - }
|
| -
|
| - typename Traits::Type::Factory* factory() {
|
| - return function_state_->factory();
|
| - }
|
| -
|
| - LanguageMode language_mode() { return scope_->language_mode(); }
|
| - bool is_generator() const { return function_state_->is_generator(); }
|
| -
|
| - bool allow_const() {
|
| - return is_strict(language_mode()) || allow_harmony_sloppy() ||
|
| - allow_legacy_const();
|
| - }
|
| -
|
| - bool allow_let() {
|
| - return is_strict(language_mode()) || allow_harmony_sloppy_let();
|
| - }
|
| -
|
| - // Report syntax errors.
|
| - void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
|
| - ParseErrorType error_type = kSyntaxError) {
|
| - Scanner::Location source_location = scanner()->location();
|
| - Traits::ReportMessageAt(source_location, message, arg, error_type);
|
| - }
|
| -
|
| - void ReportMessageAt(Scanner::Location location,
|
| - MessageTemplate::Template message,
|
| - ParseErrorType error_type = kSyntaxError) {
|
| - Traits::ReportMessageAt(location, message, reinterpret_cast<const char*>(0),
|
| - error_type);
|
| - }
|
| -
|
| - void GetUnexpectedTokenMessage(
|
| - Token::Value token, MessageTemplate::Template* message, const char** arg,
|
| - MessageTemplate::Template default_ = MessageTemplate::kUnexpectedToken);
|
| -
|
| - void ReportUnexpectedToken(Token::Value token);
|
| - void ReportUnexpectedTokenAt(
|
| - Scanner::Location location, Token::Value token,
|
| - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken);
|
| -
|
| -
|
| - void ReportClassifierError(const ExpressionClassifier::Error& error) {
|
| - Traits::ReportMessageAt(error.location, error.message, error.arg,
|
| - error.type);
|
| - }
|
| -
|
| - void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) {
|
| - if (!classifier->is_valid_expression() ||
|
| - classifier->has_cover_initialized_name()) {
|
| - const Scanner::Location& a = classifier->expression_error().location;
|
| - const Scanner::Location& b =
|
| - classifier->cover_initialized_name_error().location;
|
| - if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) {
|
| - ReportClassifierError(classifier->cover_initialized_name_error());
|
| - } else {
|
| - ReportClassifierError(classifier->expression_error());
|
| - }
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - void ValidateFormalParameterInitializer(
|
| - const ExpressionClassifier* classifier, bool* ok) {
|
| - if (!classifier->is_valid_formal_parameter_initializer()) {
|
| - ReportClassifierError(classifier->formal_parameter_initializer_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;
|
| - }
|
| - }
|
| -
|
| - void ValidateFormalParameters(const ExpressionClassifier* classifier,
|
| - LanguageMode language_mode,
|
| - bool allow_duplicates, bool* ok) {
|
| - if (!allow_duplicates &&
|
| - !classifier->is_valid_formal_parameter_list_without_duplicates()) {
|
| - ReportClassifierError(classifier->duplicate_formal_parameter_error());
|
| - *ok = false;
|
| - } else if (is_strict(language_mode) &&
|
| - !classifier->is_valid_strict_mode_formal_parameters()) {
|
| - ReportClassifierError(classifier->strict_mode_formal_parameter_error());
|
| - *ok = false;
|
| - } else if (is_strong(language_mode) &&
|
| - !classifier->is_valid_strong_mode_formal_parameters()) {
|
| - ReportClassifierError(classifier->strong_mode_formal_parameter_error());
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
|
| - ExpressionT expr,
|
| - bool parenthesized_formals, bool* ok) {
|
| - if (classifier->is_valid_binding_pattern()) {
|
| - // A simple arrow formal parameter: IDENTIFIER => BODY.
|
| - if (!this->IsIdentifier(expr)) {
|
| - Traits::ReportMessageAt(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(scanner()->current_token()));
|
| - *ok = false;
|
| - }
|
| - } else if (!classifier->is_valid_arrow_formal_parameters()) {
|
| - // If after parsing the expr, we see an error but the expression is
|
| - // neither a valid binding pattern nor a valid parenthesized formal
|
| - // parameter list, show the "arrow formal parameters" error if the formals
|
| - // started with a parenthesis, and the binding pattern error otherwise.
|
| - const ExpressionClassifier::Error& error =
|
| - parenthesized_formals ? classifier->arrow_formal_parameters_error()
|
| - : classifier->binding_pattern_error();
|
| - ReportClassifierError(error);
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - void ValidateLetPattern(const ExpressionClassifier* classifier, bool* ok) {
|
| - if (!classifier->is_valid_let_pattern()) {
|
| - ReportClassifierError(classifier->let_pattern_error());
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - void ExpressionUnexpectedToken(ExpressionClassifier* classifier) {
|
| - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
|
| - const char* arg;
|
| - GetUnexpectedTokenMessage(peek(), &message, &arg);
|
| - classifier->RecordExpressionError(scanner()->peek_location(), message, arg);
|
| - }
|
| -
|
| - void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
|
| - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
|
| - const char* arg;
|
| - GetUnexpectedTokenMessage(peek(), &message, &arg);
|
| - classifier->RecordBindingPatternError(scanner()->peek_location(), message,
|
| - arg);
|
| - }
|
| -
|
| - void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) {
|
| - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
|
| - const char* arg;
|
| - GetUnexpectedTokenMessage(peek(), &message, &arg);
|
| - classifier->RecordArrowFormalParametersError(scanner()->peek_location(),
|
| - message, arg);
|
| - }
|
| -
|
| - void FormalParameterInitializerUnexpectedToken(
|
| - ExpressionClassifier* classifier) {
|
| - MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
|
| - const char* arg;
|
| - GetUnexpectedTokenMessage(peek(), &message, &arg);
|
| - classifier->RecordFormalParameterInitializerError(
|
| - scanner()->peek_location(), message, arg);
|
| - }
|
| -
|
| - // 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. Allows passing in is_generator
|
| - // for the case of parsing the identifier in a function expression, where the
|
| - // relevant "is_generator" bit is of the function being parsed, not the
|
| - // containing
|
| - // function.
|
| - IdentifierT ParseIdentifierOrStrictReservedWord(bool is_generator,
|
| - bool* is_strict_reserved,
|
| - bool* ok);
|
| - IdentifierT ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
|
| - bool* ok) {
|
| - return ParseIdentifierOrStrictReservedWord(this->is_generator(),
|
| - is_strict_reserved, 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);
|
| -
|
| - ExpressionT ParsePrimaryExpression(ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseExpression(bool accept_IN, bool* ok);
|
| - ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseExpression(bool accept_IN, int flags,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set,
|
| - bool* is_static, bool* is_computed_name,
|
| - bool* is_identifier, bool* is_escaped_keyword,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseObjectLiteral(ExpressionClassifier* classifier, bool* ok);
|
| - ObjectLiteralPropertyT ParsePropertyDefinition(
|
| - ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
| - bool is_static, bool* is_computed_name, bool* has_seen_constructor,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - typename Traits::Type::ExpressionList ParseArguments(
|
| - Scanner::Location* first_spread_pos, ExpressionClassifier* classifier,
|
| - bool* ok);
|
| -
|
| - enum AssignmentExpressionFlags {
|
| - kIsLeftHandSide = 0,
|
| - kIsRightHandSide = 1 << 0,
|
| - kIsPatternElement = 1 << 1,
|
| - kIsPossibleArrowFormals = 1 << 2
|
| - };
|
| -
|
| - ExpressionT ParseAssignmentExpression(bool accept_IN, int flags,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseAssignmentExpression(bool accept_IN,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - return ParseAssignmentExpression(accept_IN, kIsLeftHandSide, classifier,
|
| - ok);
|
| - }
|
| - ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseConditionalExpression(bool accept_IN,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseBinaryExpression(int prec, bool accept_IN,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParsePostfixExpression(ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier,
|
| - bool* ok);
|
| - ExpressionT ParseMemberWithNewPrefixesExpression(
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseMemberExpressionContinuation(
|
| - ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseArrowFunctionLiteral(bool accept_IN,
|
| - const FormalParametersT& parameters,
|
| - const ExpressionClassifier& classifier,
|
| - bool* ok);
|
| - ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - void AddTemplateExpression(ExpressionT);
|
| - ExpressionT ParseSuperExpression(bool is_new,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseNewTargetExpression(bool* ok);
|
| - ExpressionT ParseStrongInitializationExpression(
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
|
| - bool* ok);
|
| -
|
| - void ParseFormalParameter(FormalParametersT* parameters,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - void ParseFormalParameterList(FormalParametersT* parameters,
|
| - ExpressionClassifier* classifier, bool* ok);
|
| - void CheckArityRestrictions(
|
| - int param_count, FunctionLiteral::ArityRestriction arity_restriction,
|
| - bool has_rest, int formals_start_pos, int formals_end_pos, bool* ok);
|
| -
|
| - bool IsNextLetKeyword();
|
| -
|
| - // 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.
|
| - ExpressionT CheckAndRewriteReferenceExpression(
|
| - ExpressionT expression, int beg_pos, int end_pos,
|
| - MessageTemplate::Template message, bool* ok);
|
| - ExpressionT ClassifyAndRewriteReferenceExpression(
|
| - ExpressionClassifier* classifier, ExpressionT expression, int beg_pos,
|
| - int end_pos, MessageTemplate::Template message,
|
| - ParseErrorType type = kSyntaxError);
|
| - ExpressionT CheckAndRewriteReferenceExpression(
|
| - ExpressionT expression, int beg_pos, int end_pos,
|
| - MessageTemplate::Template message, ParseErrorType type, bool* ok);
|
| -
|
| - bool IsValidReferenceExpression(ExpressionT expression);
|
| -
|
| - bool IsAssignableIdentifier(ExpressionT expression) {
|
| - if (!Traits::IsIdentifier(expression)) return false;
|
| - if (is_strict(language_mode()) &&
|
| - Traits::IsEvalOrArguments(Traits::AsIdentifier(expression))) {
|
| - return false;
|
| - }
|
| - if (is_strong(language_mode()) &&
|
| - Traits::IsUndefined(Traits::AsIdentifier(expression))) {
|
| - return false;
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - // Used to validate property names in object literals and class literals
|
| - enum PropertyKind {
|
| - kAccessorProperty,
|
| - kValueProperty,
|
| - kMethodProperty
|
| - };
|
| -
|
| - class ObjectLiteralCheckerBase {
|
| - public:
|
| - explicit ObjectLiteralCheckerBase(ParserBase* parser) : parser_(parser) {}
|
| -
|
| - virtual void CheckProperty(Token::Value property, PropertyKind type,
|
| - bool is_static, bool is_generator, bool* ok) = 0;
|
| -
|
| - virtual ~ObjectLiteralCheckerBase() {}
|
| -
|
| - protected:
|
| - ParserBase* parser() const { return parser_; }
|
| - Scanner* scanner() const { return parser_->scanner(); }
|
| -
|
| - private:
|
| - ParserBase* parser_;
|
| - };
|
| -
|
| - // Validation per ES6 object literals.
|
| - class ObjectLiteralChecker : public ObjectLiteralCheckerBase {
|
| - public:
|
| - explicit ObjectLiteralChecker(ParserBase* parser)
|
| - : ObjectLiteralCheckerBase(parser), has_seen_proto_(false) {}
|
| -
|
| - void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
| - bool is_generator, bool* ok) override;
|
| -
|
| - private:
|
| - bool IsProto() { return this->scanner()->LiteralMatches("__proto__", 9); }
|
| -
|
| - bool has_seen_proto_;
|
| - };
|
| -
|
| - // Validation per ES6 class literals.
|
| - class ClassLiteralChecker : public ObjectLiteralCheckerBase {
|
| - public:
|
| - explicit ClassLiteralChecker(ParserBase* parser)
|
| - : ObjectLiteralCheckerBase(parser), has_seen_constructor_(false) {}
|
| -
|
| - void CheckProperty(Token::Value property, PropertyKind type, bool is_static,
|
| - bool is_generator, bool* ok) override;
|
| -
|
| - private:
|
| - bool IsConstructor() {
|
| - return this->scanner()->LiteralMatches("constructor", 11);
|
| - }
|
| - bool IsPrototype() {
|
| - return this->scanner()->LiteralMatches("prototype", 9);
|
| - }
|
| -
|
| - bool has_seen_constructor_;
|
| - };
|
| -
|
| - // If true, the next (and immediately following) function literal is
|
| - // preceded by a parenthesis.
|
| - // Heuristically that means that the function will be called immediately,
|
| - // so never lazily compile it.
|
| - bool parenthesized_function_;
|
| -
|
| - Scope* scope_; // Scope stack.
|
| - FunctionState* function_state_; // Function state stack.
|
| - v8::Extension* extension_;
|
| - FuncNameInferrer* fni_;
|
| - AstValueFactory* ast_value_factory_; // Not owned.
|
| - ParserRecorder* log_;
|
| - Mode mode_;
|
| - uintptr_t stack_limit_;
|
| -
|
| - private:
|
| - Zone* zone_;
|
| -
|
| - Scanner* scanner_;
|
| - bool stack_overflow_;
|
| -
|
| - bool allow_lazy_;
|
| - bool allow_natives_;
|
| - bool allow_harmony_sloppy_;
|
| - bool allow_harmony_sloppy_function_;
|
| - bool allow_harmony_sloppy_let_;
|
| - bool allow_harmony_rest_parameters_;
|
| - bool allow_harmony_default_parameters_;
|
| - bool allow_harmony_destructuring_bind_;
|
| - bool allow_harmony_destructuring_assignment_;
|
| - bool allow_strong_mode_;
|
| - bool allow_legacy_const_;
|
| - bool allow_harmony_do_expressions_;
|
| -};
|
| -
|
| -
|
| class PreParserIdentifier {
|
| public:
|
| PreParserIdentifier() : type_(kUnknownIdentifier) {}
|
| @@ -2056,2436 +1149,6 @@ PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
|
| kind, function_type, ok);
|
| }
|
|
|
| -
|
| -template <class Traits>
|
| -ParserBase<Traits>::FunctionState::FunctionState(
|
| - FunctionState** function_state_stack, Scope** scope_stack, Scope* scope,
|
| - FunctionKind kind, typename Traits::Type::Factory* factory)
|
| - : next_materialized_literal_index_(0),
|
| - expected_property_count_(0),
|
| - this_location_(Scanner::Location::invalid()),
|
| - return_location_(Scanner::Location::invalid()),
|
| - super_location_(Scanner::Location::invalid()),
|
| - kind_(kind),
|
| - generator_object_variable_(NULL),
|
| - function_state_stack_(function_state_stack),
|
| - outer_function_state_(*function_state_stack),
|
| - scope_stack_(scope_stack),
|
| - outer_scope_(*scope_stack),
|
| - factory_(factory) {
|
| - *scope_stack_ = scope;
|
| - *function_state_stack = this;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -ParserBase<Traits>::FunctionState::~FunctionState() {
|
| - *scope_stack_ = outer_scope_;
|
| - *function_state_stack_ = outer_function_state_;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::GetUnexpectedTokenMessage(
|
| - Token::Value token, MessageTemplate::Template* message, const char** arg,
|
| - MessageTemplate::Template default_) {
|
| - // Four of the tokens are treated specially
|
| - switch (token) {
|
| - case Token::EOS:
|
| - *message = MessageTemplate::kUnexpectedEOS;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::SMI:
|
| - case Token::NUMBER:
|
| - *message = MessageTemplate::kUnexpectedTokenNumber;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::STRING:
|
| - *message = MessageTemplate::kUnexpectedTokenString;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::IDENTIFIER:
|
| - *message = MessageTemplate::kUnexpectedTokenIdentifier;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::FUTURE_RESERVED_WORD:
|
| - *message = MessageTemplate::kUnexpectedReserved;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::LET:
|
| - case Token::STATIC:
|
| - case Token::YIELD:
|
| - case Token::FUTURE_STRICT_RESERVED_WORD:
|
| - *message = is_strict(language_mode())
|
| - ? MessageTemplate::kUnexpectedStrictReserved
|
| - : MessageTemplate::kUnexpectedTokenIdentifier;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::TEMPLATE_SPAN:
|
| - case Token::TEMPLATE_TAIL:
|
| - *message = MessageTemplate::kUnexpectedTemplateString;
|
| - *arg = nullptr;
|
| - break;
|
| - case Token::ESCAPED_STRICT_RESERVED_WORD:
|
| - case Token::ESCAPED_KEYWORD:
|
| - *message = MessageTemplate::kInvalidEscapedReservedWord;
|
| - *arg = nullptr;
|
| - break;
|
| - default:
|
| - const char* name = Token::String(token);
|
| - DCHECK(name != NULL);
|
| - *arg = name;
|
| - break;
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
|
| - return ReportUnexpectedTokenAt(scanner_->location(), token);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::ReportUnexpectedTokenAt(
|
| - Scanner::Location source_location, Token::Value token,
|
| - MessageTemplate::Template message) {
|
| - const char* arg;
|
| - GetUnexpectedTokenMessage(token, &message, &arg);
|
| - Traits::ReportMessageAt(source_location, message, arg);
|
| -}
|
| -
|
| -
|
| -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());
|
| - // When this function is used to read a formal parameter, we don't always
|
| - // know whether the function is going to be strict or sloppy. Indeed for
|
| - // arrow functions we don't always know that the identifier we are reading
|
| - // is actually a formal parameter. Therefore besides the errors that we
|
| - // must detect because we know we're in strict mode, we also record any
|
| - // error that we might make in the future once we know the language mode.
|
| - if (this->IsEval(name)) {
|
| - classifier->RecordStrictModeFormalParameterError(
|
| - scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
| - if (is_strict(language_mode())) {
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
| - }
|
| - }
|
| - if (this->IsArguments(name)) {
|
| - scope_->RecordArgumentsUsage();
|
| - classifier->RecordStrictModeFormalParameterError(
|
| - scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
| - if (is_strict(language_mode())) {
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->location(), MessageTemplate::kStrictEvalArguments);
|
| - }
|
| - if (is_strong(language_mode())) {
|
| - classifier->RecordExpressionError(scanner()->location(),
|
| - MessageTemplate::kStrongArguments);
|
| - }
|
| - }
|
| - if (this->IsUndefined(name)) {
|
| - classifier->RecordStrongModeFormalParameterError(
|
| - scanner()->location(), MessageTemplate::kStrongUndefined);
|
| - if (is_strong(language_mode())) {
|
| - // TODO(dslomov): allow 'undefined' in nested patterns.
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->location(), MessageTemplate::kStrongUndefined);
|
| - classifier->RecordAssignmentPatternError(
|
| - scanner()->location(), MessageTemplate::kStrongUndefined);
|
| - }
|
| - }
|
| -
|
| - if (classifier->duplicate_finder() != nullptr &&
|
| - scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
|
| - classifier->RecordDuplicateFormalParameterError(scanner()->location());
|
| - }
|
| - return name;
|
| - } else if (is_sloppy(language_mode()) &&
|
| - (next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
| - next == Token::ESCAPED_STRICT_RESERVED_WORD ||
|
| - next == Token::LET || next == Token::STATIC ||
|
| - (next == Token::YIELD && !is_generator()))) {
|
| - classifier->RecordStrictModeFormalParameterError(
|
| - scanner()->location(), MessageTemplate::kUnexpectedStrictReserved);
|
| - if (next == Token::ESCAPED_STRICT_RESERVED_WORD &&
|
| - is_strict(language_mode())) {
|
| - ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return Traits::EmptyIdentifier();
|
| - }
|
| - if (next == Token::LET) {
|
| - classifier->RecordLetPatternError(scanner()->location(),
|
| - MessageTemplate::kLetInLexicalBinding);
|
| - }
|
| - return this->GetSymbol(scanner());
|
| - } else {
|
| - this->ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return Traits::EmptyIdentifier();
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::IdentifierT
|
| -ParserBase<Traits>::ParseIdentifierOrStrictReservedWord(
|
| - bool is_generator, bool* is_strict_reserved, bool* ok) {
|
| - Token::Value next = Next();
|
| - if (next == Token::IDENTIFIER) {
|
| - *is_strict_reserved = false;
|
| - } else if (next == Token::FUTURE_STRICT_RESERVED_WORD || next == Token::LET ||
|
| - next == Token::STATIC || (next == Token::YIELD && !is_generator)) {
|
| - *is_strict_reserved = true;
|
| - } else {
|
| - ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return Traits::EmptyIdentifier();
|
| - }
|
| -
|
| - IdentifierT name = this->GetSymbol(scanner());
|
| - if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
|
| - return name;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::IdentifierT
|
| -ParserBase<Traits>::ParseIdentifierName(bool* ok) {
|
| - Token::Value next = Next();
|
| - if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
|
| - next != Token::LET && next != Token::STATIC && next != Token::YIELD &&
|
| - next != Token::FUTURE_STRICT_RESERVED_WORD &&
|
| - next != Token::ESCAPED_KEYWORD &&
|
| - next != Token::ESCAPED_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
|
| - this->ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return Traits::EmptyIdentifier();
|
| - }
|
| -
|
| - IdentifierT name = this->GetSymbol(scanner());
|
| - if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
|
| - return name;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::IdentifierT
|
| -ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get,
|
| - bool* is_set,
|
| - bool* ok) {
|
| - IdentifierT result = ParseIdentifierName(ok);
|
| - if (!*ok) return Traits::EmptyIdentifier();
|
| - scanner()->IsGetOrSet(is_get, is_set);
|
| - return result;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral(
|
| - bool seen_equal, ExpressionClassifier* classifier, bool* ok) {
|
| - int pos = peek_position();
|
| - if (!scanner()->ScanRegExpPattern(seen_equal)) {
|
| - Next();
|
| - ReportMessage(MessageTemplate::kUnterminatedRegExp);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - }
|
| -
|
| - int literal_index = function_state_->NextMaterializedLiteralIndex();
|
| -
|
| - IdentifierT js_pattern = this->GetNextSymbol(scanner());
|
| - Maybe<RegExp::Flags> flags = scanner()->ScanRegExpFlags();
|
| - if (flags.IsNothing()) {
|
| - Next();
|
| - ReportMessage(MessageTemplate::kMalformedRegExpFlags);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - }
|
| - int js_flags = flags.FromJust();
|
| - Next();
|
| - return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index,
|
| - is_strong(language_mode()), pos);
|
| -}
|
| -
|
| -
|
| -#define CHECK_OK ok); \
|
| - if (!*ok) return this->EmptyExpression(); \
|
| - ((void)0
|
| -#define DUMMY ) // to make indentation work
|
| -#undef DUMMY
|
| -
|
| -// Used in functions where the return type is not ExpressionT.
|
| -#define CHECK_OK_CUSTOM(x) ok); \
|
| - if (!*ok) return this->x(); \
|
| - ((void)0
|
| -#define DUMMY ) // to make indentation work
|
| -#undef DUMMY
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // PrimaryExpression ::
|
| - // 'this'
|
| - // 'null'
|
| - // 'true'
|
| - // 'false'
|
| - // Identifier
|
| - // Number
|
| - // String
|
| - // ArrayLiteral
|
| - // ObjectLiteral
|
| - // RegExpLiteral
|
| - // ClassLiteral
|
| - // '(' Expression ')'
|
| - // TemplateLiteral
|
| - // do Block
|
| -
|
| - int beg_pos = peek_position();
|
| - switch (peek()) {
|
| - case Token::THIS: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - Consume(Token::THIS);
|
| - if (FLAG_strong_this && is_strong(language_mode())) {
|
| - // Constructors' usages of 'this' in strong mode are parsed separately.
|
| - // TODO(rossberg): this does not work with arrow functions yet.
|
| - if (IsClassConstructor(function_state_->kind())) {
|
| - ReportMessage(MessageTemplate::kStrongConstructorThis);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - }
|
| - return this->ThisExpression(scope_, factory(), beg_pos);
|
| - }
|
| -
|
| - case Token::NULL_LITERAL:
|
| - case Token::TRUE_LITERAL:
|
| - case Token::FALSE_LITERAL:
|
| - BindingPatternUnexpectedToken(classifier);
|
| - return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
|
| - case Token::SMI:
|
| - case Token::NUMBER:
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->peek_location(), MessageTemplate::kUnexpectedTokenNumber);
|
| - return this->ExpressionFromLiteral(Next(), beg_pos, scanner(), factory());
|
| -
|
| - case Token::IDENTIFIER:
|
| - case Token::LET:
|
| - case Token::STATIC:
|
| - case Token::YIELD:
|
| - case Token::ESCAPED_STRICT_RESERVED_WORD:
|
| - case Token::FUTURE_STRICT_RESERVED_WORD: {
|
| - // Using eval or arguments in this context is OK even in strict mode.
|
| - IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK);
|
| - return this->ExpressionFromIdentifier(
|
| - name, beg_pos, scanner()->location().end_pos, scope_, factory());
|
| - }
|
| -
|
| - case Token::STRING: {
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->peek_location(), MessageTemplate::kUnexpectedTokenString);
|
| - Consume(Token::STRING);
|
| - return this->ExpressionFromString(beg_pos, scanner(), factory());
|
| - }
|
| -
|
| - case Token::ASSIGN_DIV:
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
|
| - return this->ParseRegExpLiteral(true, classifier, ok);
|
| -
|
| - case Token::DIV:
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->peek_location(), MessageTemplate::kUnexpectedTokenRegExp);
|
| - return this->ParseRegExpLiteral(false, classifier, ok);
|
| -
|
| - case Token::LBRACK:
|
| - if (!allow_harmony_destructuring_bind()) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - }
|
| - return this->ParseArrayLiteral(classifier, ok);
|
| -
|
| - case Token::LBRACE:
|
| - if (!allow_harmony_destructuring_bind()) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - }
|
| - return this->ParseObjectLiteral(classifier, ok);
|
| -
|
| - case Token::LPAREN: {
|
| - // Arrow function formal parameters are either a single identifier or a
|
| - // list of BindingPattern productions enclosed in parentheses.
|
| - // Parentheses are not valid on the LHS of a BindingPattern, so we use the
|
| - // is_valid_binding_pattern() check to detect multiple levels of
|
| - // parenthesization.
|
| - if (!classifier->is_valid_binding_pattern()) {
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - }
|
| - BindingPatternUnexpectedToken(classifier);
|
| - Consume(Token::LPAREN);
|
| - if (Check(Token::RPAREN)) {
|
| - // ()=>x. The continuation that looks for the => is in
|
| - // ParseAssignmentExpression.
|
| - classifier->RecordExpressionError(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(Token::RPAREN));
|
| - classifier->RecordBindingPatternError(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(Token::RPAREN));
|
| - return factory()->NewEmptyParentheses(beg_pos);
|
| - } else if (allow_harmony_rest_parameters() && Check(Token::ELLIPSIS)) {
|
| - // (...x)=>x. The continuation that looks for the => is in
|
| - // ParseAssignmentExpression.
|
| - int ellipsis_pos = position();
|
| - classifier->RecordExpressionError(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(Token::ELLIPSIS));
|
| - classifier->RecordNonSimpleParameter();
|
| - Scanner::Location expr_loc = scanner()->peek_location();
|
| - Token::Value tok = peek();
|
| - ExpressionT expr =
|
| - this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| - // Patterns are not allowed as rest parameters. There is no way we can
|
| - // succeed so go ahead and use the convenient ReportUnexpectedToken
|
| - // interface.
|
| - if (!Traits::IsIdentifier(expr)) {
|
| - ReportUnexpectedTokenAt(expr_loc, tok);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - if (peek() == Token::COMMA) {
|
| - ReportMessageAt(scanner()->peek_location(),
|
| - MessageTemplate::kParamAfterRest);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - Expect(Token::RPAREN, CHECK_OK);
|
| - return factory()->NewSpread(expr, ellipsis_pos);
|
| - }
|
| - // Heuristically try to detect immediately called functions before
|
| - // seeing the call parentheses.
|
| - parenthesized_function_ = (peek() == Token::FUNCTION);
|
| - ExpressionT expr = this->ParseExpression(true, kIsPossibleArrowFormals,
|
| - classifier, CHECK_OK);
|
| - Expect(Token::RPAREN, CHECK_OK);
|
| - if (peek() != Token::ARROW) {
|
| - ValidateExpression(classifier, CHECK_OK);
|
| - }
|
| - return expr;
|
| - }
|
| -
|
| - case Token::CLASS: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - Consume(Token::CLASS);
|
| - if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
|
| - ReportMessage(MessageTemplate::kSloppyLexical);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - int class_token_position = position();
|
| - IdentifierT name = this->EmptyIdentifier();
|
| - bool is_strict_reserved_name = false;
|
| - Scanner::Location class_name_location = Scanner::Location::invalid();
|
| - if (peek_any_identifier()) {
|
| - name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
|
| - CHECK_OK);
|
| - class_name_location = scanner()->location();
|
| - }
|
| - return this->ParseClassLiteral(name, class_name_location,
|
| - is_strict_reserved_name,
|
| - class_token_position, ok);
|
| - }
|
| -
|
| - case Token::TEMPLATE_SPAN:
|
| - case Token::TEMPLATE_TAIL:
|
| - classifier->RecordBindingPatternError(
|
| - scanner()->peek_location(),
|
| - MessageTemplate::kUnexpectedTemplateString);
|
| - return this->ParseTemplateLiteral(Traits::NoTemplateTag(), beg_pos,
|
| - classifier, ok);
|
| -
|
| - case Token::MOD:
|
| - if (allow_natives() || extension_ != NULL) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - return this->ParseV8Intrinsic(ok);
|
| - }
|
| - break;
|
| -
|
| - case Token::DO:
|
| - if (allow_harmony_do_expressions()) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - return Traits::ParseDoExpression(ok);
|
| - }
|
| - break;
|
| -
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - ReportUnexpectedToken(Next());
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| - bool accept_IN, bool* ok) {
|
| - ExpressionClassifier classifier;
|
| - ExpressionT result = ParseExpression(accept_IN, &classifier, CHECK_OK);
|
| - ValidateExpression(&classifier, CHECK_OK);
|
| - return result;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| - bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
|
| - return ParseExpression(accept_IN, kIsLeftHandSide, classifier, ok);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| - bool accept_IN, int flags, ExpressionClassifier* classifier, bool* ok) {
|
| - // Expression ::
|
| - // AssignmentExpression
|
| - // Expression ',' AssignmentExpression
|
| -
|
| - ExpressionClassifier binding_classifier;
|
| - ExpressionT result = this->ParseAssignmentExpression(
|
| - accept_IN, flags, &binding_classifier, CHECK_OK);
|
| - classifier->Accumulate(binding_classifier,
|
| - ExpressionClassifier::AllProductions);
|
| - bool is_simple_parameter_list = this->IsIdentifier(result);
|
| - bool seen_rest = false;
|
| - while (peek() == Token::COMMA) {
|
| - if (seen_rest) {
|
| - // At this point the production can't possibly be valid, but we don't know
|
| - // which error to signal.
|
| - classifier->RecordArrowFormalParametersError(
|
| - scanner()->peek_location(), MessageTemplate::kParamAfterRest);
|
| - }
|
| - Consume(Token::COMMA);
|
| - bool is_rest = false;
|
| - if (allow_harmony_rest_parameters() && peek() == Token::ELLIPSIS) {
|
| - // 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
|
| - // as the formal parameters of'(x, y, ...z) => foo', and is not itself a
|
| - // valid expression or binding pattern.
|
| - ExpressionUnexpectedToken(classifier);
|
| - BindingPatternUnexpectedToken(classifier);
|
| - Consume(Token::ELLIPSIS);
|
| - seen_rest = is_rest = true;
|
| - }
|
| - int pos = position();
|
| - ExpressionT right = this->ParseAssignmentExpression(
|
| - accept_IN, flags, &binding_classifier, CHECK_OK);
|
| - if (is_rest) right = factory()->NewSpread(right, pos);
|
| - is_simple_parameter_list =
|
| - is_simple_parameter_list && this->IsIdentifier(right);
|
| - classifier->Accumulate(binding_classifier,
|
| - ExpressionClassifier::AllProductions);
|
| - result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
|
| - }
|
| - if (!is_simple_parameter_list || seen_rest) {
|
| - classifier->RecordNonSimpleParameter();
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // ArrayLiteral ::
|
| - // '[' Expression? (',' Expression?)* ']'
|
| -
|
| - int pos = peek_position();
|
| - typename Traits::Type::ExpressionList values =
|
| - this->NewExpressionList(4, zone_);
|
| - int first_spread_index = -1;
|
| - Expect(Token::LBRACK, CHECK_OK);
|
| - while (peek() != Token::RBRACK) {
|
| - ExpressionT elem = this->EmptyExpression();
|
| - if (peek() == Token::COMMA) {
|
| - if (is_strong(language_mode())) {
|
| - ReportMessageAt(scanner()->peek_location(),
|
| - MessageTemplate::kStrongEllision);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - elem = this->GetLiteralTheHole(peek_position(), factory());
|
| - } else if (peek() == Token::ELLIPSIS) {
|
| - int start_pos = peek_position();
|
| - Consume(Token::ELLIPSIS);
|
| - ExpressionT argument =
|
| - this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| - elem = factory()->NewSpread(argument, start_pos);
|
| -
|
| - if (first_spread_index < 0) {
|
| - first_spread_index = values->length();
|
| - }
|
| -
|
| - CheckDestructuringElement(argument, classifier, start_pos,
|
| - scanner()->location().end_pos);
|
| -
|
| - if (peek() == Token::COMMA) {
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(start_pos, scanner()->location().end_pos),
|
| - MessageTemplate::kElementAfterRest);
|
| - }
|
| - } else {
|
| - elem = this->ParseAssignmentExpression(true, kIsPatternElement,
|
| - classifier, CHECK_OK);
|
| - if (!this->IsValidReferenceExpression(elem) &&
|
| - !classifier->is_valid_assignment_pattern()) {
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidDestructuringTarget);
|
| - }
|
| - }
|
| - values->Add(elem, zone_);
|
| - if (peek() != Token::RBRACK) {
|
| - Expect(Token::COMMA, CHECK_OK);
|
| - }
|
| - }
|
| - Expect(Token::RBRACK, CHECK_OK);
|
| -
|
| - // Update the scope information before the pre-parsing bailout.
|
| - int literal_index = function_state_->NextMaterializedLiteralIndex();
|
| -
|
| - return factory()->NewArrayLiteral(values, first_spread_index, literal_index,
|
| - is_strong(language_mode()), pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParsePropertyName(
|
| - IdentifierT* name, bool* is_get, bool* is_set, bool* is_static,
|
| - bool* is_computed_name, bool* is_identifier, bool* is_escaped_keyword,
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - Token::Value token = peek();
|
| - int pos = peek_position();
|
| -
|
| - // For non computed property names we normalize the name a bit:
|
| - //
|
| - // "12" -> 12
|
| - // 12.3 -> "12.3"
|
| - // 12.30 -> "12.3"
|
| - // identifier -> "identifier"
|
| - //
|
| - // This is important because we use the property name as a key in a hash
|
| - // table when we compute constant properties.
|
| - switch (token) {
|
| - case Token::STRING:
|
| - Consume(Token::STRING);
|
| - *name = this->GetSymbol(scanner());
|
| - break;
|
| -
|
| - case Token::SMI:
|
| - Consume(Token::SMI);
|
| - *name = this->GetNumberAsSymbol(scanner());
|
| - break;
|
| -
|
| - case Token::NUMBER:
|
| - Consume(Token::NUMBER);
|
| - *name = this->GetNumberAsSymbol(scanner());
|
| - break;
|
| -
|
| - case Token::LBRACK: {
|
| - *is_computed_name = true;
|
| - Consume(Token::LBRACK);
|
| - ExpressionClassifier computed_name_classifier;
|
| - ExpressionT expression =
|
| - ParseAssignmentExpression(true, &computed_name_classifier, CHECK_OK);
|
| - classifier->Accumulate(computed_name_classifier,
|
| - ExpressionClassifier::ExpressionProductions);
|
| - Expect(Token::RBRACK, CHECK_OK);
|
| - return expression;
|
| - }
|
| -
|
| - case Token::ESCAPED_KEYWORD:
|
| - *is_escaped_keyword = true;
|
| - *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
|
| - break;
|
| -
|
| - case Token::STATIC:
|
| - *is_static = true;
|
| -
|
| - // Fall through.
|
| - default:
|
| - *is_identifier = true;
|
| - *name = ParseIdentifierNameOrGetOrSet(is_get, is_set, CHECK_OK);
|
| - break;
|
| - }
|
| -
|
| - uint32_t index;
|
| - return this->IsArrayIndex(*name, &index)
|
| - ? factory()->NewNumberLiteral(index, pos)
|
| - : factory()->NewStringLiteral(*name, pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ObjectLiteralPropertyT
|
| -ParserBase<Traits>::ParsePropertyDefinition(
|
| - ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends,
|
| - bool is_static, bool* is_computed_name, bool* has_seen_constructor,
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - DCHECK(!in_class || is_static || has_seen_constructor != nullptr);
|
| - ExpressionT value = this->EmptyExpression();
|
| - IdentifierT name = this->EmptyIdentifier();
|
| - bool is_get = false;
|
| - bool is_set = false;
|
| - bool name_is_static = false;
|
| - bool is_generator = Check(Token::MUL);
|
| -
|
| - Token::Value name_token = peek();
|
| - int next_beg_pos = scanner()->peek_location().beg_pos;
|
| - int next_end_pos = scanner()->peek_location().end_pos;
|
| - bool is_identifier = false;
|
| - bool is_escaped_keyword = false;
|
| - ExpressionT name_expression = ParsePropertyName(
|
| - &name, &is_get, &is_set, &name_is_static, is_computed_name,
|
| - &is_identifier, &is_escaped_keyword, classifier,
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| -
|
| - if (fni_ != nullptr && !*is_computed_name) {
|
| - this->PushLiteralName(fni_, name);
|
| - }
|
| -
|
| - bool escaped_static =
|
| - is_escaped_keyword &&
|
| - scanner()->is_literal_contextual_keyword(CStrVector("static"));
|
| -
|
| - if (!in_class && !is_generator) {
|
| - DCHECK(!is_static);
|
| -
|
| - if (peek() == Token::COLON) {
|
| - // PropertyDefinition
|
| - // PropertyName ':' AssignmentExpression
|
| - if (!*is_computed_name) {
|
| - checker->CheckProperty(name_token, kValueProperty, false, false,
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| - }
|
| - Consume(Token::COLON);
|
| - int pos = peek_position();
|
| - value = this->ParseAssignmentExpression(
|
| - true, kIsPatternElement, classifier,
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| -
|
| - if (!this->IsValidReferenceExpression(value) &&
|
| - !classifier->is_valid_assignment_pattern()) {
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidDestructuringTarget);
|
| - }
|
| -
|
| - return factory()->NewObjectLiteralProperty(name_expression, value, false,
|
| - *is_computed_name);
|
| - }
|
| -
|
| - if ((is_identifier || is_escaped_keyword) &&
|
| - (peek() == Token::COMMA || peek() == Token::RBRACE ||
|
| - peek() == Token::ASSIGN)) {
|
| - // PropertyDefinition
|
| - // IdentifierReference
|
| - // CoverInitializedName
|
| - //
|
| - // CoverInitializedName
|
| - // IdentifierReference Initializer?
|
| - if (!Token::IsIdentifier(name_token, language_mode(),
|
| - this->is_generator())) {
|
| - if (!escaped_static) {
|
| - ReportUnexpectedTokenAt(scanner()->location(), name_token);
|
| - *ok = false;
|
| - return this->EmptyObjectLiteralProperty();
|
| - }
|
| - }
|
| - if (classifier->duplicate_finder() != nullptr &&
|
| - scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
|
| - classifier->RecordDuplicateFormalParameterError(scanner()->location());
|
| - }
|
| - if (name_token == Token::LET) {
|
| - classifier->RecordLetPatternError(
|
| - scanner()->location(), MessageTemplate::kLetInLexicalBinding);
|
| - }
|
| -
|
| - ExpressionT lhs = this->ExpressionFromIdentifier(
|
| - name, next_beg_pos, next_end_pos, scope_, factory());
|
| -
|
| - if (peek() == Token::ASSIGN) {
|
| - Consume(Token::ASSIGN);
|
| - ExpressionClassifier rhs_classifier;
|
| - ExpressionT rhs = this->ParseAssignmentExpression(
|
| - true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| - classifier->Accumulate(rhs_classifier,
|
| - ExpressionClassifier::ExpressionProductions);
|
| - value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
|
| - RelocInfo::kNoPosition);
|
| - classifier->RecordCoverInitializedNameError(
|
| - Scanner::Location(next_beg_pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidCoverInitializedName);
|
| - } else {
|
| - value = lhs;
|
| - }
|
| -
|
| - return factory()->NewObjectLiteralProperty(
|
| - name_expression, value, ObjectLiteralProperty::COMPUTED, false,
|
| - false);
|
| - }
|
| - }
|
| -
|
| - if (in_class && escaped_static && !is_static) {
|
| - ReportUnexpectedTokenAt(scanner()->location(), name_token);
|
| - *ok = false;
|
| - return this->EmptyObjectLiteralProperty();
|
| - }
|
| -
|
| - // Method definitions are never valid in patterns.
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(next_beg_pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidDestructuringTarget);
|
| -
|
| - if (is_generator || peek() == Token::LPAREN) {
|
| - // MethodDefinition
|
| - // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
| - // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
| - if (!*is_computed_name) {
|
| - checker->CheckProperty(name_token, kMethodProperty, is_static,
|
| - is_generator,
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| - }
|
| -
|
| - FunctionKind kind = is_generator ? FunctionKind::kConciseGeneratorMethod
|
| - : FunctionKind::kConciseMethod;
|
| -
|
| - if (in_class && !is_static && this->IsConstructor(name)) {
|
| - *has_seen_constructor = true;
|
| - kind = has_extends ? FunctionKind::kSubclassConstructor
|
| - : FunctionKind::kBaseConstructor;
|
| - }
|
| -
|
| - if (!in_class) kind = WithObjectLiteralBit(kind);
|
| -
|
| - value = this->ParseFunctionLiteral(
|
| - name, scanner()->location(), kSkipFunctionNameCheck, kind,
|
| - RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
|
| - FunctionLiteral::NORMAL_ARITY, language_mode(),
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| -
|
| - return factory()->NewObjectLiteralProperty(name_expression, value,
|
| - ObjectLiteralProperty::COMPUTED,
|
| - is_static, *is_computed_name);
|
| - }
|
| -
|
| - if (in_class && name_is_static && !is_static) {
|
| - // ClassElement (static)
|
| - // 'static' MethodDefinition
|
| - return ParsePropertyDefinition(checker, true, has_extends, true,
|
| - is_computed_name, nullptr, classifier, ok);
|
| - }
|
| -
|
| - if (is_get || is_set) {
|
| - // MethodDefinition (Accessors)
|
| - // get PropertyName '(' ')' '{' FunctionBody '}'
|
| - // set PropertyName '(' PropertySetParameterList ')' '{' FunctionBody '}'
|
| - name = this->EmptyIdentifier();
|
| - bool dont_care = false;
|
| - name_token = peek();
|
| -
|
| - name_expression = ParsePropertyName(
|
| - &name, &dont_care, &dont_care, &dont_care, is_computed_name, &dont_care,
|
| - &dont_care, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| -
|
| - if (!*is_computed_name) {
|
| - checker->CheckProperty(name_token, kAccessorProperty, is_static,
|
| - is_generator,
|
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| - }
|
| -
|
| - FunctionKind kind = FunctionKind::kAccessorFunction;
|
| - if (!in_class) kind = WithObjectLiteralBit(kind);
|
| - typename Traits::Type::FunctionLiteral value = this->ParseFunctionLiteral(
|
| - name, scanner()->location(), kSkipFunctionNameCheck, kind,
|
| - RelocInfo::kNoPosition, FunctionLiteral::ANONYMOUS_EXPRESSION,
|
| - is_get ? FunctionLiteral::GETTER_ARITY : FunctionLiteral::SETTER_ARITY,
|
| - language_mode(), CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| -
|
| - // Make sure the name expression is a string since we need a Name for
|
| - // Runtime_DefineAccessorPropertyUnchecked and since we can determine this
|
| - // statically we can skip the extra runtime check.
|
| - if (!*is_computed_name) {
|
| - name_expression =
|
| - factory()->NewStringLiteral(name, name_expression->position());
|
| - }
|
| -
|
| - return factory()->NewObjectLiteralProperty(
|
| - name_expression, value,
|
| - is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER,
|
| - is_static, *is_computed_name);
|
| - }
|
| -
|
| - Token::Value next = Next();
|
| - ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return this->EmptyObjectLiteralProperty();
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // ObjectLiteral ::
|
| - // '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
|
| -
|
| - int pos = peek_position();
|
| - typename Traits::Type::PropertyList properties =
|
| - this->NewPropertyList(4, zone_);
|
| - int number_of_boilerplate_properties = 0;
|
| - bool has_function = false;
|
| - bool has_computed_names = false;
|
| - ObjectLiteralChecker checker(this);
|
| -
|
| - Expect(Token::LBRACE, CHECK_OK);
|
| -
|
| - while (peek() != Token::RBRACE) {
|
| - if (fni_ != nullptr) fni_->Enter();
|
| -
|
| - const bool in_class = false;
|
| - const bool is_static = false;
|
| - const bool has_extends = false;
|
| - bool is_computed_name = false;
|
| - ObjectLiteralPropertyT property = this->ParsePropertyDefinition(
|
| - &checker, in_class, has_extends, is_static, &is_computed_name, NULL,
|
| - classifier, CHECK_OK);
|
| -
|
| - if (is_computed_name) {
|
| - has_computed_names = true;
|
| - }
|
| -
|
| - // Mark top-level object literals that contain function literals and
|
| - // pretenure the literal so it can be added as a constant function
|
| - // property. (Parser only.)
|
| - this->CheckFunctionLiteralInsideTopLevelObjectLiteral(scope_, property,
|
| - &has_function);
|
| -
|
| - // Count CONSTANT or COMPUTED properties to maintain the enumeration order.
|
| - if (!has_computed_names && this->IsBoilerplateProperty(property)) {
|
| - number_of_boilerplate_properties++;
|
| - }
|
| - properties->Add(property, zone());
|
| -
|
| - if (peek() != Token::RBRACE) {
|
| - // Need {} because of the CHECK_OK macro.
|
| - Expect(Token::COMMA, CHECK_OK);
|
| - }
|
| -
|
| - if (fni_ != nullptr) {
|
| - fni_->Infer();
|
| - fni_->Leave();
|
| - }
|
| - }
|
| - Expect(Token::RBRACE, CHECK_OK);
|
| -
|
| - // Computation of literal_index must happen before pre parse bailout.
|
| - int literal_index = function_state_->NextMaterializedLiteralIndex();
|
| -
|
| - return factory()->NewObjectLiteral(properties,
|
| - literal_index,
|
| - number_of_boilerplate_properties,
|
| - has_function,
|
| - is_strong(language_mode()),
|
| - pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
| - Scanner::Location* first_spread_arg_loc, ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // Arguments ::
|
| - // '(' (AssignmentExpression)*[','] ')'
|
| -
|
| - Scanner::Location spread_arg = Scanner::Location::invalid();
|
| - typename Traits::Type::ExpressionList result =
|
| - this->NewExpressionList(4, zone_);
|
| - Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList));
|
| - bool done = (peek() == Token::RPAREN);
|
| - bool was_unspread = false;
|
| - int unspread_sequences_count = 0;
|
| - while (!done) {
|
| - int start_pos = peek_position();
|
| - bool is_spread = Check(Token::ELLIPSIS);
|
| -
|
| - ExpressionT argument = this->ParseAssignmentExpression(
|
| - true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
|
| - if (is_spread) {
|
| - if (!spread_arg.IsValid()) {
|
| - spread_arg.beg_pos = start_pos;
|
| - spread_arg.end_pos = peek_position();
|
| - }
|
| - argument = factory()->NewSpread(argument, start_pos);
|
| - }
|
| - result->Add(argument, zone_);
|
| -
|
| - // unspread_sequences_count is the number of sequences of parameters which
|
| - // are not prefixed with a spread '...' operator.
|
| - if (is_spread) {
|
| - was_unspread = false;
|
| - } else if (!was_unspread) {
|
| - was_unspread = true;
|
| - unspread_sequences_count++;
|
| - }
|
| -
|
| - if (result->length() > Code::kMaxArguments) {
|
| - ReportMessage(MessageTemplate::kTooManyArguments);
|
| - *ok = false;
|
| - return this->NullExpressionList();
|
| - }
|
| - done = (peek() != Token::COMMA);
|
| - if (!done) {
|
| - Next();
|
| - }
|
| - }
|
| - Scanner::Location location = scanner_->location();
|
| - if (Token::RPAREN != Next()) {
|
| - ReportMessageAt(location, MessageTemplate::kUnterminatedArgList);
|
| - *ok = false;
|
| - return this->NullExpressionList();
|
| - }
|
| - *first_spread_arg_loc = spread_arg;
|
| -
|
| - if (spread_arg.IsValid()) {
|
| - // Unspread parameter sequences are translated into array literals in the
|
| - // parser. Ensure that the number of materialized literals matches between
|
| - // the parser and preparser
|
| - Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -// Precedence = 2
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, int flags,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // AssignmentExpression ::
|
| - // ConditionalExpression
|
| - // ArrowFunction
|
| - // YieldExpression
|
| - // LeftHandSideExpression AssignmentOperator AssignmentExpression
|
| - bool is_rhs = flags & kIsRightHandSide;
|
| - bool is_pattern_element = flags & kIsPatternElement;
|
| - bool is_destructuring_assignment = false;
|
| - bool is_arrow_formals = flags & kIsPossibleArrowFormals;
|
| - int lhs_beg_pos = peek_position();
|
| -
|
| - if (peek() == Token::YIELD && is_generator()) {
|
| - return this->ParseYieldExpression(classifier, ok);
|
| - }
|
| -
|
| - if (fni_ != NULL) fni_->Enter();
|
| - ParserBase<Traits>::Checkpoint checkpoint(this);
|
| - ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
|
| - bool parenthesized_formals = peek() == Token::LPAREN;
|
| - if (!parenthesized_formals) {
|
| - ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
|
| - }
|
| - ExpressionT expression = this->ParseConditionalExpression(
|
| - accept_IN, &arrow_formals_classifier, CHECK_OK);
|
| - if (peek() == Token::ARROW) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
|
| - parenthesized_formals, CHECK_OK);
|
| - Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
|
| - Scope* scope =
|
| - this->NewScope(scope_, FUNCTION_SCOPE, FunctionKind::kArrowFunction);
|
| - // Because the arrow's parameters were parsed in the outer scope, any
|
| - // usage flags that might have been triggered there need to be copied
|
| - // to the arrow scope.
|
| - scope_->PropagateUsageFlagsToScope(scope);
|
| - FormalParametersT parameters(scope);
|
| - if (!arrow_formals_classifier.is_simple_parameter_list()) {
|
| - scope->SetHasNonSimpleParameters();
|
| - parameters.is_simple = false;
|
| - }
|
| -
|
| - Scanner::Location duplicate_loc = Scanner::Location::invalid();
|
| - this->ParseArrowFunctionFormalParameterList(¶meters, expression, loc,
|
| - &duplicate_loc, CHECK_OK);
|
| -
|
| - checkpoint.Restore(¶meters.materialized_literals_count);
|
| -
|
| - scope->set_start_position(lhs_beg_pos);
|
| - if (duplicate_loc.IsValid()) {
|
| - arrow_formals_classifier.RecordDuplicateFormalParameterError(
|
| - duplicate_loc);
|
| - }
|
| - expression = this->ParseArrowFunctionLiteral(
|
| - accept_IN, parameters, arrow_formals_classifier, CHECK_OK);
|
| - if (is_pattern_element) {
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidDestructuringTarget);
|
| - }
|
| - return expression;
|
| - }
|
| -
|
| - if (this->IsValidReferenceExpression(expression)) {
|
| - arrow_formals_classifier.ForgiveAssignmentPatternError();
|
| - }
|
| -
|
| - // "expression" was not itself an arrow function parameter list, but it might
|
| - // form part of one. Propagate speculative formal parameter error locations.
|
| - classifier->Accumulate(
|
| - arrow_formals_classifier,
|
| - ExpressionClassifier::StandardProductions |
|
| - ExpressionClassifier::FormalParametersProductions |
|
| - ExpressionClassifier::CoverInitializedNameProduction);
|
| -
|
| - bool maybe_pattern =
|
| - expression->IsObjectLiteral() || expression->IsArrayLiteral();
|
| - // bool binding_pattern =
|
| - // allow_harmony_destructuring_bind() && maybe_pattern && !is_rhs;
|
| -
|
| - if (!Token::IsAssignmentOp(peek())) {
|
| - if (fni_ != NULL) fni_->Leave();
|
| - // Parsed conditional expression only (no assignment).
|
| - if (is_pattern_element && !this->IsValidReferenceExpression(expression) &&
|
| - !maybe_pattern) {
|
| - classifier->RecordPatternError(
|
| - Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
|
| - MessageTemplate::kInvalidDestructuringTarget);
|
| - } else if (is_rhs && maybe_pattern) {
|
| - ValidateExpression(classifier, CHECK_OK);
|
| - }
|
| -
|
| - return expression;
|
| - }
|
| -
|
| - if (!(allow_harmony_destructuring_bind() ||
|
| - allow_harmony_default_parameters())) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - }
|
| -
|
| - if (allow_harmony_destructuring_assignment() && maybe_pattern &&
|
| - peek() == Token::ASSIGN) {
|
| - classifier->ForgiveCoverInitializedNameError();
|
| - ValidateAssignmentPattern(classifier, CHECK_OK);
|
| - is_destructuring_assignment = true;
|
| - } else if (is_arrow_formals) {
|
| - expression = this->ClassifyAndRewriteReferenceExpression(
|
| - classifier, expression, lhs_beg_pos, scanner()->location().end_pos,
|
| - MessageTemplate::kInvalidLhsInAssignment);
|
| - } else {
|
| - expression = this->CheckAndRewriteReferenceExpression(
|
| - expression, lhs_beg_pos, scanner()->location().end_pos,
|
| - MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
|
| - }
|
| -
|
| - expression = this->MarkExpressionAsAssigned(expression);
|
| -
|
| - Token::Value op = Next(); // Get assignment operator.
|
| - if (op != Token::ASSIGN) {
|
| - classifier->RecordBindingPatternError(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(op));
|
| - }
|
| - int pos = position();
|
| -
|
| - ExpressionClassifier rhs_classifier;
|
| -
|
| - int rhs_flags = flags;
|
| - rhs_flags &= ~(kIsPatternElement | kIsPossibleArrowFormals);
|
| - rhs_flags |= kIsRightHandSide;
|
| - ExpressionT right = this->ParseAssignmentExpression(
|
| - accept_IN, rhs_flags, &rhs_classifier, CHECK_OK);
|
| - classifier->Accumulate(
|
| - rhs_classifier, ExpressionClassifier::ExpressionProductions |
|
| - ExpressionClassifier::CoverInitializedNameProduction);
|
| -
|
| - // TODO(1231235): We try to estimate the set of properties set by
|
| - // constructors. We define a new property whenever there is an
|
| - // assignment to a property of 'this'. We should probably only add
|
| - // properties if we haven't seen them before. Otherwise we'll
|
| - // probably overestimate the number of properties.
|
| - if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
|
| - function_state_->AddProperty();
|
| - }
|
| -
|
| - this->CheckAssigningFunctionLiteralToProperty(expression, right);
|
| -
|
| - if (fni_ != NULL) {
|
| - // Check if the right hand side is a call to avoid inferring a
|
| - // name if we're dealing with "a = function(){...}();"-like
|
| - // expression.
|
| - if ((op == Token::INIT || op == Token::ASSIGN) &&
|
| - (!right->IsCall() && !right->IsCallNew())) {
|
| - fni_->Infer();
|
| - } else {
|
| - fni_->RemoveLastFunction();
|
| - }
|
| - fni_->Leave();
|
| - }
|
| -
|
| - ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
|
| -
|
| - if (is_destructuring_assignment) {
|
| - result = factory()->NewRewritableAssignmentExpression(result);
|
| - Traits::QueueDestructuringAssignmentForRewriting(result);
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // YieldExpression ::
|
| - // 'yield' ([no line terminator] '*'? AssignmentExpression)?
|
| - int pos = peek_position();
|
| - BindingPatternUnexpectedToken(classifier);
|
| - FormalParameterInitializerUnexpectedToken(classifier);
|
| - Expect(Token::YIELD, CHECK_OK);
|
| - ExpressionT generator_object =
|
| - factory()->NewVariableProxy(function_state_->generator_object_variable());
|
| - ExpressionT expression = Traits::EmptyExpression();
|
| - Yield::Kind kind = Yield::kSuspend;
|
| - if (!scanner()->HasAnyLineTerminatorBeforeNext()) {
|
| - if (Check(Token::MUL)) kind = Yield::kDelegating;
|
| - switch (peek()) {
|
| - case Token::EOS:
|
| - case Token::SEMICOLON:
|
| - case Token::RBRACE:
|
| - case Token::RBRACK:
|
| - case Token::RPAREN:
|
| - case Token::COLON:
|
| - case Token::COMMA:
|
| - // The above set of tokens is the complete set of tokens that can appear
|
| - // after an AssignmentExpression, and none of them can start an
|
| - // AssignmentExpression. This allows us to avoid looking for an RHS for
|
| - // a Yield::kSuspend operation, given only one look-ahead token.
|
| - if (kind == Yield::kSuspend)
|
| - break;
|
| - DCHECK_EQ(Yield::kDelegating, kind);
|
| - // Delegating yields require an RHS; fall through.
|
| - default:
|
| - expression = ParseAssignmentExpression(false, classifier, CHECK_OK);
|
| - break;
|
| - }
|
| - }
|
| - if (kind == Yield::kDelegating) {
|
| - // var iterator = subject[Symbol.iterator]();
|
| - // Hackily disambiguate o from o.next and o [Symbol.iterator]().
|
| - // TODO(verwaest): Come up with a better solution.
|
| - expression = this->GetIterator(expression, factory(), pos + 1);
|
| - }
|
| - // Hackily disambiguate o from o.next and o [Symbol.iterator]().
|
| - // TODO(verwaest): Come up with a better solution.
|
| - typename Traits::Type::YieldExpression yield =
|
| - factory()->NewYield(generator_object, expression, kind, pos);
|
| - return yield;
|
| -}
|
| -
|
| -
|
| -// Precedence = 3
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseConditionalExpression(bool accept_IN,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // ConditionalExpression ::
|
| - // LogicalOrExpression
|
| - // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
|
| -
|
| - int pos = peek_position();
|
| - // We start using the binary expression parser for prec >= 4 only!
|
| - ExpressionT expression =
|
| - this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
|
| - if (peek() != Token::CONDITIONAL) return expression;
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - BindingPatternUnexpectedToken(classifier);
|
| - Consume(Token::CONDITIONAL);
|
| - // In parsing the first assignment expression in conditional
|
| - // expressions we always accept the 'in' keyword; see ECMA-262,
|
| - // section 11.12, page 58.
|
| - ExpressionT left = ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| - Expect(Token::COLON, CHECK_OK);
|
| - ExpressionT right =
|
| - ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
|
| - return factory()->NewConditional(expression, left, right, pos);
|
| -}
|
| -
|
| -
|
| -// Precedence >= 4
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - DCHECK(prec >= 4);
|
| - ExpressionT x = this->ParseUnaryExpression(classifier, CHECK_OK);
|
| - for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
|
| - // prec1 >= 4
|
| - while (Precedence(peek(), accept_IN) == prec1) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - Token::Value op = Next();
|
| - Scanner::Location op_location = scanner()->location();
|
| - int pos = position();
|
| - ExpressionT y =
|
| - ParseBinaryExpression(prec1 + 1, accept_IN, classifier, CHECK_OK);
|
| -
|
| - if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
|
| - factory())) {
|
| - continue;
|
| - }
|
| -
|
| - // For now we distinguish between comparisons and other binary
|
| - // operations. (We could combine the two and get rid of this
|
| - // code and AST node eventually.)
|
| - if (Token::IsCompareOp(op)) {
|
| - // We have a comparison.
|
| - Token::Value cmp = op;
|
| - switch (op) {
|
| - case Token::NE: cmp = Token::EQ; break;
|
| - case Token::NE_STRICT: cmp = Token::EQ_STRICT; break;
|
| - default: break;
|
| - }
|
| - if (cmp == Token::EQ && is_strong(language_mode())) {
|
| - ReportMessageAt(op_location, MessageTemplate::kStrongEqual);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - x = factory()->NewCompareOperation(cmp, x, y, pos);
|
| - if (cmp != op) {
|
| - // The comparison was negated - add a NOT.
|
| - x = factory()->NewUnaryOperation(Token::NOT, x, pos);
|
| - }
|
| -
|
| - } else {
|
| - // We have a "normal" binary operation.
|
| - x = factory()->NewBinaryOperation(op, x, y, pos);
|
| - }
|
| - }
|
| - }
|
| - return x;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // UnaryExpression ::
|
| - // PostfixExpression
|
| - // 'delete' UnaryExpression
|
| - // 'void' UnaryExpression
|
| - // 'typeof' UnaryExpression
|
| - // '++' UnaryExpression
|
| - // '--' UnaryExpression
|
| - // '+' UnaryExpression
|
| - // '-' UnaryExpression
|
| - // '~' UnaryExpression
|
| - // '!' UnaryExpression
|
| -
|
| - Token::Value op = peek();
|
| - if (Token::IsUnaryOp(op)) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - op = Next();
|
| - int pos = position();
|
| - ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
|
| -
|
| - if (op == Token::DELETE && is_strict(language_mode())) {
|
| - if (is_strong(language_mode())) {
|
| - ReportMessage(MessageTemplate::kStrongDelete);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - } else if (this->IsIdentifier(expression)) {
|
| - // "delete identifier" is a syntax error in strict mode.
|
| - ReportMessage(MessageTemplate::kStrictDelete);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - }
|
| -
|
| - // Allow Traits do rewrite the expression.
|
| - return this->BuildUnaryExpression(expression, op, pos, factory());
|
| - } else if (Token::IsCountOp(op)) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - op = Next();
|
| - int beg_pos = peek_position();
|
| - ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
|
| - expression = this->CheckAndRewriteReferenceExpression(
|
| - expression, beg_pos, scanner()->location().end_pos,
|
| - MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
|
| - this->MarkExpressionAsAssigned(expression);
|
| -
|
| - return factory()->NewCountOperation(op,
|
| - true /* prefix */,
|
| - expression,
|
| - position());
|
| -
|
| - } else {
|
| - return this->ParsePostfixExpression(classifier, ok);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // PostfixExpression ::
|
| - // LeftHandSideExpression ('++' | '--')?
|
| -
|
| - int lhs_beg_pos = peek_position();
|
| - ExpressionT expression =
|
| - this->ParseLeftHandSideExpression(classifier, CHECK_OK);
|
| - if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| - Token::IsCountOp(peek())) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - expression = this->CheckAndRewriteReferenceExpression(
|
| - expression, lhs_beg_pos, scanner()->location().end_pos,
|
| - MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
|
| - expression = this->MarkExpressionAsAssigned(expression);
|
| -
|
| - Token::Value next = Next();
|
| - expression =
|
| - factory()->NewCountOperation(next,
|
| - false /* postfix */,
|
| - expression,
|
| - position());
|
| - }
|
| - return expression;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseLeftHandSideExpression(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // LeftHandSideExpression ::
|
| - // (NewExpression | MemberExpression) ...
|
| -
|
| - ExpressionT result =
|
| - this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
| -
|
| - while (true) {
|
| - switch (peek()) {
|
| - case Token::LBRACK: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - Consume(Token::LBRACK);
|
| - int pos = position();
|
| - ExpressionT index = ParseExpression(true, classifier, CHECK_OK);
|
| - result = factory()->NewProperty(result, index, pos);
|
| - Expect(Token::RBRACK, CHECK_OK);
|
| - break;
|
| - }
|
| -
|
| - case Token::LPAREN: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - if (is_strong(language_mode()) && this->IsIdentifier(result) &&
|
| - this->IsEval(this->AsIdentifier(result))) {
|
| - ReportMessage(MessageTemplate::kStrongDirectEval);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - int pos;
|
| - if (scanner()->current_token() == Token::IDENTIFIER ||
|
| - scanner()->current_token() == Token::SUPER) {
|
| - // For call of an identifier we want to report position of
|
| - // the identifier as position of the call in the stack trace.
|
| - pos = position();
|
| - } else {
|
| - // For other kinds of calls we record position of the parenthesis as
|
| - // position of the call. Note that this is extremely important for
|
| - // expressions of the form function(){...}() for which call position
|
| - // should not point to the closing brace otherwise it will intersect
|
| - // with positions recorded for function literal and confuse debugger.
|
| - pos = peek_position();
|
| - // Also the trailing parenthesis are a hint that the function will
|
| - // be called immediately. If we happen to have parsed a preceding
|
| - // function literal eagerly, we can also compile it eagerly.
|
| - if (result->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
|
| - result->AsFunctionLiteral()->set_should_eager_compile();
|
| - }
|
| - }
|
| - Scanner::Location spread_pos;
|
| - typename Traits::Type::ExpressionList args =
|
| - ParseArguments(&spread_pos, classifier, CHECK_OK);
|
| -
|
| - // Keep track of eval() calls since they disable all local variable
|
| - // optimizations.
|
| - // The calls that need special treatment are the
|
| - // direct eval calls. These calls are all of the form eval(...), with
|
| - // no explicit receiver.
|
| - // These calls are marked as potentially direct eval calls. Whether
|
| - // they are actually direct calls to eval is determined at run time.
|
| - this->CheckPossibleEvalCall(result, scope_);
|
| -
|
| - bool is_super_call = result->IsSuperCallReference();
|
| - if (spread_pos.IsValid()) {
|
| - args = Traits::PrepareSpreadArguments(args);
|
| - result = Traits::SpreadCall(result, args, pos);
|
| - } else {
|
| - result = factory()->NewCall(result, args, pos);
|
| - }
|
| -
|
| - // Explicit calls to the super constructor using super() perform an
|
| - // implicit binding assignment to the 'this' variable.
|
| - if (is_super_call) {
|
| - ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
|
| - result =
|
| - factory()->NewAssignment(Token::INIT, this_expr, result, pos);
|
| - }
|
| -
|
| - if (fni_ != NULL) fni_->RemoveLastFunction();
|
| - break;
|
| - }
|
| -
|
| - case Token::PERIOD: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - Consume(Token::PERIOD);
|
| - int pos = position();
|
| - IdentifierT name = ParseIdentifierName(CHECK_OK);
|
| - result = factory()->NewProperty(
|
| - result, factory()->NewStringLiteral(name, pos), pos);
|
| - if (fni_ != NULL) this->PushLiteralName(fni_, name);
|
| - break;
|
| - }
|
| -
|
| - case Token::TEMPLATE_SPAN:
|
| - case Token::TEMPLATE_TAIL: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - result = ParseTemplateLiteral(result, position(), classifier, CHECK_OK);
|
| - break;
|
| - }
|
| -
|
| - default:
|
| - return result;
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // NewExpression ::
|
| - // ('new')+ MemberExpression
|
| - //
|
| - // NewTarget ::
|
| - // 'new' '.' 'target'
|
| -
|
| - // The grammar for new expressions is pretty warped. We can have several 'new'
|
| - // keywords following each other, and then a MemberExpression. When we see '('
|
| - // after the MemberExpression, it's associated with the rightmost unassociated
|
| - // 'new' to create a NewExpression with arguments. However, a NewExpression
|
| - // can also occur without arguments.
|
| -
|
| - // Examples of new expression:
|
| - // new foo.bar().baz means (new (foo.bar)()).baz
|
| - // new foo()() means (new foo())()
|
| - // new new foo()() means (new (new foo())())
|
| - // new new foo means new (new foo)
|
| - // new new foo() means new (new foo())
|
| - // new new foo().bar().baz means (new (new foo()).bar()).baz
|
| -
|
| - if (peek() == Token::NEW) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - Consume(Token::NEW);
|
| - int new_pos = position();
|
| - ExpressionT result = this->EmptyExpression();
|
| - if (peek() == Token::SUPER) {
|
| - const bool is_new = true;
|
| - result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
| - } else if (peek() == Token::PERIOD) {
|
| - return ParseNewTargetExpression(CHECK_OK);
|
| - } else {
|
| - result = this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
| - }
|
| - if (peek() == Token::LPAREN) {
|
| - // NewExpression with arguments.
|
| - Scanner::Location spread_pos;
|
| - typename Traits::Type::ExpressionList args =
|
| - this->ParseArguments(&spread_pos, classifier, CHECK_OK);
|
| -
|
| - if (spread_pos.IsValid()) {
|
| - args = Traits::PrepareSpreadArguments(args);
|
| - result = Traits::SpreadCallNew(result, args, new_pos);
|
| - } else {
|
| - result = factory()->NewCallNew(result, args, new_pos);
|
| - }
|
| - // The expression can still continue with . or [ after the arguments.
|
| - result =
|
| - this->ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
|
| - return result;
|
| - }
|
| - // NewExpression without arguments.
|
| - return factory()->NewCallNew(result, this->NewExpressionList(0, zone_),
|
| - new_pos);
|
| - }
|
| - // No 'new' or 'super' keyword.
|
| - return this->ParseMemberExpression(classifier, ok);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // MemberExpression ::
|
| - // (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
| - // ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
| -
|
| - // The '[' Expression ']' and '.' Identifier parts are parsed by
|
| - // ParseMemberExpressionContinuation, and the Arguments part is parsed by the
|
| - // caller.
|
| -
|
| - // Parse the initial primary or function expression.
|
| - ExpressionT result = this->EmptyExpression();
|
| - if (peek() == Token::FUNCTION) {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - Consume(Token::FUNCTION);
|
| - int function_token_position = position();
|
| - bool is_generator = Check(Token::MUL);
|
| - IdentifierT name = this->EmptyIdentifier();
|
| - bool is_strict_reserved_name = false;
|
| - Scanner::Location function_name_location = Scanner::Location::invalid();
|
| - FunctionLiteral::FunctionType function_type =
|
| - FunctionLiteral::ANONYMOUS_EXPRESSION;
|
| - if (peek_any_identifier()) {
|
| - name = ParseIdentifierOrStrictReservedWord(
|
| - is_generator, &is_strict_reserved_name, CHECK_OK);
|
| - function_name_location = scanner()->location();
|
| - function_type = FunctionLiteral::NAMED_EXPRESSION;
|
| - }
|
| - result = this->ParseFunctionLiteral(
|
| - name, function_name_location,
|
| - is_strict_reserved_name ? kFunctionNameIsStrictReserved
|
| - : kFunctionNameValidityUnknown,
|
| - is_generator ? FunctionKind::kGeneratorFunction
|
| - : FunctionKind::kNormalFunction,
|
| - function_token_position, function_type, FunctionLiteral::NORMAL_ARITY,
|
| - language_mode(), CHECK_OK);
|
| - } else if (peek() == Token::SUPER) {
|
| - const bool is_new = false;
|
| - result = ParseSuperExpression(is_new, classifier, CHECK_OK);
|
| - } else {
|
| - result = ParsePrimaryExpression(classifier, CHECK_OK);
|
| - }
|
| -
|
| - result = ParseMemberExpressionContinuation(result, classifier, CHECK_OK);
|
| - return result;
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseStrongInitializationExpression(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // InitializationExpression :: (strong mode)
|
| - // 'this' '.' IdentifierName '=' AssignmentExpression
|
| - // 'this' '[' Expression ']' '=' AssignmentExpression
|
| -
|
| - if (fni_ != NULL) fni_->Enter();
|
| -
|
| - Consume(Token::THIS);
|
| - int pos = position();
|
| - function_state_->set_this_location(scanner()->location());
|
| - ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
|
| -
|
| - ExpressionT left = this->EmptyExpression();
|
| - switch (peek()) {
|
| - case Token::LBRACK: {
|
| - Consume(Token::LBRACK);
|
| - int pos = position();
|
| - ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
|
| - left = factory()->NewProperty(this_expr, index, pos);
|
| - if (fni_ != NULL) {
|
| - this->PushPropertyName(fni_, index);
|
| - }
|
| - Expect(Token::RBRACK, CHECK_OK);
|
| - break;
|
| - }
|
| - case Token::PERIOD: {
|
| - Consume(Token::PERIOD);
|
| - int pos = position();
|
| - IdentifierT name = ParseIdentifierName(CHECK_OK);
|
| - left = factory()->NewProperty(
|
| - this_expr, factory()->NewStringLiteral(name, pos), pos);
|
| - if (fni_ != NULL) {
|
| - this->PushLiteralName(fni_, name);
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - ReportMessage(MessageTemplate::kStrongConstructorThis);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - if (peek() != Token::ASSIGN) {
|
| - ReportMessageAt(function_state_->this_location(),
|
| - MessageTemplate::kStrongConstructorThis);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - Consume(Token::ASSIGN);
|
| - left = this->MarkExpressionAsAssigned(left);
|
| -
|
| - ExpressionT right =
|
| - this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| - this->CheckAssigningFunctionLiteralToProperty(left, right);
|
| - function_state_->AddProperty();
|
| - if (fni_ != NULL) {
|
| - // Check if the right hand side is a call to avoid inferring a
|
| - // name if we're dealing with "this.a = function(){...}();"-like
|
| - // expression.
|
| - if (!right->IsCall() && !right->IsCallNew()) {
|
| - fni_->Infer();
|
| - } else {
|
| - fni_->RemoveLastFunction();
|
| - }
|
| - fni_->Leave();
|
| - }
|
| -
|
| - if (function_state_->return_location().IsValid()) {
|
| - ReportMessageAt(function_state_->return_location(),
|
| - MessageTemplate::kStrongConstructorReturnMisplaced);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - return factory()->NewAssignment(Token::ASSIGN, left, right, pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseStrongSuperCallExpression(
|
| - ExpressionClassifier* classifier, bool* ok) {
|
| - // SuperCallExpression :: (strong mode)
|
| - // 'super' '(' ExpressionList ')'
|
| - BindingPatternUnexpectedToken(classifier);
|
| -
|
| - Consume(Token::SUPER);
|
| - int pos = position();
|
| - Scanner::Location super_loc = scanner()->location();
|
| - ExpressionT expr = this->SuperCallReference(scope_, factory(), pos);
|
| -
|
| - if (peek() != Token::LPAREN) {
|
| - ReportMessage(MessageTemplate::kStrongConstructorSuper);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - Scanner::Location spread_pos;
|
| - typename Traits::Type::ExpressionList args =
|
| - ParseArguments(&spread_pos, classifier, CHECK_OK);
|
| -
|
| - // TODO(rossberg): This doesn't work with arrow functions yet.
|
| - if (!IsSubclassConstructor(function_state_->kind())) {
|
| - ReportMessage(MessageTemplate::kUnexpectedSuper);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - } else if (function_state_->super_location().IsValid()) {
|
| - ReportMessageAt(scanner()->location(),
|
| - MessageTemplate::kStrongSuperCallDuplicate);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - } else if (function_state_->this_location().IsValid()) {
|
| - ReportMessageAt(scanner()->location(),
|
| - MessageTemplate::kStrongSuperCallMisplaced);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - } else if (function_state_->return_location().IsValid()) {
|
| - ReportMessageAt(function_state_->return_location(),
|
| - MessageTemplate::kStrongConstructorReturnMisplaced);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - function_state_->set_super_location(super_loc);
|
| - if (spread_pos.IsValid()) {
|
| - args = Traits::PrepareSpreadArguments(args);
|
| - expr = Traits::SpreadCall(expr, args, pos);
|
| - } else {
|
| - expr = factory()->NewCall(expr, args, pos);
|
| - }
|
| -
|
| - // Explicit calls to the super constructor using super() perform an implicit
|
| - // binding assignment to the 'this' variable.
|
| - ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos);
|
| - return factory()->NewAssignment(Token::INIT, this_expr, expr, pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseSuperExpression(bool is_new,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - Expect(Token::SUPER, CHECK_OK);
|
| - int pos = position();
|
| -
|
| - Scope* scope = scope_->ReceiverScope();
|
| - FunctionKind kind = scope->function_kind();
|
| - if (IsConciseMethod(kind) || IsAccessorFunction(kind) ||
|
| - IsClassConstructor(kind)) {
|
| - if (peek() == Token::PERIOD || peek() == Token::LBRACK) {
|
| - scope->RecordSuperPropertyUsage();
|
| - return this->SuperPropertyReference(scope_, factory(), pos);
|
| - }
|
| - // new super() is never allowed.
|
| - // super() is only allowed in derived constructor
|
| - if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) {
|
| - if (is_strong(language_mode())) {
|
| - // Super calls in strong mode are parsed separately.
|
| - ReportMessageAt(scanner()->location(),
|
| - MessageTemplate::kStrongConstructorSuper);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| - // TODO(rossberg): This might not be the correct FunctionState for the
|
| - // method here.
|
| - function_state_->set_super_location(scanner()->location());
|
| - return this->SuperCallReference(scope_, factory(), pos);
|
| - }
|
| - }
|
| -
|
| - ReportMessageAt(scanner()->location(), MessageTemplate::kUnexpectedSuper);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseNewTargetExpression(bool* ok) {
|
| - int pos = position();
|
| - Consume(Token::PERIOD);
|
| - ExpectContextualKeyword(CStrVector("target"), CHECK_OK);
|
| -
|
| - if (!scope_->ReceiverScope()->is_function_scope()) {
|
| - ReportMessageAt(scanner()->location(),
|
| - MessageTemplate::kUnexpectedNewTarget);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - return this->NewTargetExpression(scope_, factory(), pos);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseMemberExpressionContinuation(
|
| - ExpressionT expression, ExpressionClassifier* classifier, bool* ok) {
|
| - // Parses this part of MemberExpression:
|
| - // ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
| - while (true) {
|
| - switch (peek()) {
|
| - case Token::LBRACK: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - Consume(Token::LBRACK);
|
| - int pos = position();
|
| - ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
|
| - expression = factory()->NewProperty(expression, index, pos);
|
| - if (fni_ != NULL) {
|
| - this->PushPropertyName(fni_, index);
|
| - }
|
| - Expect(Token::RBRACK, CHECK_OK);
|
| - break;
|
| - }
|
| - case Token::PERIOD: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| -
|
| - Consume(Token::PERIOD);
|
| - int pos = position();
|
| - IdentifierT name = ParseIdentifierName(CHECK_OK);
|
| - expression = factory()->NewProperty(
|
| - expression, factory()->NewStringLiteral(name, pos), pos);
|
| - if (fni_ != NULL) {
|
| - this->PushLiteralName(fni_, name);
|
| - }
|
| - break;
|
| - }
|
| - case Token::TEMPLATE_SPAN:
|
| - case Token::TEMPLATE_TAIL: {
|
| - BindingPatternUnexpectedToken(classifier);
|
| - ArrowFormalParametersUnexpectedToken(classifier);
|
| - int pos;
|
| - if (scanner()->current_token() == Token::IDENTIFIER) {
|
| - pos = position();
|
| - } else {
|
| - pos = peek_position();
|
| - if (expression->IsFunctionLiteral() && mode() == PARSE_EAGERLY) {
|
| - // If the tag function looks like an IIFE, set_parenthesized() to
|
| - // force eager compilation.
|
| - expression->AsFunctionLiteral()->set_should_eager_compile();
|
| - }
|
| - }
|
| - expression =
|
| - ParseTemplateLiteral(expression, pos, classifier, CHECK_OK);
|
| - break;
|
| - }
|
| - default:
|
| - return expression;
|
| - }
|
| - }
|
| - DCHECK(false);
|
| - return this->EmptyExpression();
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::ParseFormalParameter(
|
| - FormalParametersT* parameters, ExpressionClassifier* classifier, bool* ok) {
|
| - // FormalParameter[Yield,GeneratorParameter] :
|
| - // BindingElement[?Yield, ?GeneratorParameter]
|
| - bool is_rest = parameters->has_rest;
|
| -
|
| - Token::Value next = peek();
|
| - ExpressionT pattern = ParsePrimaryExpression(classifier, ok);
|
| - if (!*ok) return;
|
| -
|
| - ValidateBindingPattern(classifier, ok);
|
| - if (!*ok) return;
|
| -
|
| - if (!Traits::IsIdentifier(pattern)) {
|
| - if (is_rest || !allow_harmony_destructuring_bind()) {
|
| - ReportUnexpectedToken(next);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - parameters->is_simple = false;
|
| - ValidateFormalParameterInitializer(classifier, ok);
|
| - if (!*ok) return;
|
| - classifier->RecordNonSimpleParameter();
|
| - }
|
| -
|
| - if (is_rest) {
|
| - parameters->rest_array_literal_index =
|
| - function_state_->NextMaterializedLiteralIndex();
|
| - ++parameters->materialized_literals_count;
|
| - }
|
| -
|
| - ExpressionT initializer = Traits::EmptyExpression();
|
| - if (!is_rest && allow_harmony_default_parameters() && Check(Token::ASSIGN)) {
|
| - ExpressionClassifier init_classifier;
|
| - initializer = ParseAssignmentExpression(true, &init_classifier, ok);
|
| - if (!*ok) return;
|
| - ValidateExpression(&init_classifier, ok);
|
| - ValidateFormalParameterInitializer(&init_classifier, ok);
|
| - if (!*ok) return;
|
| - parameters->is_simple = false;
|
| - classifier->RecordNonSimpleParameter();
|
| - }
|
| -
|
| - Traits::AddFormalParameter(parameters, pattern, initializer,
|
| - scanner()->location().end_pos, is_rest);
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::ParseFormalParameterList(
|
| - FormalParametersT* parameters, ExpressionClassifier* classifier, 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]
|
| -
|
| - DCHECK_EQ(0, parameters->Arity());
|
| -
|
| - if (peek() != Token::RPAREN) {
|
| - do {
|
| - if (parameters->Arity() > Code::kMaxArguments) {
|
| - ReportMessage(MessageTemplate::kTooManyParameters);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - parameters->has_rest =
|
| - allow_harmony_rest_parameters() && Check(Token::ELLIPSIS);
|
| - ParseFormalParameter(parameters, classifier, ok);
|
| - if (!*ok) return;
|
| - } while (!parameters->has_rest && Check(Token::COMMA));
|
| -
|
| - if (parameters->has_rest) {
|
| - parameters->is_simple = false;
|
| - classifier->RecordNonSimpleParameter();
|
| - if (peek() == Token::COMMA) {
|
| - ReportMessageAt(scanner()->peek_location(),
|
| - MessageTemplate::kParamAfterRest);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - }
|
| - }
|
| -
|
| - for (int i = 0; i < parameters->Arity(); ++i) {
|
| - auto parameter = parameters->at(i);
|
| - Traits::DeclareFormalParameter(parameters->scope, parameter, classifier);
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -void ParserBase<Traits>::CheckArityRestrictions(
|
| - int param_count, FunctionLiteral::ArityRestriction arity_restriction,
|
| - bool has_rest, 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),
|
| - MessageTemplate::kBadGetterArity);
|
| - *ok = false;
|
| - }
|
| - break;
|
| - case FunctionLiteral::SETTER_ARITY:
|
| - if (param_count != 1) {
|
| - ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
|
| - MessageTemplate::kBadSetterArity);
|
| - *ok = false;
|
| - }
|
| - if (has_rest) {
|
| - ReportMessageAt(Scanner::Location(formals_start_pos, formals_end_pos),
|
| - MessageTemplate::kBadSetterRestParameter);
|
| - *ok = false;
|
| - }
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -bool ParserBase<Traits>::IsNextLetKeyword() {
|
| - DCHECK(peek() == Token::LET);
|
| - if (!allow_let()) {
|
| - return false;
|
| - }
|
| - Token::Value next_next = PeekAhead();
|
| - switch (next_next) {
|
| - case Token::LBRACE:
|
| - case Token::LBRACK:
|
| - case Token::IDENTIFIER:
|
| - case Token::STATIC:
|
| - case Token::LET: // Yes, you can do let let = ... in sloppy mode
|
| - case Token::YIELD:
|
| - return true;
|
| - default:
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -
|
| -template <class Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseArrowFunctionLiteral(
|
| - bool accept_IN, const FormalParametersT& formal_parameters,
|
| - const ExpressionClassifier& formals_classifier, bool* ok) {
|
| - if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
| - // ASI inserts `;` after arrow parameters if a line terminator is found.
|
| - // `=> ...` is never a valid expression, so report as syntax error.
|
| - // If next token is not `=>`, it's a syntax error anyways.
|
| - ReportUnexpectedTokenAt(scanner_->peek_location(), Token::ARROW);
|
| - *ok = false;
|
| - return this->EmptyExpression();
|
| - }
|
| -
|
| - typename Traits::Type::StatementList body;
|
| - int num_parameters = formal_parameters.scope->num_parameters();
|
| - int materialized_literal_count = -1;
|
| - int expected_property_count = -1;
|
| - Scanner::Location super_loc;
|
| -
|
| - {
|
| - typename Traits::Type::Factory function_factory(ast_value_factory());
|
| - FunctionState function_state(&function_state_, &scope_,
|
| - formal_parameters.scope, kArrowFunction,
|
| - &function_factory);
|
| -
|
| - function_state.SkipMaterializedLiterals(
|
| - formal_parameters.materialized_literals_count);
|
| -
|
| - this->ReindexLiterals(formal_parameters);
|
| -
|
| - Expect(Token::ARROW, CHECK_OK);
|
| -
|
| - if (peek() == Token::LBRACE) {
|
| - // Multiple statement body
|
| - Consume(Token::LBRACE);
|
| - bool is_lazily_parsed =
|
| - (mode() == PARSE_LAZILY && scope_->AllowsLazyCompilation());
|
| - if (is_lazily_parsed) {
|
| - body = this->NewStatementList(0, zone());
|
| - this->SkipLazyFunctionBody(&materialized_literal_count,
|
| - &expected_property_count, CHECK_OK);
|
| -
|
| - if (formal_parameters.materialized_literals_count > 0) {
|
| - materialized_literal_count +=
|
| - formal_parameters.materialized_literals_count;
|
| - }
|
| - } else {
|
| - body = this->ParseEagerFunctionBody(
|
| - this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
|
| - kArrowFunction, FunctionLiteral::ANONYMOUS_EXPRESSION, CHECK_OK);
|
| - materialized_literal_count =
|
| - function_state.materialized_literal_count();
|
| - expected_property_count = function_state.expected_property_count();
|
| - }
|
| - } else {
|
| - // Single-expression body
|
| - int pos = position();
|
| - parenthesized_function_ = false;
|
| - ExpressionClassifier classifier;
|
| - ExpressionT expression =
|
| - ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
|
| - ValidateExpression(&classifier, CHECK_OK);
|
| - body = this->NewStatementList(1, zone());
|
| - this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
|
| - body->Add(factory()->NewReturnStatement(expression, pos), zone());
|
| - materialized_literal_count = function_state.materialized_literal_count();
|
| - expected_property_count = function_state.expected_property_count();
|
| - }
|
| - super_loc = function_state.super_location();
|
| -
|
| - formal_parameters.scope->set_end_position(scanner()->location().end_pos);
|
| -
|
| - // 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 allow_duplicate_parameters = false;
|
| - this->ValidateFormalParameters(&formals_classifier, language_mode(),
|
| - allow_duplicate_parameters, CHECK_OK);
|
| -
|
| - // Validate strict mode.
|
| - if (is_strict(language_mode())) {
|
| - CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
|
| - scanner()->location().end_pos, CHECK_OK);
|
| - }
|
| - if (is_strict(language_mode()) || allow_harmony_sloppy()) {
|
| - this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
|
| - }
|
| -
|
| - Traits::RewriteDestructuringAssignments();
|
| - }
|
| -
|
| - FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
|
| - this->EmptyIdentifierString(), ast_value_factory(),
|
| - formal_parameters.scope, body, materialized_literal_count,
|
| - expected_property_count, num_parameters,
|
| - FunctionLiteral::kNoDuplicateParameters,
|
| - FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
|
| - FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
|
| - formal_parameters.scope->start_position());
|
| -
|
| - function_literal->set_function_token_position(
|
| - formal_parameters.scope->start_position());
|
| - if (super_loc.IsValid()) function_state_->set_super_location(super_loc);
|
| -
|
| - if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
|
| -
|
| - return function_literal;
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start,
|
| - ExpressionClassifier* classifier,
|
| - bool* ok) {
|
| - // A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal
|
| - // text followed by a substitution expression), finalized by a single
|
| - // TEMPLATE_TAIL.
|
| - //
|
| - // In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or
|
| - // TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or
|
| - // NoSubstitutionTemplate.
|
| - //
|
| - // When parsing a TemplateLiteral, we must have scanned either an initial
|
| - // TEMPLATE_SPAN, or a TEMPLATE_TAIL.
|
| - CHECK(peek() == Token::TEMPLATE_SPAN || peek() == Token::TEMPLATE_TAIL);
|
| -
|
| - // If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate.
|
| - // In this case we may simply consume the token and build a template with a
|
| - // single TEMPLATE_SPAN and no expressions.
|
| - if (peek() == Token::TEMPLATE_TAIL) {
|
| - Consume(Token::TEMPLATE_TAIL);
|
| - int pos = position();
|
| - CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
| - typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
|
| - Traits::AddTemplateSpan(&ts, true);
|
| - return Traits::CloseTemplateLiteral(&ts, start, tag);
|
| - }
|
| -
|
| - Consume(Token::TEMPLATE_SPAN);
|
| - int pos = position();
|
| - typename Traits::TemplateLiteralState ts = Traits::OpenTemplateLiteral(pos);
|
| - Traits::AddTemplateSpan(&ts, false);
|
| - Token::Value next;
|
| -
|
| - // If we open with a TEMPLATE_SPAN, we must scan the subsequent expression,
|
| - // and repeat if the following token is a TEMPLATE_SPAN as well (in this
|
| - // case, representing a TemplateMiddle).
|
| -
|
| - do {
|
| - CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
| - next = peek();
|
| - if (next == Token::EOS) {
|
| - ReportMessageAt(Scanner::Location(start, peek_position()),
|
| - MessageTemplate::kUnterminatedTemplate);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - } else if (next == Token::ILLEGAL) {
|
| - Traits::ReportMessageAt(
|
| - Scanner::Location(position() + 1, peek_position()),
|
| - MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - }
|
| -
|
| - int expr_pos = peek_position();
|
| - ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
|
| - Traits::AddTemplateExpression(&ts, expression);
|
| -
|
| - if (peek() != Token::RBRACE) {
|
| - ReportMessageAt(Scanner::Location(expr_pos, peek_position()),
|
| - MessageTemplate::kUnterminatedTemplateExpr);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - }
|
| -
|
| - // If we didn't die parsing that expression, our next token should be a
|
| - // TEMPLATE_SPAN or TEMPLATE_TAIL.
|
| - next = scanner()->ScanTemplateContinuation();
|
| - Next();
|
| - pos = position();
|
| -
|
| - if (next == Token::EOS) {
|
| - ReportMessageAt(Scanner::Location(start, pos),
|
| - MessageTemplate::kUnterminatedTemplate);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - } else if (next == Token::ILLEGAL) {
|
| - Traits::ReportMessageAt(
|
| - Scanner::Location(position() + 1, peek_position()),
|
| - MessageTemplate::kUnexpectedToken, "ILLEGAL", kSyntaxError);
|
| - *ok = false;
|
| - return Traits::EmptyExpression();
|
| - }
|
| -
|
| - Traits::AddTemplateSpan(&ts, next == Token::TEMPLATE_TAIL);
|
| - } while (next == Token::TEMPLATE_SPAN);
|
| -
|
| - DCHECK_EQ(next, Token::TEMPLATE_TAIL);
|
| - CheckTemplateOctalLiteral(pos, peek_position(), CHECK_OK);
|
| - // Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
| - return Traits::CloseTemplateLiteral(&ts, start, tag);
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::CheckAndRewriteReferenceExpression(
|
| - ExpressionT expression, int beg_pos, int end_pos,
|
| - MessageTemplate::Template message, bool* ok) {
|
| - return this->CheckAndRewriteReferenceExpression(expression, beg_pos, end_pos,
|
| - message, kReferenceError, ok);
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::CheckAndRewriteReferenceExpression(
|
| - ExpressionT expression, int beg_pos, int end_pos,
|
| - MessageTemplate::Template message, ParseErrorType type, bool* ok) {
|
| - ExpressionClassifier classifier;
|
| - ExpressionT result = ClassifyAndRewriteReferenceExpression(
|
| - &classifier, expression, beg_pos, end_pos, message, type);
|
| - ValidateExpression(&classifier, ok);
|
| - if (!*ok) return this->EmptyExpression();
|
| - return result;
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -typename ParserBase<Traits>::ExpressionT
|
| -ParserBase<Traits>::ClassifyAndRewriteReferenceExpression(
|
| - ExpressionClassifier* classifier, ExpressionT expression, int beg_pos,
|
| - int end_pos, MessageTemplate::Template message, ParseErrorType type) {
|
| - Scanner::Location location(beg_pos, end_pos);
|
| - if (this->IsIdentifier(expression)) {
|
| - if (is_strict(language_mode()) &&
|
| - this->IsEvalOrArguments(this->AsIdentifier(expression))) {
|
| - classifier->RecordExpressionError(
|
| - location, MessageTemplate::kStrictEvalArguments, kSyntaxError);
|
| - return expression;
|
| - }
|
| - if (is_strong(language_mode()) &&
|
| - this->IsUndefined(this->AsIdentifier(expression))) {
|
| - classifier->RecordExpressionError(
|
| - location, MessageTemplate::kStrongUndefined, kSyntaxError);
|
| - return expression;
|
| - }
|
| - }
|
| - if (expression->IsValidReferenceExpression()) {
|
| - return expression;
|
| - } else if (expression->IsCall()) {
|
| - // If it is a call, make it a runtime error for legacy web compatibility.
|
| - // Rewrite `expr' to `expr[throw ReferenceError]'.
|
| - int pos = location.beg_pos;
|
| - ExpressionT error = this->NewThrowReferenceError(message, pos);
|
| - return factory()->NewProperty(expression, error, pos);
|
| - } else {
|
| - classifier->RecordExpressionError(location, message, type);
|
| - return expression;
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -bool ParserBase<Traits>::IsValidReferenceExpression(ExpressionT expression) {
|
| - return this->IsAssignableIdentifier(expression) || expression->IsProperty();
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -void ParserBase<Traits>::CheckDestructuringElement(
|
| - ExpressionT expression, ExpressionClassifier* classifier, int begin,
|
| - int end) {
|
| - static const MessageTemplate::Template message =
|
| - MessageTemplate::kInvalidDestructuringTarget;
|
| - if (!this->IsAssignableIdentifier(expression)) {
|
| - const Scanner::Location location(begin, end);
|
| - classifier->RecordBindingPatternError(location, message);
|
| - if (!expression->IsProperty() &&
|
| - !(expression->IsObjectLiteral() || expression->IsArrayLiteral())) {
|
| - classifier->RecordAssignmentPatternError(location, message);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -#undef CHECK_OK
|
| -#undef CHECK_OK_CUSTOM
|
| -
|
| -
|
| -template <typename Traits>
|
| -void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
| - Token::Value property, PropertyKind type, bool is_static, bool is_generator,
|
| - bool* ok) {
|
| - DCHECK(!is_static);
|
| - DCHECK(!is_generator || type == kMethodProperty);
|
| -
|
| - if (property == Token::SMI || property == Token::NUMBER) return;
|
| -
|
| - if (type == kValueProperty && IsProto()) {
|
| - if (has_seen_proto_) {
|
| - this->parser()->ReportMessage(MessageTemplate::kDuplicateProto);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - has_seen_proto_ = true;
|
| - return;
|
| - }
|
| -}
|
| -
|
| -
|
| -template <typename Traits>
|
| -void ParserBase<Traits>::ClassLiteralChecker::CheckProperty(
|
| - Token::Value property, PropertyKind type, bool is_static, bool is_generator,
|
| - bool* ok) {
|
| - DCHECK(type == kMethodProperty || type == kAccessorProperty);
|
| -
|
| - if (property == Token::SMI || property == Token::NUMBER) return;
|
| -
|
| - if (is_static) {
|
| - if (IsPrototype()) {
|
| - this->parser()->ReportMessage(MessageTemplate::kStaticPrototype);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - } else if (IsConstructor()) {
|
| - if (is_generator || type == kAccessorProperty) {
|
| - MessageTemplate::Template msg =
|
| - is_generator ? MessageTemplate::kConstructorIsGenerator
|
| - : MessageTemplate::kConstructorIsAccessor;
|
| - this->parser()->ReportMessage(msg);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - if (has_seen_constructor_) {
|
| - this->parser()->ReportMessage(MessageTemplate::kDuplicateConstructor);
|
| - *ok = false;
|
| - return;
|
| - }
|
| - has_seen_constructor_ = true;
|
| - return;
|
| - }
|
| -}
|
| } // namespace internal
|
| } // namespace v8
|
|
|
|
|