Parse 'super' keyword.
authordslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 12:35:34 +0000 (12:35 +0000)
committerdslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 12:35:34 +0000 (12:35 +0000)
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

17 files changed:
src/ast.cc
src/ast.h
src/compiler/ast-graph-builder.cc
src/flag-definitions.h
src/full-codegen.cc
src/hydrogen.cc
src/messages.js
src/objects.h
src/parser.cc
src/parser.h
src/preparser.h
src/prettyprinter.cc
src/scanner.cc
src/scanner.h
src/token.h
src/typing.cc
test/cctest/test-parsing.cc

index 9f43160..d08ad1c 100644 (file)
@@ -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)
 
index e18fdc7..2b4d0f1 100644 (file)
--- 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:
index 49a6715..e7e8828 100644 (file)
@@ -1540,6 +1540,11 @@ void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
+  UNREACHABLE();
+}
+
+
 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
 
 
index 55af2e6..16fe48a 100644 (file)
@@ -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)
index 0297f88..22a6306 100644 (file)
@@ -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());
index 957f247..619b7e5 100644 (file)
@@ -11185,6 +11185,11 @@ void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) {
+  UNREACHABLE();
+}
+
+
 void HOptimizedGraphBuilder::VisitDeclarations(
     ZoneList<Declaration*>* declarations) {
   DCHECK(globals_.is_empty());
index eba1e16..d98fe48 100644 (file)
@@ -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"]
 };
 
 
index 2f52094..b214a37 100644 (file)
@@ -1022,7 +1022,7 @@ template <class C> 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 <class C> 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 <class C> 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 <class C> 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 <class C> 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")                                              \
index 6c941da..e2677b5 100644 (file)
@@ -619,6 +619,12 @@ Expression* ParserTraits::ThisExpression(
   return factory->NewVariableProxy(scope->receiver(), pos);
 }
 
+Expression* ParserTraits::SuperReference(
+    Scope* scope, AstNodeFactory<AstConstructionVisitor>* 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;
index e3cee84..93af699 100644 (file)
@@ -549,6 +549,9 @@ class ParserTraits {
   Expression* ThisExpression(Scope* scope,
                              AstNodeFactory<AstConstructionVisitor>* factory,
                              int pos = RelocInfo::kNoPosition);
+  Expression* SuperReference(Scope* scope,
+                             AstNodeFactory<AstConstructionVisitor>* factory,
+                             int pos = RelocInfo::kNoPosition);
   Literal* ExpressionFromLiteral(
       Token::Value token, int pos, Scanner* scanner,
       AstNodeFactory<AstConstructionVisitor>* factory);
index 8a93258..7609a3a 100644 (file)
@@ -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<Traits>::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<Traits>::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<Traits>::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);
   }
index 19b0290..0f5d225 100644 (file)
@@ -447,6 +447,11 @@ void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
 }
 
 
+void PrettyPrinter::VisitSuperReference(SuperReference* node) {
+  Print("<super-reference>");
+}
+
+
 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
index 2e8e24b..195287f 100644 (file)
@@ -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;
index d3a6c6b..b958fd4 100644 (file)
@@ -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
index 3535e34..fe95412 100644 (file)
@@ -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)                                           \
index 136f722..ee473ed 100644 (file)
@@ -723,6 +723,9 @@ void AstTyper::VisitThisFunction(ThisFunction* expr) {
 }
 
 
+void AstTyper::VisitSuperReference(SuperReference* expr) {}
+
+
 void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
   for (int i = 0; i < decls->length(); ++i) {
     Declaration* decl = decls->at(i);
index 9cb5d69..b905afb 100644 (file)
@@ -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<Traits>* 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));
+}