From 65ae6e92abc42bb86017d680803c6180e033c39b Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Mon, 18 Aug 2014 12:35:34 +0000 Subject: [PATCH] Parse 'super' keyword. BUG=v8:3330 LOG=N R=arv@chromium.org, marja@chromium.org Review URL: https://codereview.chromium.org/480543002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23157 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/ast.cc | 1 + src/ast.h | 29 ++++++++ src/compiler/ast-graph-builder.cc | 5 ++ src/flag-definitions.h | 2 + src/full-codegen.cc | 9 +++ src/hydrogen.cc | 5 ++ src/messages.js | 3 +- src/objects.h | 41 ++++------- src/parser.cc | 7 ++ src/parser.h | 3 + src/preparser.h | 38 ++++++++++- src/prettyprinter.cc | 10 +++ src/scanner.cc | 139 ++++++++++++++++++++------------------ src/scanner.h | 8 +++ src/token.h | 1 + src/typing.cc | 3 + test/cctest/test-parsing.cc | 52 +++++++++++++- 17 files changed, 257 insertions(+), 99 deletions(-) diff --git a/src/ast.cc b/src/ast.cc index 9f43160..d08ad1c 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -1097,6 +1097,7 @@ DONT_OPTIMIZE_NODE(TryCatchStatement) DONT_OPTIMIZE_NODE(TryFinallyStatement) DONT_OPTIMIZE_NODE(DebuggerStatement) DONT_OPTIMIZE_NODE(NativeFunctionLiteral) +DONT_OPTIMIZE_NODE(SuperReference) DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(Yield) diff --git a/src/ast.h b/src/ast.h index e18fdc7..2b4d0f1 100644 --- a/src/ast.h +++ b/src/ast.h @@ -94,6 +94,7 @@ namespace internal { V(BinaryOperation) \ V(CompareOperation) \ V(ThisFunction) \ + V(SuperReference) \ V(CaseClause) #define AST_NODE_LIST(V) \ @@ -1710,6 +1711,10 @@ class Property V8_FINAL : public Expression, public FeedbackSlotInterface { void mark_for_call() { is_for_call_ = true; } bool IsForCall() { return is_for_call_; } + bool IsSuperAccess() { + return obj()->IsSuperReference(); + } + TypeFeedbackId PropertyFeedbackId() { return reuse(id()); } virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; } @@ -2554,6 +2559,25 @@ class ThisFunction V8_FINAL : public Expression { explicit ThisFunction(Zone* zone, int pos): Expression(zone, pos) {} }; + +class SuperReference V8_FINAL : public Expression { + public: + DECLARE_NODE_TYPE(SuperReference) + + VariableProxy* this_var() const { return this_var_; } + + TypeFeedbackId HomeObjectFeedbackId() { return reuse(id()); } + + protected: + explicit SuperReference(Zone* zone, VariableProxy* this_var, int pos) + : Expression(zone, pos), this_var_(this_var) { + DCHECK(this_var->is_this()); + } + + VariableProxy* this_var_; +}; + + #undef DECLARE_NODE_TYPE @@ -3472,6 +3496,11 @@ class AstNodeFactory V8_FINAL BASE_EMBEDDED { VISIT_AND_RETURN(ThisFunction, fun) } + SuperReference* NewSuperReference(VariableProxy* this_var, int pos) { + SuperReference* super = new (zone_) SuperReference(zone_, this_var, pos); + VISIT_AND_RETURN(SuperReference, super); + } + #undef VISIT_AND_RETURN private: diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 49a6715..e7e8828 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -1540,6 +1540,11 @@ void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { } +void AstGraphBuilder::VisitSuperReference(SuperReference* expr) { + UNREACHABLE(); +} + + void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 55af2e6..16fe48a 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -160,6 +160,7 @@ DEFINE_BOOL(harmony_numeric_literals, false, DEFINE_BOOL(harmony_strings, false, "enable harmony string") DEFINE_BOOL(harmony_arrays, false, "enable harmony arrays") DEFINE_BOOL(harmony_arrow_functions, false, "enable harmony arrow functions") +DEFINE_BOOL(harmony_classes, false, "enable harmony classes") DEFINE_BOOL(harmony, false, "enable all harmony features (except proxies)") DEFINE_IMPLICATION(harmony, harmony_scoping) @@ -171,6 +172,7 @@ DEFINE_IMPLICATION(harmony, harmony_numeric_literals) DEFINE_IMPLICATION(harmony, harmony_strings) DEFINE_IMPLICATION(harmony, harmony_arrays) DEFINE_IMPLICATION(harmony, harmony_arrow_functions) +DEFINE_IMPLICATION(harmony, harmony_classes) DEFINE_IMPLICATION(harmony_modules, harmony_scoping) DEFINE_IMPLICATION(harmony, es_staging) diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 0297f88..22a6306 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -285,6 +285,9 @@ void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) { } +void BreakableStatementChecker::VisitSuperReference(SuperReference* expr) {} + + #define __ ACCESS_MASM(masm()) bool FullCodeGenerator::MakeCode(CompilationInfo* info) { @@ -819,6 +822,12 @@ void FullCodeGenerator::SetStatementPosition(Statement* stmt) { } +void FullCodeGenerator::VisitSuperReference(SuperReference* super) { + DCHECK(FLAG_harmony_classes); + UNIMPLEMENTED(); +} + + void FullCodeGenerator::SetExpressionPosition(Expression* expr) { if (!info_->is_debug()) { CodeGenerator::RecordPositions(masm_, expr->position()); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 957f247..619b7e5 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -11185,6 +11185,11 @@ void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) { } +void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) { + UNREACHABLE(); +} + + void HOptimizedGraphBuilder::VisitDeclarations( ZoneList* declarations) { DCHECK(globals_.is_empty()); diff --git a/src/messages.js b/src/messages.js index eba1e16..d98fe48 100644 --- a/src/messages.js +++ b/src/messages.js @@ -167,7 +167,8 @@ var kMessages = { symbol_to_number: ["Cannot convert a Symbol value to a number"], invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"], module_type_error: ["Module '", "%0", "' used improperly"], - module_export_undefined: ["Export '", "%0", "' is not defined in module"] + module_export_undefined: ["Export '", "%0", "' is not defined in module"], + unexpected_super: ["'super' keyword unexpected here"] }; diff --git a/src/objects.h b/src/objects.h index 2f52094..b214a37 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1022,7 +1022,7 @@ template inline bool Is(Object* obj); V(OrderedHashTable) -#define ERROR_MESSAGES_LIST(V) \ +#define ERROR_MESSAGES_LIST(V) \ V(kNoReason, "no reason") \ \ V(k32BitValueInRegisterIsNotZeroExtended, \ @@ -1089,24 +1089,17 @@ template inline bool Is(Object* obj); V(kExpectedNonIdenticalObjects, "Expected non-identical objects") \ V(kExpectedNonNullContext, "Expected non-null context") \ V(kExpectedPositiveZero, "Expected +0.0") \ - V(kExpectedAllocationSiteInCell, \ - "Expected AllocationSite in property cell") \ + V(kExpectedAllocationSiteInCell, "Expected AllocationSite in property cell")\ V(kExpectedFixedArrayInFeedbackVector, \ "Expected fixed array in feedback vector") \ - V(kExpectedFixedArrayInRegisterA2, \ - "Expected fixed array in register a2") \ - V(kExpectedFixedArrayInRegisterEbx, \ - "Expected fixed array in register ebx") \ - V(kExpectedFixedArrayInRegisterR2, \ - "Expected fixed array in register r2") \ - V(kExpectedFixedArrayInRegisterRbx, \ - "Expected fixed array in register rbx") \ + V(kExpectedFixedArrayInRegisterA2, "Expected fixed array in register a2") \ + V(kExpectedFixedArrayInRegisterEbx, "Expected fixed array in register ebx") \ + V(kExpectedFixedArrayInRegisterR2, "Expected fixed array in register r2") \ + V(kExpectedFixedArrayInRegisterRbx, "Expected fixed array in register rbx") \ V(kExpectedNewSpaceObject, "Expected new space object") \ V(kExpectedSmiOrHeapNumber, "Expected smi or HeapNumber") \ - V(kExpectedUndefinedOrCell, \ - "Expected undefined or cell in register") \ - V(kExpectingAlignmentForCopyBytes, \ - "Expecting alignment for CopyBytes") \ + V(kExpectedUndefinedOrCell, "Expected undefined or cell in register") \ + V(kExpectingAlignmentForCopyBytes, "Expecting alignment for CopyBytes") \ V(kExportDeclaration, "Export declaration") \ V(kExternalStringExpectedButNotFound, \ "External string expected, but not found") \ @@ -1179,8 +1172,7 @@ template inline bool Is(Object* obj); V(kLhsHasBeenClobbered, "lhs has been clobbered") \ V(kLiveBytesCountOverflowChunkSize, "Live Bytes Count overflow chunk size") \ V(kLiveEdit, "LiveEdit") \ - V(kLookupVariableInCountOperation, \ - "Lookup variable in count operation") \ + V(kLookupVariableInCountOperation, "Lookup variable in count operation") \ V(kMapBecameDeprecated, "Map became deprecated") \ V(kMapBecameUnstable, "Map became unstable") \ V(kMapIsNoLongerInEax, "Map is no longer in eax") \ @@ -1191,25 +1183,23 @@ template inline bool Is(Object* obj); V(kModuleVariable, "Module variable") \ V(kModuleUrl, "Module url") \ V(kNativeFunctionLiteral, "Native function literal") \ + V(kSuperReference, "Super reference") \ V(kNeedSmiLiteral, "Need a Smi literal here") \ V(kNoCasesLeft, "No cases left") \ V(kNoEmptyArraysHereInEmitFastAsciiArrayJoin, \ "No empty arrays here in EmitFastAsciiArrayJoin") \ - V(kNonInitializerAssignmentToConst, \ - "Non-initializer assignment to const") \ + V(kNonInitializerAssignmentToConst, "Non-initializer assignment to const") \ V(kNonSmiIndex, "Non-smi index") \ V(kNonSmiKeyInArrayLiteral, "Non-smi key in array literal") \ V(kNonSmiValue, "Non-smi value") \ V(kNonObject, "Non-object value") \ V(kNotEnoughVirtualRegistersForValues, \ "Not enough virtual registers for values") \ - V(kNotEnoughSpillSlotsForOsr, \ - "Not enough spill slots for OSR") \ + V(kNotEnoughSpillSlotsForOsr, "Not enough spill slots for OSR") \ V(kNotEnoughVirtualRegistersRegalloc, \ "Not enough virtual registers (regalloc)") \ V(kObjectFoundInSmiOnlyArray, "Object found in smi-only array") \ - V(kObjectLiteralWithComplexProperty, \ - "Object literal with complex property") \ + V(kObjectLiteralWithComplexProperty, "Object literal with complex property")\ V(kOddballInStringTableIsNotUndefinedOrTheHole, \ "Oddball in string table is not undefined or the hole") \ V(kOffsetOutOfRange, "Offset out of range") \ @@ -1235,12 +1225,11 @@ template inline bool Is(Object* obj); V(kReceivedInvalidReturnAddress, "Received invalid return address") \ V(kReferenceToAVariableWhichRequiresDynamicLookup, \ "Reference to a variable which requires dynamic lookup") \ - V(kReferenceToGlobalLexicalVariable, \ - "Reference to global lexical variable") \ + V(kReferenceToGlobalLexicalVariable, "Reference to global lexical variable")\ V(kReferenceToUninitializedVariable, "Reference to uninitialized variable") \ V(kRegisterDidNotMatchExpectedRoot, "Register did not match expected root") \ V(kRegisterWasClobbered, "Register was clobbered") \ - V(kRememberedSetPointerInNewSpace, "Remembered set pointer is in new space") \ + V(kRememberedSetPointerInNewSpace, "Remembered set pointer is in new space")\ V(kReturnAddressNotFoundInFrame, "Return address not found in frame") \ V(kRhsHasBeenClobbered, "Rhs has been clobbered") \ V(kScopedBlock, "ScopedBlock") \ diff --git a/src/parser.cc b/src/parser.cc index 6c941da..e2677b5 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -619,6 +619,12 @@ Expression* ParserTraits::ThisExpression( return factory->NewVariableProxy(scope->receiver(), pos); } +Expression* ParserTraits::SuperReference( + Scope* scope, AstNodeFactory* factory, int pos) { + return factory->NewSuperReference( + ThisExpression(scope, factory, pos)->AsVariableProxy(), + pos); +} Literal* ParserTraits::ExpressionFromLiteral( Token::Value token, int pos, @@ -731,6 +737,7 @@ Parser::Parser(CompilationInfo* info) set_allow_generators(FLAG_harmony_generators); set_allow_arrow_functions(FLAG_harmony_arrow_functions); set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); + set_allow_classes(FLAG_harmony_classes); for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; ++feature) { use_counts_[feature] = 0; diff --git a/src/parser.h b/src/parser.h index e3cee84..93af699 100644 --- a/src/parser.h +++ b/src/parser.h @@ -549,6 +549,9 @@ class ParserTraits { Expression* ThisExpression(Scope* scope, AstNodeFactory* factory, int pos = RelocInfo::kNoPosition); + Expression* SuperReference(Scope* scope, + AstNodeFactory* factory, + int pos = RelocInfo::kNoPosition); Literal* ExpressionFromLiteral( Token::Value token, int pos, Scanner* scanner, AstNodeFactory* factory); diff --git a/src/preparser.h b/src/preparser.h index 8a93258..7609a3a 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -95,6 +95,7 @@ class ParserBase : public Traits { bool allow_harmony_numeric_literals() const { return scanner()->HarmonyNumericLiterals(); } + bool allow_classes() const { return scanner()->HarmonyClasses(); } // Setters that determine whether certain syntactical constructs are // allowed to be parsed by this instance of the parser. @@ -109,6 +110,9 @@ class ParserBase : public Traits { void set_allow_harmony_numeric_literals(bool allow) { scanner()->SetHarmonyNumericLiterals(allow); } + void set_allow_classes(bool allow) { + scanner()->SetHarmonyClasses(allow); + } protected: friend class Traits::Type::Checkpoint; @@ -677,6 +681,10 @@ class PreParserExpression { return PreParserExpression(kThisExpression); } + static PreParserExpression Super() { + return PreParserExpression(kSuperExpression); + } + static PreParserExpression ThisProperty() { return PreParserExpression(kThisPropertyExpression); } @@ -798,7 +806,8 @@ class PreParserExpression { kThisExpression = (1 << 4), kThisPropertyExpression = (2 << 4), kPropertyExpression = (3 << 4), - kCallExpression = (4 << 4) + kCallExpression = (4 << 4), + kSuperExpression = (5 << 4) }; explicit PreParserExpression(int expression_code) : code_(expression_code) {} @@ -1248,6 +1257,11 @@ class PreParserTraits { return PreParserExpression::This(); } + static PreParserExpression SuperReference(PreParserScope* scope, + PreParserFactory* factory) { + return PreParserExpression::Super(); + } + static PreParserExpression ExpressionFromLiteral( Token::Value token, int pos, Scanner* scanner, PreParserFactory* factory) { @@ -2383,7 +2397,12 @@ ParserBase::ParseMemberWithNewPrefixesExpression(bool* ok) { if (peek() == Token::NEW) { Consume(Token::NEW); int new_pos = position(); - ExpressionT result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK); + ExpressionT result = this->EmptyExpression(); + if (Check(Token::SUPER)) { + result = this->SuperReference(scope_, factory()); + } else { + result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK); + } if (peek() == Token::LPAREN) { // NewExpression with arguments. typename Traits::Type::ExpressionList args = @@ -2397,7 +2416,7 @@ ParserBase::ParseMemberWithNewPrefixesExpression(bool* ok) { return factory()->NewCallNew(result, this->NewExpressionList(0, zone_), new_pos); } - // No 'new' keyword. + // No 'new' or 'super' keyword. return this->ParseMemberExpression(ok); } @@ -2438,6 +2457,19 @@ ParserBase::ParseMemberExpression(bool* ok) { function_type, FunctionLiteral::NORMAL_ARITY, CHECK_OK); + } else if (peek() == Token::SUPER) { + int beg_pos = position(); + Consume(Token::SUPER); + Token::Value next = peek(); + if (next == Token::PERIOD || next == Token::LBRACK || + next == Token::LPAREN) { + result = this->SuperReference(scope_, factory()); + } else { + ReportMessageAt(Scanner::Location(beg_pos, position()), + "unexpected_super"); + *ok = false; + return this->EmptyExpression(); + } } else { result = ParsePrimaryExpression(CHECK_OK); } diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc index 19b0290..0f5d225 100644 --- a/src/prettyprinter.cc +++ b/src/prettyprinter.cc @@ -447,6 +447,11 @@ void PrettyPrinter::VisitThisFunction(ThisFunction* node) { } +void PrettyPrinter::VisitSuperReference(SuperReference* node) { + Print(""); +} + + const char* PrettyPrinter::Print(AstNode* node) { Init(); Visit(node); @@ -1145,6 +1150,11 @@ void AstPrinter::VisitThisFunction(ThisFunction* node) { IndentedScope indent(this, "THIS-FUNCTION"); } + +void AstPrinter::VisitSuperReference(SuperReference* node) { + IndentedScope indent(this, "SUPER-REFERENCE"); +} + #endif // DEBUG } } // namespace v8::internal diff --git a/src/scanner.cc b/src/scanner.cc index 2e8e24b..195287f 100644 --- a/src/scanner.cc +++ b/src/scanner.cc @@ -36,7 +36,8 @@ Scanner::Scanner(UnicodeCache* unicode_cache) octal_pos_(Location::invalid()), harmony_scoping_(false), harmony_modules_(false), - harmony_numeric_literals_(false) { } + harmony_numeric_literals_(false), + harmony_classes_(false) { } void Scanner::Initialize(Utf16CharacterStream* source) { @@ -901,76 +902,78 @@ uc32 Scanner::ScanIdentifierUnicodeEscape() { // ---------------------------------------------------------------------------- // Keyword Matcher -#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ - KEYWORD_GROUP('b') \ - KEYWORD("break", Token::BREAK) \ - KEYWORD_GROUP('c') \ - KEYWORD("case", Token::CASE) \ - KEYWORD("catch", Token::CATCH) \ - KEYWORD("class", Token::FUTURE_RESERVED_WORD) \ - KEYWORD("const", Token::CONST) \ - KEYWORD("continue", Token::CONTINUE) \ - KEYWORD_GROUP('d') \ - KEYWORD("debugger", Token::DEBUGGER) \ - KEYWORD("default", Token::DEFAULT) \ - KEYWORD("delete", Token::DELETE) \ - KEYWORD("do", Token::DO) \ - KEYWORD_GROUP('e') \ - KEYWORD("else", Token::ELSE) \ - KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ - KEYWORD("export", harmony_modules \ - ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \ - KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \ - KEYWORD_GROUP('f') \ - KEYWORD("false", Token::FALSE_LITERAL) \ - KEYWORD("finally", Token::FINALLY) \ - KEYWORD("for", Token::FOR) \ - KEYWORD("function", Token::FUNCTION) \ - KEYWORD_GROUP('i') \ - KEYWORD("if", Token::IF) \ - KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("import", harmony_modules \ - ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \ - KEYWORD("in", Token::IN) \ - KEYWORD("instanceof", Token::INSTANCEOF) \ - KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD_GROUP('l') \ - KEYWORD("let", harmony_scoping \ - ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD_GROUP('n') \ - KEYWORD("new", Token::NEW) \ - KEYWORD("null", Token::NULL_LITERAL) \ - KEYWORD_GROUP('p') \ - KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD_GROUP('r') \ - KEYWORD("return", Token::RETURN) \ - KEYWORD_GROUP('s') \ - KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \ - KEYWORD("super", Token::FUTURE_RESERVED_WORD) \ - KEYWORD("switch", Token::SWITCH) \ - KEYWORD_GROUP('t') \ - KEYWORD("this", Token::THIS) \ - KEYWORD("throw", Token::THROW) \ - KEYWORD("true", Token::TRUE_LITERAL) \ - KEYWORD("try", Token::TRY) \ - KEYWORD("typeof", Token::TYPEOF) \ - KEYWORD_GROUP('v') \ - KEYWORD("var", Token::VAR) \ - KEYWORD("void", Token::VOID) \ - KEYWORD_GROUP('w') \ - KEYWORD("while", Token::WHILE) \ - KEYWORD("with", Token::WITH) \ - KEYWORD_GROUP('y') \ +#define KEYWORDS(KEYWORD_GROUP, KEYWORD) \ + KEYWORD_GROUP('b') \ + KEYWORD("break", Token::BREAK) \ + KEYWORD_GROUP('c') \ + KEYWORD("case", Token::CASE) \ + KEYWORD("catch", Token::CATCH) \ + KEYWORD("class", Token::FUTURE_RESERVED_WORD) \ + KEYWORD("const", Token::CONST) \ + KEYWORD("continue", Token::CONTINUE) \ + KEYWORD_GROUP('d') \ + KEYWORD("debugger", Token::DEBUGGER) \ + KEYWORD("default", Token::DEFAULT) \ + KEYWORD("delete", Token::DELETE) \ + KEYWORD("do", Token::DO) \ + KEYWORD_GROUP('e') \ + KEYWORD("else", Token::ELSE) \ + KEYWORD("enum", Token::FUTURE_RESERVED_WORD) \ + KEYWORD("export", \ + harmony_modules ? Token::EXPORT : Token::FUTURE_RESERVED_WORD) \ + KEYWORD("extends", Token::FUTURE_RESERVED_WORD) \ + KEYWORD_GROUP('f') \ + KEYWORD("false", Token::FALSE_LITERAL) \ + KEYWORD("finally", Token::FINALLY) \ + KEYWORD("for", Token::FOR) \ + KEYWORD("function", Token::FUNCTION) \ + KEYWORD_GROUP('i') \ + KEYWORD("if", Token::IF) \ + KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("import", \ + harmony_modules ? Token::IMPORT : Token::FUTURE_RESERVED_WORD) \ + KEYWORD("in", Token::IN) \ + KEYWORD("instanceof", Token::INSTANCEOF) \ + KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('l') \ + KEYWORD("let", \ + harmony_scoping ? Token::LET : Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('n') \ + KEYWORD("new", Token::NEW) \ + KEYWORD("null", Token::NULL_LITERAL) \ + KEYWORD_GROUP('p') \ + KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD_GROUP('r') \ + KEYWORD("return", Token::RETURN) \ + KEYWORD_GROUP('s') \ + KEYWORD("static", Token::FUTURE_STRICT_RESERVED_WORD) \ + KEYWORD("super", \ + harmony_classes ? Token::SUPER : Token::FUTURE_RESERVED_WORD) \ + KEYWORD("switch", Token::SWITCH) \ + KEYWORD_GROUP('t') \ + KEYWORD("this", Token::THIS) \ + KEYWORD("throw", Token::THROW) \ + KEYWORD("true", Token::TRUE_LITERAL) \ + KEYWORD("try", Token::TRY) \ + KEYWORD("typeof", Token::TYPEOF) \ + KEYWORD_GROUP('v') \ + KEYWORD("var", Token::VAR) \ + KEYWORD("void", Token::VOID) \ + KEYWORD_GROUP('w') \ + KEYWORD("while", Token::WHILE) \ + KEYWORD("with", Token::WITH) \ + KEYWORD_GROUP('y') \ KEYWORD("yield", Token::YIELD) static Token::Value KeywordOrIdentifierToken(const uint8_t* input, int input_length, bool harmony_scoping, - bool harmony_modules) { + bool harmony_modules, + bool harmony_classes) { DCHECK(input_length >= 1); const int kMinLength = 2; const int kMaxLength = 10; @@ -1014,7 +1017,8 @@ bool Scanner::IdentifierIsFutureStrictReserved( return string->is_one_byte() && Token::FUTURE_STRICT_RESERVED_WORD == KeywordOrIdentifierToken(string->raw_data(), string->length(), - harmony_scoping_, harmony_modules_); + harmony_scoping_, harmony_modules_, + harmony_classes_); } @@ -1057,7 +1061,8 @@ Token::Value Scanner::ScanIdentifierOrKeyword() { return KeywordOrIdentifierToken(chars.start(), chars.length(), harmony_scoping_, - harmony_modules_); + harmony_modules_, + harmony_classes_); } return Token::IDENTIFIER; diff --git a/src/scanner.h b/src/scanner.h index d3a6c6b..b958fd4 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -438,6 +438,12 @@ class Scanner { void SetHarmonyNumericLiterals(bool numeric_literals) { harmony_numeric_literals_ = numeric_literals; } + bool HarmonyClasses() const { + return harmony_classes_; + } + void SetHarmonyClasses(bool classes) { + harmony_classes_ = classes; + } // Returns true if there was a line terminator before the peek'ed token, // possibly inside a multi-line comment. @@ -647,6 +653,8 @@ class Scanner { bool harmony_modules_; // Whether we scan 0o777 and 0b111 as numbers. bool harmony_numeric_literals_; + // Whether we scan 'super' as keyword. + bool harmony_classes_; }; } } // namespace v8::internal diff --git a/src/token.h b/src/token.h index 3535e34..fe95412 100644 --- a/src/token.h +++ b/src/token.h @@ -153,6 +153,7 @@ namespace internal { K(IMPORT, "import", 0) \ K(LET, "let", 0) \ K(YIELD, "yield", 0) \ + K(SUPER, "super", 0) \ \ /* Illegal token - not able to scan. */ \ T(ILLEGAL, "ILLEGAL", 0) \ diff --git a/src/typing.cc b/src/typing.cc index 136f722..ee473ed 100644 --- a/src/typing.cc +++ b/src/typing.cc @@ -723,6 +723,9 @@ void AstTyper::VisitThisFunction(ThisFunction* expr) { } +void AstTyper::VisitSuperReference(SuperReference* expr) {} + + void AstTyper::VisitDeclarations(ZoneList* decls) { for (int i = 0; i < decls->length(); ++i) { Declaration* decl = decls->at(i); diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index 9cb5d69..b905afb 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -72,6 +72,7 @@ TEST(ScanKeywords) { // The scanner should parse Harmony keywords for this test. scanner.SetHarmonyScoping(true); scanner.SetHarmonyModules(true); + scanner.SetHarmonyClasses(true); scanner.Initialize(&stream); CHECK_EQ(key_token.token, scanner.Next()); CHECK_EQ(i::Token::EOS, scanner.Next()); @@ -1209,7 +1210,8 @@ enum ParserFlag { kAllowModules, kAllowGenerators, kAllowHarmonyNumericLiterals, - kAllowArrowFunctions + kAllowArrowFunctions, + kAllowClasses }; @@ -1230,6 +1232,7 @@ void SetParserFlags(i::ParserBase* parser, parser->set_allow_harmony_numeric_literals( flags.Contains(kAllowHarmonyNumericLiterals)); parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions)); + parser->set_allow_classes(flags.Contains(kAllowClasses)); } @@ -1512,7 +1515,8 @@ void RunParserSyncTest(const char* context_data[][2], static const ParserFlag default_flags[] = { kAllowLazy, kAllowHarmonyScoping, kAllowModules, - kAllowGenerators, kAllowNativesSyntax, kAllowArrowFunctions}; + kAllowGenerators, kAllowNativesSyntax, kAllowArrowFunctions, + kAllowClasses}; ParserFlag* generated_flags = NULL; if (flags == NULL) { flags = default_flags; @@ -3343,3 +3347,47 @@ TEST(NoErrorsArrowFunctions) { RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, always_flags, ARRAY_SIZE(always_flags)); } + + +TEST(NoErrorsSuper) { + // Tests that parser and preparser accept 'super' keyword in right places. + const char* context_data[][2] = {{"", ";"}, + {"k = ", ";"}, + {"foo(", ");"}, + {NULL, NULL}}; + + const char* statement_data[] = { + "super.x", + "super[27]", + "new super", + "new super()", + "new super(12, 45)", + "new new super", + "new new super()", + "new new super()()", + "z.super", // Ok, property lookup. + NULL}; + + static const ParserFlag always_flags[] = {kAllowClasses}; + RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); +} + + +TEST(ErrorsSuper) { + // Tests that parser and preparser generate same errors for 'super'. + const char* context_data[][2] = {{"", ";"}, + {"k = ", ";"}, + {"foo(", ");"}, + {NULL, NULL}}; + + const char* statement_data[] = { + "super = x", + "y = super", + "f(super)", + NULL}; + + static const ParserFlag always_flags[] = {kAllowClasses}; + RunParserSyncTest(context_data, statement_data, kError, NULL, 0, + always_flags, ARRAY_SIZE(always_flags)); +} -- 2.7.4