Traitify ParserBase and move functions there.
authormarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Feb 2014 09:35:32 +0000 (09:35 +0000)
committermarja@chromium.org <marja@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Feb 2014 09:35:32 +0000 (09:35 +0000)
(Second try, with fixes. First try: https://codereview.chromium.org/149913006/ )

The long-term goal is to move all recursive descent functions from Parser and
PreParser into ParserBase, but first they need to be unified.

Notes:
- The functions moved in this CL: ParseIdentifier, ParseIdentifierName,
ParseIdentifierNameOrGetOrSet, ParseIdentifierOrStrictReservedWord.
- IOW, this CL removes Parser::ParseIdentifier and PreParser::ParseIdentifier
and adds ParserBase::ParseIdentifier, etc.
- Error reporting used to require virtual funcs; now error reporting is moved to
the Traits too, and ParserBase no longer needs to be virtual.
- I had to move PreParser::Identifier out of the PreParser class, because
otherwise PreParserTraits cannot use it in a typedef.

BUG=v8:3126
LOG=N
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/158913003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
test/cctest/test-parsing.cc

index c1c1122..0f842ad 100644 (file)
@@ -533,8 +533,78 @@ Parser::FunctionState::~FunctionState() {
 // ----------------------------------------------------------------------------
 // Implementation of Parser
 
+bool ParserTraits::is_classic_mode() const {
+  return parser_->top_scope_->is_classic_mode();
+}
+
+
+bool ParserTraits::is_generator() const {
+  return parser_->current_function_state_->is_generator();
+}
+
+
+bool ParserTraits::IsEvalOrArguments(Handle<String> identifier) const {
+  return identifier.is_identical_to(
+             parser_->isolate()->factory()->eval_string()) ||
+         identifier.is_identical_to(
+             parser_->isolate()->factory()->arguments_string());
+}
+
+
+void ParserTraits::ReportMessageAt(Scanner::Location source_location,
+                                   const char* message,
+                                   Vector<const char*> args) {
+  MessageLocation location(parser_->script_,
+                           source_location.beg_pos,
+                           source_location.end_pos);
+  Factory* factory = parser_->isolate()->factory();
+  Handle<FixedArray> elements = factory->NewFixedArray(args.length());
+  for (int i = 0; i < args.length(); i++) {
+    Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
+    elements->set(i, *arg_string);
+  }
+  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+  Handle<Object> result = factory->NewSyntaxError(message, array);
+  parser_->isolate()->Throw(*result, &location);
+}
+
+
+void ParserTraits::ReportMessage(const char* message,
+                                 Vector<Handle<String> > args) {
+  Scanner::Location source_location = parser_->scanner().location();
+  ReportMessageAt(source_location, message, args);
+}
+
+
+void ParserTraits::ReportMessageAt(Scanner::Location source_location,
+                                   const char* message,
+                                   Vector<Handle<String> > args) {
+  MessageLocation location(parser_->script_,
+                           source_location.beg_pos,
+                           source_location.end_pos);
+  Factory* factory = parser_->isolate()->factory();
+  Handle<FixedArray> elements = factory->NewFixedArray(args.length());
+  for (int i = 0; i < args.length(); i++) {
+    elements->set(i, *args[i]);
+  }
+  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
+  Handle<Object> result = factory->NewSyntaxError(message, array);
+  parser_->isolate()->Throw(*result, &location);
+}
+
+
+Handle<String> ParserTraits::GetSymbol() {
+  int symbol_id = -1;
+  if (parser_->pre_parse_data() != NULL) {
+    symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier();
+  }
+  return parser_->LookupSymbol(symbol_id);
+}
+
 Parser::Parser(CompilationInfo* info)
-    : ParserBase(&scanner_, info->isolate()->stack_guard()->real_climit()),
+    : ParserBase<ParserTraits>(&scanner_,
+                               info->isolate()->stack_guard()->real_climit(),
+                               this),
       isolate_(info->isolate()),
       symbol_cache_(0, info->zone()),
       script_(info->script()),
@@ -794,62 +864,6 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
 }
 
 
-Handle<String> Parser::GetSymbol() {
-  int symbol_id = -1;
-  if (pre_parse_data() != NULL) {
-    symbol_id = pre_parse_data()->GetSymbolIdentifier();
-  }
-  return LookupSymbol(symbol_id);
-}
-
-
-void Parser::ReportMessage(const char* message, Vector<const char*> args) {
-  Scanner::Location source_location = scanner().location();
-  ReportMessageAt(source_location, message, args);
-}
-
-
-void Parser::ReportMessage(const char* message, Vector<Handle<String> > args) {
-  Scanner::Location source_location = scanner().location();
-  ReportMessageAt(source_location, message, args);
-}
-
-
-void Parser::ReportMessageAt(Scanner::Location source_location,
-                             const char* message,
-                             Vector<const char*> args) {
-  MessageLocation location(script_,
-                           source_location.beg_pos,
-                           source_location.end_pos);
-  Factory* factory = isolate()->factory();
-  Handle<FixedArray> elements = factory->NewFixedArray(args.length());
-  for (int i = 0; i < args.length(); i++) {
-    Handle<String> arg_string = factory->NewStringFromUtf8(CStrVector(args[i]));
-    elements->set(i, *arg_string);
-  }
-  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
-  Handle<Object> result = factory->NewSyntaxError(message, array);
-  isolate()->Throw(*result, &location);
-}
-
-
-void Parser::ReportMessageAt(Scanner::Location source_location,
-                             const char* message,
-                             Vector<Handle<String> > args) {
-  MessageLocation location(script_,
-                           source_location.beg_pos,
-                           source_location.end_pos);
-  Factory* factory = isolate()->factory();
-  Handle<FixedArray> elements = factory->NewFixedArray(args.length());
-  for (int i = 0; i < args.length(); i++) {
-    elements->set(i, *args[i]);
-  }
-  Handle<JSArray> array = factory->NewJSArrayWithElements(elements);
-  Handle<Object> result = factory->NewSyntaxError(message, array);
-  isolate()->Throw(*result, &location);
-}
-
-
 void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
                                   int end_token,
                                   bool is_eval,
@@ -1082,8 +1096,8 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
        !it.done(); it.Advance()) {
     if (scope->LocalLookup(it.name()) == NULL) {
       Handle<String> name(it.name());
-      ReportMessage("module_export_undefined",
-                    Vector<Handle<String> >(&name, 1));
+      ParserTraits::ReportMessage("module_export_undefined",
+                                  Vector<Handle<String> >(&name, 1));
       *ok = false;
       return NULL;
     }
@@ -1122,7 +1136,8 @@ Module* Parser::ParseModulePath(bool* ok) {
         member->interface()->Print();
       }
 #endif
-      ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
+      ParserTraits::ReportMessage("invalid_module_path",
+                                  Vector<Handle<String> >(&name, 1));
       return NULL;
     }
     result = member;
@@ -1232,7 +1247,8 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
         module->interface()->Print();
       }
 #endif
-      ReportMessage("invalid_module_path", Vector<Handle<String> >(&name, 1));
+      ParserTraits::ReportMessage("invalid_module_path",
+                                  Vector<Handle<String> >(&name, 1));
       return NULL;
     }
     VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
@@ -1440,8 +1456,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
       // Statement:
       //    GeneratorDeclaration
       if (!top_scope_->is_classic_mode()) {
-        ReportMessageAt(scanner().peek_location(), "strict_function",
-                        Vector<const char*>::empty());
+        ReportMessageAt(scanner().peek_location(), "strict_function");
         *ok = false;
         return NULL;
       }
@@ -1620,7 +1635,8 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
           var->interface()->Print();
         }
 #endif
-        ReportMessage("module_type_error", Vector<Handle<String> >(&name, 1));
+        ParserTraits::ReportMessage("module_type_error",
+                                    Vector<Handle<String> >(&name, 1));
       }
     }
   }
@@ -1778,12 +1794,6 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
 }
 
 
-bool Parser::IsEvalOrArguments(Handle<String> string) {
-  return string.is_identical_to(isolate()->factory()->eval_string()) ||
-      string.is_identical_to(isolate()->factory()->arguments_string());
-}
-
-
 // If the variable declaration declares exactly one non-const
 // variable, then *out is set to that variable. In all other cases,
 // *out is untouched; in particular, it is the caller's responsibility
@@ -1929,8 +1939,7 @@ Block* Parser::ParseVariableDeclarations(
     Declare(declaration, mode != VAR, CHECK_OK);
     nvars++;
     if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) {
-      ReportMessageAt(scanner().location(), "too_many_variables",
-                      Vector<const char*>::empty());
+      ReportMessageAt(scanner().location(), "too_many_variables");
       *ok = false;
       return NULL;
     }
@@ -2233,7 +2242,7 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
       message = "unknown_label";
       args = Vector<Handle<String> >(&label, 1);
     }
-    ReportMessageAt(scanner().location(), message, args);
+    ParserTraits::ReportMessageAt(scanner().location(), message, args);
     *ok = false;
     return NULL;
   }
@@ -2271,7 +2280,7 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
       message = "unknown_label";
       args = Vector<Handle<String> >(&label, 1);
     }
-    ReportMessageAt(scanner().location(), message, args);
+    ParserTraits::ReportMessageAt(scanner().location(), message, args);
     *ok = false;
     return NULL;
   }
@@ -3014,14 +3023,6 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
 }
 
 
-int ParserBase::Precedence(Token::Value tok, bool accept_IN) {
-  if (tok == Token::IN && !accept_IN)
-    return 0;  // 0 precedence will terminate binary expression parsing
-
-  return Token::Precedence(tok);
-}
-
-
 // Precedence >= 4
 Expression* Parser::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) {
   ASSERT(prec >= 4);
@@ -3864,8 +3865,7 @@ ZoneList<Expression*>* Parser::ParseArguments(bool* ok) {
     Expression* argument = ParseAssignmentExpression(true, CHECK_OK);
     result->Add(argument, zone());
     if (result->length() > Code::kMaxArguments) {
-      ReportMessageAt(scanner().location(), "too_many_arguments",
-                      Vector<const char*>::empty());
+      ReportMessageAt(scanner().location(), "too_many_arguments");
       *ok = false;
       return NULL;
     }
@@ -4097,8 +4097,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
       top_scope_->DeclareParameter(param_name, VAR);
       num_parameters++;
       if (num_parameters > Code::kMaxArguments) {
-        ReportMessageAt(scanner().location(), "too_many_parameters",
-                        Vector<const char*>::empty());
+        ReportMessageAt(scanner().location(), "too_many_parameters");
         *ok = false;
         return NULL;
       }
@@ -4189,8 +4188,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
           if (arg != NULL) {
             args = Vector<const char*>(&arg, 1);
           }
-          ReportMessageAt(Scanner::Location(logger.start(), logger.end()),
-                          logger.message(), args);
+          ParserTraits::ReportMessageAt(
+              Scanner::Location(logger.start(), logger.end()),
+              logger.message(),
+              args);
           *ok = false;
           return NULL;
         }
@@ -4264,33 +4265,27 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
     // since the function can declare itself strict.
     if (!top_scope_->is_classic_mode()) {
       if (IsEvalOrArguments(function_name)) {
-        ReportMessageAt(function_name_location,
-                        "strict_eval_arguments",
-                        Vector<const char*>::empty());
+        ReportMessageAt(function_name_location, "strict_eval_arguments");
         *ok = false;
         return NULL;
       }
       if (name_is_strict_reserved) {
-        ReportMessageAt(function_name_location, "unexpected_strict_reserved",
-                        Vector<const char*>::empty());
+        ReportMessageAt(function_name_location, "unexpected_strict_reserved");
         *ok = false;
         return NULL;
       }
       if (eval_args_error_log.IsValid()) {
-        ReportMessageAt(eval_args_error_log, "strict_eval_arguments",
-                        Vector<const char*>::empty());
+        ReportMessageAt(eval_args_error_log, "strict_eval_arguments");
         *ok = false;
         return NULL;
       }
       if (dupe_error_loc.IsValid()) {
-        ReportMessageAt(dupe_error_loc, "strict_param_dupe",
-                        Vector<const char*>::empty());
+        ReportMessageAt(dupe_error_loc, "strict_param_dupe");
         *ok = false;
         return NULL;
       }
       if (reserved_loc.IsValid()) {
-        ReportMessageAt(reserved_loc, "unexpected_strict_reserved",
-                        Vector<const char*>::empty());
+        ReportMessageAt(reserved_loc, "unexpected_strict_reserved");
         *ok = false;
         return NULL;
       }
@@ -4401,7 +4396,8 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
 
   // Check that the function is defined if it's an inline runtime call.
   if (function == NULL && name->Get(0) == '_') {
-    ReportMessage("not_defined", Vector<Handle<String> >(&name, 1));
+    ParserTraits::ReportMessage("not_defined",
+                                Vector<Handle<String> >(&name, 1));
     *ok = false;
     return NULL;
   }
@@ -4411,88 +4407,6 @@ Expression* Parser::ParseV8Intrinsic(bool* ok) {
 }
 
 
-bool ParserBase::peek_any_identifier() {
-  Token::Value next = peek();
-  return next == Token::IDENTIFIER ||
-         next == Token::FUTURE_RESERVED_WORD ||
-         next == Token::FUTURE_STRICT_RESERVED_WORD ||
-         next == Token::YIELD;
-}
-
-
-bool ParserBase::CheckContextualKeyword(Vector<const char> keyword) {
-  if (peek() == Token::IDENTIFIER &&
-      scanner()->is_next_contextual_keyword(keyword)) {
-    Consume(Token::IDENTIFIER);
-    return true;
-  }
-  return false;
-}
-
-
-void ParserBase::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);
-}
-
-
-void ParserBase::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;
-  }
-}
-
-
-void ParserBase::ReportUnexpectedToken(Token::Value token) {
-  // We don't report stack overflows here, to avoid increasing the
-  // stack depth even further.  Instead we report it after parsing is
-  // over, in ParseProgram.
-  if (token == Token::ILLEGAL && stack_overflow()) {
-    return;
-  }
-  Scanner::Location source_location = scanner()->location();
-
-  // Four of the tokens are treated specially
-  switch (token) {
-  case Token::EOS:
-    return ReportMessageAt(source_location, "unexpected_eos");
-  case Token::NUMBER:
-    return ReportMessageAt(source_location, "unexpected_token_number");
-  case Token::STRING:
-    return ReportMessageAt(source_location, "unexpected_token_string");
-  case Token::IDENTIFIER:
-    return ReportMessageAt(source_location,
-                           "unexpected_token_identifier");
-  case Token::FUTURE_RESERVED_WORD:
-    return ReportMessageAt(source_location, "unexpected_reserved");
-  case Token::YIELD:
-  case Token::FUTURE_STRICT_RESERVED_WORD:
-    return ReportMessageAt(source_location,
-                           is_classic_mode() ? "unexpected_token_identifier"
-                                             : "unexpected_strict_reserved");
-  default:
-    const char* name = Token::String(token);
-    ASSERT(name != NULL);
-    ReportMessageAt(
-        source_location, "unexpected_token", Vector<const char*>(&name, 1));
-  }
-}
-
-
 Literal* Parser::GetLiteralUndefined(int position) {
   return factory()->NewLiteral(
       isolate()->factory()->undefined_value(), position);
@@ -4505,68 +4419,6 @@ Literal* Parser::GetLiteralTheHole(int position) {
 }
 
 
-// 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;").
-Handle<String> Parser::ParseIdentifier(
-    AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
-    bool* ok) {
-  Token::Value next = Next();
-  if (next == Token::IDENTIFIER) {
-    Handle<String> name = GetSymbol();
-    if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
-        !top_scope_->is_classic_mode() && IsEvalOrArguments(name)) {
-      ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
-      *ok = false;
-    }
-    return name;
-  } else if (top_scope_->is_classic_mode() &&
-             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-              (next == Token::YIELD && !is_generator()))) {
-    return GetSymbol();
-  } else {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Handle<String>();
-  }
-}
-
-
-// Parses and identifier or a strict mode future reserved word, and indicate
-// whether it is strict mode future reserved.
-Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
-    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::YIELD && !is_generator())) {
-    *is_strict_reserved = true;
-  } else {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Handle<String>();
-  }
-  return GetSymbol();
-}
-
-
-Handle<String> Parser::ParseIdentifierName(bool* ok) {
-  Token::Value next = Next();
-  if (next != Token::IDENTIFIER &&
-      next != Token::FUTURE_RESERVED_WORD &&
-      next != Token::FUTURE_STRICT_RESERVED_WORD &&
-      !Token::IsKeyword(next)) {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Handle<String>();
-  }
-  return GetSymbol();
-}
-
-
 void Parser::MarkAsLValue(Expression* expression) {
   VariableProxy* proxy = expression != NULL
       ? expression->AsVariableProxy()
@@ -4592,18 +4444,6 @@ void Parser::CheckStrictModeLValue(Expression* expression,
 }
 
 
-// Checks whether an octal literal was last seen between beg_pos and end_pos.
-// If so, reports an error. Only called for strict mode.
-void ParserBase::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
-  Scanner::Location octal = scanner()->octal_position();
-  if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
-    ReportMessageAt(octal, "strict_octal_literal");
-    scanner()->clear_octal_position();
-    *ok = false;
-  }
-}
-
-
 void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
   Declaration* decl = scope->CheckConflictingVarDeclarations();
   if (decl != NULL) {
@@ -4617,28 +4457,12 @@ void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
     Scanner::Location location = position == RelocInfo::kNoPosition
         ? Scanner::Location::invalid()
         : Scanner::Location(position, position + 1);
-    ReportMessageAt(location, "redeclaration", args);
+    ParserTraits::ReportMessageAt(location, "redeclaration", args);
     *ok = false;
   }
 }
 
 
-// This function reads an identifier name and determines whether or not it
-// is 'get' or 'set'.
-Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
-                                                     bool* is_set,
-                                                     bool* ok) {
-  Handle<String> result = ParseIdentifierName(ok);
-  if (!*ok) return Handle<String>();
-  if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
-    const char* token = scanner().literal_ascii_string().start();
-    *is_get = strncmp(token, "get", 3) == 0;
-    *is_set = !*is_get && strncmp(token, "set", 3) == 0;
-  }
-  return result;
-}
-
-
 // ----------------------------------------------------------------------------
 // Parser support
 
@@ -5687,7 +5511,7 @@ bool Parser::Parse() {
       Scanner::Location loc = pre_parse_data->MessageLocation();
       const char* message = pre_parse_data->BuildMessage();
       Vector<const char*> args = pre_parse_data->BuildArgs();
-      ReportMessageAt(loc, message, args);
+      ParserTraits::ReportMessageAt(loc, message, args);
       DeleteArray(message);
       for (int i = 0; i < args.length(); i++) {
         DeleteArray(args[i]);
index 2b0995a..64513d3 100644 (file)
@@ -404,10 +404,44 @@ class RegExpParser BASE_EMBEDDED {
 // ----------------------------------------------------------------------------
 // JAVASCRIPT PARSING
 
-// Forward declaration.
+class Parser;
 class SingletonLogger;
 
-class Parser : public ParserBase {
+class ParserTraits {
+ public:
+  typedef Parser* ParserType;
+  // Return types for traversing functions.
+  typedef Handle<String> IdentifierType;
+
+  explicit ParserTraits(Parser* parser) : parser_(parser) {}
+
+  // Helper functions for recursive descent.
+  bool is_classic_mode() const;
+  bool is_generator() const;
+  bool IsEvalOrArguments(Handle<String> identifier) const;
+
+  // Reporting errors.
+  void ReportMessageAt(Scanner::Location source_location,
+                       const char* message,
+                       Vector<const char*> args);
+  void ReportMessage(const char* message, Vector<Handle<String> > args);
+  void ReportMessageAt(Scanner::Location source_location,
+                       const char* message,
+                       Vector<Handle<String> > args);
+
+  // Identifiers:
+  static IdentifierType EmptyIdentifier() {
+    return Handle<String>();
+  }
+
+  IdentifierType GetSymbol();
+
+ private:
+  Parser* parser_;
+};
+
+
+class Parser : public ParserBase<ParserTraits> {
  public:
   explicit Parser(CompilationInfo* info);
   ~Parser() {
@@ -427,6 +461,8 @@ class Parser : public ParserBase {
   bool Parse();
 
  private:
+  friend class ParserTraits;
+
   static const int kMaxNumFunctionLocals = 131071;  // 2^17-1
 
   enum Mode {
@@ -521,10 +557,6 @@ class Parser : public ParserBase {
     Mode old_mode_;
   };
 
-  virtual bool is_classic_mode() {
-    return top_scope_->is_classic_mode();
-  }
-
   // Returns NULL if parsing failed.
   FunctionLiteral* ParseProgram();
 
@@ -541,17 +573,6 @@ class Parser : public ParserBase {
 
   // Report syntax error
   void ReportInvalidPreparseData(Handle<String> name, bool* ok);
-  void ReportMessage(const char* message, Vector<const char*> args);
-  void ReportMessage(const char* message, Vector<Handle<String> > args);
-  void ReportMessageAt(Scanner::Location location, const char* type) {
-    ReportMessageAt(location, type, Vector<const char*>::empty());
-  }
-  void ReportMessageAt(Scanner::Location loc,
-                       const char* message,
-                       Vector<const char*> args);
-  void ReportMessageAt(Scanner::Location loc,
-                       const char* message,
-                       Vector<Handle<String> > args);
 
   void set_pre_parse_data(ScriptDataImpl *data) {
     pre_parse_data_ = data;
@@ -571,9 +592,6 @@ class Parser : public ParserBase {
         ? top_scope_ : top_scope_->DeclarationScope();
   }
 
-  // Check if the given string is 'eval' or 'arguments'.
-  bool IsEvalOrArguments(Handle<String> string);
-
   // All ParseXXX functions take as the last argument an *ok parameter
   // which is set to false if parsing failed; it is unchanged otherwise.
   // By making the 'exception handling' explicit, we are forced to check
@@ -660,8 +678,6 @@ class Parser : public ParserBase {
   // Magical syntax support.
   Expression* ParseV8Intrinsic(bool* ok);
 
-  bool is_generator() const { return current_function_state_->is_generator(); }
-
   bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
 
   Handle<String> LiteralString(PretenureFlag tenured) {
@@ -684,20 +700,10 @@ class Parser : public ParserBase {
     }
   }
 
-  Handle<String> GetSymbol();
-
   // Get odd-ball literals.
   Literal* GetLiteralUndefined(int position);
   Literal* GetLiteralTheHole(int position);
 
-  Handle<String> ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
-  Handle<String> ParseIdentifierOrStrictReservedWord(
-      bool* is_strict_reserved, bool* ok);
-  Handle<String> ParseIdentifierName(bool* ok);
-  Handle<String> ParseIdentifierNameOrGetOrSet(bool* is_get,
-                                               bool* is_set,
-                                               bool* ok);
-
   // Determine if the expression is a variable proxy and mark it as being used
   // in an assignment or with a increment/decrement operator. This is currently
   // used on for the statically checking assignments to harmony const bindings.
index fa6f217..c01acdd 100644 (file)
@@ -55,6 +55,68 @@ int isfinite(double value);
 namespace v8 {
 namespace internal {
 
+bool PreParserTraits::is_classic_mode() const {
+  return pre_parser_->scope_->language_mode() == CLASSIC_MODE;
+}
+
+
+bool PreParserTraits::is_generator() const {
+  return pre_parser_->scope_->is_generator();
+}
+
+
+void PreParserTraits::ReportMessageAt(Scanner::Location location,
+                                      const char* message,
+                                      Vector<const char*> args) {
+  ReportMessageAt(location.beg_pos,
+                  location.end_pos,
+                  message,
+                  args.length() > 0 ? args[0] : NULL);
+}
+
+
+void PreParserTraits::ReportMessageAt(Scanner::Location location,
+                                      const char* type,
+                                      const char* name_opt) {
+  pre_parser_->log_
+      ->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
+}
+
+
+void PreParserTraits::ReportMessageAt(int start_pos,
+                                      int end_pos,
+                                      const char* type,
+                                      const char* name_opt) {
+  pre_parser_->log_->LogMessage(start_pos, end_pos, type, name_opt);
+}
+
+
+PreParserIdentifier PreParserTraits::GetSymbol() {
+  Scanner* scanner = pre_parser_->scanner();
+  pre_parser_->LogSymbol();
+  if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
+    return PreParserIdentifier::FutureReserved();
+  } else if (scanner->current_token() ==
+             Token::FUTURE_STRICT_RESERVED_WORD) {
+    return PreParserIdentifier::FutureStrictReserved();
+  } else if (scanner->current_token() == Token::YIELD) {
+    return PreParserIdentifier::Yield();
+  }
+  if (scanner->is_literal_ascii()) {
+    // Detect strict-mode poison words.
+    if (scanner->literal_length() == 4 &&
+        !strncmp(scanner->literal_ascii_string().start(), "eval", 4)) {
+      return PreParserIdentifier::Eval();
+    }
+    if (scanner->literal_length() == 9 &&
+        !strncmp(scanner->literal_ascii_string().start(), "arguments", 9)) {
+      return PreParserIdentifier::Arguments();
+    }
+  }
+  return PreParserIdentifier::Default();
+}
+
+
 PreParser::PreParseResult PreParser::PreParseLazyFunction(
     LanguageMode mode, bool is_generator, ParserRecorder* log) {
   log_ = log;
@@ -235,8 +297,10 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
       Statement statement = ParseFunctionDeclaration(CHECK_OK);
       Scanner::Location end_location = scanner()->location();
       if (!scope_->is_classic_mode()) {
-        ReportMessageAt(start_location.beg_pos, end_location.end_pos,
-                        "strict_function", NULL);
+        PreParserTraits::ReportMessageAt(start_location.beg_pos,
+                                         end_location.end_pos,
+                                         "strict_function",
+                                         NULL);
         *ok = false;
         return Statement::Default();
       } else {
@@ -352,16 +416,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
         break;
       case STRICT_MODE: {
         Scanner::Location location = scanner()->peek_location();
-        ReportMessageAt(location, "strict_const", NULL);
+        ReportMessageAt(location, "strict_const");
         *ok = false;
         return Statement::Default();
       }
       case EXTENDED_MODE:
         if (var_context != kSourceElement &&
             var_context != kForStatement) {
-          Scanner::Location location = scanner()->peek_location();
-          ReportMessageAt(location.beg_pos, location.end_pos,
-                          "unprotected_const", NULL);
+          ReportMessageAt(scanner()->peek_location(), "unprotected_const");
           *ok = false;
           return Statement::Default();
         }
@@ -376,18 +438,14 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
     // * It is a Syntax Error if the code that matches this production is not
     //   contained in extended code.
     if (!is_extended_mode()) {
-      Scanner::Location location = scanner()->peek_location();
-      ReportMessageAt(location.beg_pos, location.end_pos,
-                      "illegal_let", NULL);
+      ReportMessageAt(scanner()->peek_location(), "illegal_let");
       *ok = false;
       return Statement::Default();
     }
     Consume(Token::LET);
     if (var_context != kSourceElement &&
         var_context != kForStatement) {
-      Scanner::Location location = scanner()->peek_location();
-      ReportMessageAt(location.beg_pos, location.end_pos,
-                      "unprotected_let", NULL);
+      ReportMessageAt(scanner()->peek_location(), "unprotected_let");
       *ok = false;
       return Statement::Default();
     }
@@ -531,8 +589,7 @@ PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
   //   'with' '(' Expression ')' Statement
   Expect(Token::WITH, CHECK_OK);
   if (!scope_->is_classic_mode()) {
-    Scanner::Location location = scanner()->location();
-    ReportMessageAt(location, "strict_mode_with", NULL);
+    ReportMessageAt(scanner()->location(), "strict_mode_with");
     *ok = false;
     return Statement::Default();
   }
@@ -676,8 +733,7 @@ PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
 
   Expect(Token::THROW, CHECK_OK);
   if (scanner()->HasAnyLineTerminatorBeforeNext()) {
-    Scanner::Location pos = scanner()->location();
-    ReportMessageAt(pos, "newline_after_throw", NULL);
+    ReportMessageAt(scanner()->location(), "newline_after_throw");
     *ok = false;
     return Statement::Default();
   }
@@ -705,7 +761,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
 
   Token::Value tok = peek();
   if (tok != Token::CATCH && tok != Token::FINALLY) {
-    ReportMessageAt(scanner()->location(), "no_catch_or_finally", NULL);
+    ReportMessageAt(scanner()->location(), "no_catch_or_finally");
     *ok = false;
     return Statement::Default();
   }
@@ -788,8 +844,8 @@ PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
       expression.IsIdentifier() &&
       expression.AsIdentifier().IsEvalOrArguments()) {
     Scanner::Location after = scanner()->location();
-    ReportMessageAt(before.beg_pos, after.end_pos,
-                    "strict_eval_arguments", NULL);
+    PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
+                                     "strict_eval_arguments", NULL);
     *ok = false;
     return Expression::Default();
   }
@@ -882,8 +938,8 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
         expression.IsIdentifier() &&
         expression.AsIdentifier().IsEvalOrArguments()) {
       Scanner::Location after = scanner()->location();
-      ReportMessageAt(before.beg_pos, after.end_pos,
-                      "strict_eval_arguments", NULL);
+      PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
+                                       "strict_eval_arguments", NULL);
       *ok = false;
     }
     return Expression::Default();
@@ -905,8 +961,8 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
         expression.IsIdentifier() &&
         expression.AsIdentifier().IsEvalOrArguments()) {
       Scanner::Location after = scanner()->location();
-      ReportMessageAt(before.beg_pos, after.end_pos,
-                      "strict_eval_arguments", NULL);
+      PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
+                                       "strict_eval_arguments", NULL);
       *ok = false;
       return Expression::Default();
     }
@@ -1249,7 +1305,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
                                                     bool* ok) {
   if (!scanner()->ScanRegExpPattern(seen_equal)) {
     Next();
-    ReportMessageAt(scanner()->location(), "unterminated_regexp", NULL);
+    ReportMessageAt(scanner()->location(), "unterminated_regexp");
     *ok = false;
     return Expression::Default();
   }
@@ -1258,7 +1314,7 @@ PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
 
   if (!scanner()->ScanRegExpFlags()) {
     Next();
-    ReportMessageAt(scanner()->location(), "invalid_regexp_flags", NULL);
+    ReportMessageAt(scanner()->location(), "invalid_regexp_flags");
     *ok = false;
     return Expression::Default();
   }
@@ -1366,31 +1422,27 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
   // since the function can declare itself strict.
   if (!scope_->is_classic_mode()) {
     if (function_name.IsEvalOrArguments()) {
-      ReportMessageAt(function_name_location, "strict_eval_arguments", NULL);
+      ReportMessageAt(function_name_location, "strict_eval_arguments");
       *ok = false;
       return Expression::Default();
     }
     if (name_is_strict_reserved) {
-      ReportMessageAt(
-          function_name_location, "unexpected_strict_reserved", NULL);
+      ReportMessageAt(function_name_location, "unexpected_strict_reserved");
       *ok = false;
       return Expression::Default();
     }
     if (eval_args_error_loc.IsValid()) {
-      ReportMessageAt(eval_args_error_loc, "strict_eval_arguments",
-                      Vector<const char*>::empty());
+      ReportMessageAt(eval_args_error_loc, "strict_eval_arguments");
       *ok = false;
       return Expression::Default();
     }
     if (dupe_error_loc.IsValid()) {
-      ReportMessageAt(dupe_error_loc, "strict_param_dupe",
-                      Vector<const char*>::empty());
+      ReportMessageAt(dupe_error_loc, "strict_param_dupe");
       *ok = false;
       return Expression::Default();
     }
     if (reserved_error_loc.IsValid()) {
-      ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved",
-                      Vector<const char*>::empty());
+      ReportMessageAt(reserved_error_loc, "unexpected_strict_reserved");
       *ok = false;
       return Expression::Default();
     }
@@ -1464,142 +1516,4 @@ PreParser::Expression PreParser::GetStringSymbol() {
 }
 
 
-PreParser::Identifier PreParser::GetIdentifierSymbol() {
-  LogSymbol();
-  if (scanner()->current_token() == Token::FUTURE_RESERVED_WORD) {
-    return Identifier::FutureReserved();
-  } else if (scanner()->current_token() ==
-             Token::FUTURE_STRICT_RESERVED_WORD) {
-    return Identifier::FutureStrictReserved();
-  } else if (scanner()->current_token() == Token::YIELD) {
-    return Identifier::Yield();
-  }
-  if (scanner()->is_literal_ascii()) {
-    // Detect strict-mode poison words.
-    if (scanner()->literal_length() == 4 &&
-        !strncmp(scanner()->literal_ascii_string().start(), "eval", 4)) {
-      return Identifier::Eval();
-    }
-    if (scanner()->literal_length() == 9 &&
-        !strncmp(scanner()->literal_ascii_string().start(), "arguments", 9)) {
-      return Identifier::Arguments();
-    }
-  }
-  return Identifier::Default();
-}
-
-
-// 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;").
-PreParser::Identifier PreParser::ParseIdentifier(
-    AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
-    bool* ok) {
-  Token::Value next = Next();
-  if (next == Token::IDENTIFIER) {
-    PreParser::Identifier name = GetIdentifierSymbol();
-    if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
-        !scope_->is_classic_mode() && name.IsEvalOrArguments()) {
-      ReportMessageAt(scanner()->location(), "strict_eval_arguments", NULL);
-      *ok = false;
-    }
-    return name;
-  } else if (scope_->is_classic_mode() &&
-             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
-              (next == Token::YIELD && !scope_->is_generator()))) {
-    return GetIdentifierSymbol();
-  } else {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Identifier::Default();
-  }
-}
-
-
-// Parses and identifier or a strict mode future reserved word, and indicate
-// whether it is strict mode future reserved.
-PreParser::Identifier PreParser::ParseIdentifierOrStrictReservedWord(
-    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::YIELD && !scope_->is_generator())) {
-    *is_strict_reserved = true;
-  } else {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Identifier::Default();
-  }
-  return GetIdentifierSymbol();
-}
-
-
-PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
-  Token::Value next = Next();
-  if (next != Token::IDENTIFIER &&
-      next != Token::FUTURE_RESERVED_WORD &&
-      next != Token::FUTURE_STRICT_RESERVED_WORD &&
-      !Token::IsKeyword(next)) {
-    ReportUnexpectedToken(next);
-    *ok = false;
-    return Identifier::Default();
-  }
-  return GetIdentifierSymbol();
-}
-
-#undef CHECK_OK
-
-
-// This function reads an identifier and determines whether or not it
-// is 'get' or 'set'.
-PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
-                                                               bool* is_set,
-                                                               bool* ok) {
-  Identifier result = ParseIdentifierName(ok);
-  if (!*ok) return Identifier::Default();
-  if (scanner()->is_literal_ascii() &&
-      scanner()->literal_length() == 3) {
-    const char* token = scanner()->literal_ascii_string().start();
-    *is_get = strncmp(token, "get", 3) == 0;
-    *is_set = !*is_get && strncmp(token, "set", 3) == 0;
-  }
-  return result;
-}
-
-
-void PreParser::ObjectLiteralChecker::CheckProperty(Token::Value property,
-                                                    PropertyKind type,
-                                                    bool* ok) {
-  int old;
-  if (property == Token::NUMBER) {
-    old = finder_.AddNumber(scanner()->literal_ascii_string(), type);
-  } else if (scanner()->is_literal_ascii()) {
-    old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type);
-  } else {
-    old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type);
-  }
-  PropertyKind old_type = static_cast<PropertyKind>(old);
-  if (HasConflict(old_type, type)) {
-    if (IsDataDataConflict(old_type, type)) {
-      // Both are data properties.
-      if (language_mode_ == CLASSIC_MODE) return;
-      parser()->ReportMessageAt(scanner()->location(),
-                               "strict_duplicate_property");
-    } else if (IsDataAccessorConflict(old_type, type)) {
-      // Both a data and an accessor property with the same name.
-      parser()->ReportMessageAt(scanner()->location(),
-                               "accessor_data_property");
-    } else {
-      ASSERT(IsAccessorAccessorConflict(old_type, type));
-      // Both accessors of the same type.
-      parser()->ReportMessageAt(scanner()->location(),
-                               "accessor_get_set");
-    }
-    *ok = false;
-  }
-}
-
 } }  // v8::internal
index bcaab74..b6a9e84 100644 (file)
@@ -36,18 +36,19 @@ namespace v8 {
 namespace internal {
 
 // Common base class shared between parser and pre-parser.
-class ParserBase {
+template <typename Traits>
+class ParserBase : public Traits {
  public:
-  ParserBase(Scanner* scanner, uintptr_t stack_limit)
-      : scanner_(scanner),
+  ParserBase(Scanner* scanner, uintptr_t stack_limit,
+             typename Traits::ParserType this_object)
+      : Traits(this_object),
+        scanner_(scanner),
         stack_limit_(stack_limit),
         stack_overflow_(false),
         allow_lazy_(false),
         allow_natives_syntax_(false),
         allow_generators_(false),
         allow_for_of_(false) { }
-  // TODO(mstarzinger): Only virtual until message reporting has been unified.
-  virtual ~ParserBase() { }
 
   // Getters that indicate whether certain syntactical constructs are
   // allowed to be parsed by this instance of the parser.
@@ -87,8 +88,6 @@ class ParserBase {
   bool stack_overflow() const { return stack_overflow_; }
   void set_stack_overflow() { stack_overflow_ = true; }
 
-  virtual bool is_classic_mode() = 0;
-
   INLINE(Token::Value peek()) {
     if (stack_overflow_) return Token::ILLEGAL;
     return scanner()->peek();
@@ -132,25 +131,99 @@ class ParserBase {
     }
   }
 
-  bool peek_any_identifier();
-  void ExpectSemicolon(bool* ok);
-  bool CheckContextualKeyword(Vector<const char> keyword);
-  void ExpectContextualKeyword(Vector<const char> keyword, bool* ok);
+  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::YIELD;
+  }
 
-  // Strict mode octal literal validation.
-  void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
+  bool CheckContextualKeyword(Vector<const char> keyword) {
+    if (peek() == Token::IDENTIFIER &&
+        scanner()->is_next_contextual_keyword(keyword)) {
+      Consume(Token::IDENTIFIER);
+      return true;
+    }
+    return false;
+  }
+
+  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;
+    }
+  }
+
+  // Checks whether an octal literal was last seen between beg_pos and end_pos.
+  // If so, reports an error. Only called for strict mode.
+  void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
+    Scanner::Location octal = scanner()->octal_position();
+    if (octal.IsValid() && beg_pos <= octal.beg_pos &&
+        octal.end_pos <= end_pos) {
+      ReportMessageAt(octal, "strict_octal_literal");
+      scanner()->clear_octal_position();
+      *ok = false;
+    }
+  }
 
   // Determine precedence of given token.
-  static int Precedence(Token::Value token, bool accept_IN);
+  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);
+  }
 
   // Report syntax errors.
-  void ReportUnexpectedToken(Token::Value token);
-  void ReportMessageAt(Scanner::Location location, const char* type) {
-    ReportMessageAt(location, type, Vector<const char*>::empty());
+  void ReportMessage(const char* message, Vector<const char*> args) {
+    Scanner::Location source_location = scanner()->location();
+    Traits::ReportMessageAt(source_location, message, args);
   }
-  virtual void ReportMessageAt(Scanner::Location source_location,
-                               const char* message,
-                               Vector<const char*> args) = 0;
+
+  void ReportMessageAt(Scanner::Location location, const char* message) {
+    Traits::ReportMessageAt(location, message, Vector<const char*>::empty());
+  }
+
+  void ReportUnexpectedToken(Token::Value token);
+
+  // 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;").
+  typename Traits::IdentifierType ParseIdentifier(
+      AllowEvalOrArgumentsAsIdentifier,
+      bool* ok);
+  // Parses an identifier or a strict mode future reserved word, and indicate
+  // whether it is strict mode future reserved.
+  typename Traits::IdentifierType ParseIdentifierOrStrictReservedWord(
+      bool* is_strict_reserved,
+      bool* ok);
+  typename Traits::IdentifierType ParseIdentifierName(bool* ok);
+  // Parses an identifier and determines whether or not it is 'get' or 'set'.
+  typename Traits::IdentifierType ParseIdentifierNameOrGetOrSet(bool* is_get,
+                                                                bool* is_set,
+                                                                bool* ok);
 
   // Used to detect duplicates in object literals. Each of the values
   // kGetterProperty, kSetterProperty and kValueProperty represents
@@ -218,6 +291,176 @@ class ParserBase {
 };
 
 
+class PreParserIdentifier {
+ public:
+  static PreParserIdentifier Default() {
+    return PreParserIdentifier(kUnknownIdentifier);
+  }
+  static PreParserIdentifier Eval() {
+    return PreParserIdentifier(kEvalIdentifier);
+  }
+  static PreParserIdentifier Arguments() {
+    return PreParserIdentifier(kArgumentsIdentifier);
+  }
+  static PreParserIdentifier FutureReserved() {
+    return PreParserIdentifier(kFutureReservedIdentifier);
+  }
+  static PreParserIdentifier FutureStrictReserved() {
+    return PreParserIdentifier(kFutureStrictReservedIdentifier);
+  }
+  static PreParserIdentifier Yield() {
+    return PreParserIdentifier(kYieldIdentifier);
+  }
+  bool IsEval() { return type_ == kEvalIdentifier; }
+  bool IsArguments() { return type_ == kArgumentsIdentifier; }
+  bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
+  bool IsYield() { return type_ == kYieldIdentifier; }
+  bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
+  bool IsFutureStrictReserved() {
+    return type_ == kFutureStrictReservedIdentifier;
+  }
+  bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; }
+
+ private:
+  enum Type {
+    kUnknownIdentifier,
+    kFutureReservedIdentifier,
+    kFutureStrictReservedIdentifier,
+    kYieldIdentifier,
+    kEvalIdentifier,
+    kArgumentsIdentifier
+  };
+  explicit PreParserIdentifier(Type type) : type_(type) {}
+  Type type_;
+
+  friend class PreParserExpression;
+};
+
+
+// Bits 0 and 1 are used to identify the type of expression:
+// If bit 0 is set, it's an identifier.
+// if bit 1 is set, it's a string literal.
+// If neither is set, it's no particular type, and both set isn't
+// use yet.
+class PreParserExpression {
+ public:
+  static PreParserExpression Default() {
+    return PreParserExpression(kUnknownExpression);
+  }
+
+  static PreParserExpression FromIdentifier(PreParserIdentifier id) {
+    return PreParserExpression(kIdentifierFlag |
+                               (id.type_ << kIdentifierShift));
+  }
+
+  static PreParserExpression StringLiteral() {
+    return PreParserExpression(kUnknownStringLiteral);
+  }
+
+  static PreParserExpression UseStrictStringLiteral() {
+    return PreParserExpression(kUseStrictString);
+  }
+
+  static PreParserExpression This() {
+    return PreParserExpression(kThisExpression);
+  }
+
+  static PreParserExpression ThisProperty() {
+    return PreParserExpression(kThisPropertyExpression);
+  }
+
+  static PreParserExpression StrictFunction() {
+    return PreParserExpression(kStrictFunctionExpression);
+  }
+
+  bool IsIdentifier() { return (code_ & kIdentifierFlag) != 0; }
+
+  // Only works corretly if it is actually an identifier expression.
+  PreParserIdentifier AsIdentifier() {
+    return PreParserIdentifier(
+        static_cast<PreParserIdentifier::Type>(code_ >> kIdentifierShift));
+  }
+
+  bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; }
+
+  bool IsUseStrictLiteral() {
+    return (code_ & kStringLiteralMask) == kUseStrictString;
+  }
+
+  bool IsThis() { return code_ == kThisExpression; }
+
+  bool IsThisProperty() { return code_ == kThisPropertyExpression; }
+
+  bool IsStrictFunction() { return code_ == kStrictFunctionExpression; }
+
+ private:
+  // First two/three bits are used as flags.
+  // Bit 0 and 1 represent identifiers or strings literals, and are
+  // mutually exclusive, but can both be absent.
+  enum {
+    kUnknownExpression = 0,
+    // Identifiers
+    kIdentifierFlag = 1,  // Used to detect labels.
+    kIdentifierShift = 3,
+
+    kStringLiteralFlag = 2,  // Used to detect directive prologue.
+    kUnknownStringLiteral = kStringLiteralFlag,
+    kUseStrictString = kStringLiteralFlag | 8,
+    kStringLiteralMask = kUseStrictString,
+
+    // Below here applies if neither identifier nor string literal.
+    kThisExpression = 4,
+    kThisPropertyExpression = 8,
+    kStrictFunctionExpression = 12
+  };
+
+  explicit PreParserExpression(int expression_code) : code_(expression_code) {}
+
+  int code_;
+};
+
+class PreParser;
+
+
+class PreParserTraits {
+ public:
+  typedef PreParser* ParserType;
+  // Return types for traversing functions.
+  typedef PreParserIdentifier IdentifierType;
+
+  explicit PreParserTraits(PreParser* pre_parser) : pre_parser_(pre_parser) {}
+
+  // Helper functions for recursive descent.
+  bool is_classic_mode() const;
+  bool is_generator() const;
+  static bool IsEvalOrArguments(IdentifierType identifier) {
+    return identifier.IsEvalOrArguments();
+  }
+
+  // Reporting errors.
+  void ReportMessageAt(Scanner::Location location,
+                       const char* message,
+                       Vector<const char*> args);
+  void ReportMessageAt(Scanner::Location location,
+                       const char* type,
+                       const char* name_opt);
+  void ReportMessageAt(int start_pos,
+                       int end_pos,
+                       const char* type,
+                       const char* name_opt);
+
+  // Identifiers:
+  static IdentifierType EmptyIdentifier() {
+    return PreParserIdentifier::Default();
+  }
+
+  IdentifierType GetSymbol();
+
+ private:
+  PreParser* pre_parser_;
+};
+
+
 // Preparsing checks a JavaScript program and emits preparse-data that helps
 // a later parsing to be faster.
 // See preparse-data-format.h for the data format.
@@ -230,8 +473,11 @@ class ParserBase {
 // rather it is to speed up properly written and correct programs.
 // That means that contextual checks (like a label being declared where
 // it is used) are generally omitted.
-class PreParser : public ParserBase {
+class PreParser : public ParserBase<PreParserTraits> {
  public:
+  typedef PreParserIdentifier Identifier;
+  typedef PreParserExpression Expression;
+
   enum PreParseResult {
     kPreParseStackOverflow,
     kPreParseSuccess
@@ -240,7 +486,7 @@ class PreParser : public ParserBase {
   PreParser(Scanner* scanner,
             ParserRecorder* log,
             uintptr_t stack_limit)
-      : ParserBase(scanner, stack_limit),
+      : ParserBase<PreParserTraits>(scanner, stack_limit, this),
         log_(log),
         scope_(NULL),
         parenthesized_function_(false) { }
@@ -278,6 +524,8 @@ class PreParser : public ParserBase {
                                       ParserRecorder* log);
 
  private:
+  friend class PreParserTraits;
+
   // These types form an algebra over syntactic categories that is just
   // rich enough to let us recognize and propagate the constructs that
   // are either being counted in the preparser data, or is important
@@ -300,142 +548,6 @@ class PreParser : public ParserBase {
     kHasNoInitializers
   };
 
-  class Expression;
-
-  class Identifier {
-   public:
-    static Identifier Default() {
-      return Identifier(kUnknownIdentifier);
-    }
-    static Identifier Eval()  {
-      return Identifier(kEvalIdentifier);
-    }
-    static Identifier Arguments()  {
-      return Identifier(kArgumentsIdentifier);
-    }
-    static Identifier FutureReserved()  {
-      return Identifier(kFutureReservedIdentifier);
-    }
-    static Identifier FutureStrictReserved()  {
-      return Identifier(kFutureStrictReservedIdentifier);
-    }
-    static Identifier Yield()  {
-      return Identifier(kYieldIdentifier);
-    }
-    bool IsEval() { return type_ == kEvalIdentifier; }
-    bool IsArguments() { return type_ == kArgumentsIdentifier; }
-    bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
-    bool IsYield() { return type_ == kYieldIdentifier; }
-    bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
-    bool IsFutureStrictReserved() {
-      return type_ == kFutureStrictReservedIdentifier;
-    }
-    bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; }
-
-   private:
-    enum Type {
-      kUnknownIdentifier,
-      kFutureReservedIdentifier,
-      kFutureStrictReservedIdentifier,
-      kYieldIdentifier,
-      kEvalIdentifier,
-      kArgumentsIdentifier
-    };
-    explicit Identifier(Type type) : type_(type) { }
-    Type type_;
-
-    friend class Expression;
-  };
-
-  // Bits 0 and 1 are used to identify the type of expression:
-  // If bit 0 is set, it's an identifier.
-  // if bit 1 is set, it's a string literal.
-  // If neither is set, it's no particular type, and both set isn't
-  // use yet.
-  class Expression {
-   public:
-    static Expression Default() {
-      return Expression(kUnknownExpression);
-    }
-
-    static Expression FromIdentifier(Identifier id) {
-      return Expression(kIdentifierFlag | (id.type_ << kIdentifierShift));
-    }
-
-    static Expression StringLiteral() {
-      return Expression(kUnknownStringLiteral);
-    }
-
-    static Expression UseStrictStringLiteral() {
-      return Expression(kUseStrictString);
-    }
-
-    static Expression This() {
-      return Expression(kThisExpression);
-    }
-
-    static Expression ThisProperty() {
-      return Expression(kThisPropertyExpression);
-    }
-
-    static Expression StrictFunction() {
-      return Expression(kStrictFunctionExpression);
-    }
-
-    bool IsIdentifier() {
-      return (code_ & kIdentifierFlag) != 0;
-    }
-
-    // Only works corretly if it is actually an identifier expression.
-    PreParser::Identifier AsIdentifier() {
-      return PreParser::Identifier(
-          static_cast<PreParser::Identifier::Type>(code_ >> kIdentifierShift));
-    }
-
-    bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; }
-
-    bool IsUseStrictLiteral() {
-      return (code_ & kStringLiteralMask) == kUseStrictString;
-    }
-
-    bool IsThis() {
-      return code_ == kThisExpression;
-    }
-
-    bool IsThisProperty() {
-      return code_ == kThisPropertyExpression;
-    }
-
-    bool IsStrictFunction() {
-      return code_ == kStrictFunctionExpression;
-    }
-
-   private:
-    // First two/three bits are used as flags.
-    // Bit 0 and 1 represent identifiers or strings literals, and are
-    // mutually exclusive, but can both be absent.
-    enum  {
-      kUnknownExpression = 0,
-      // Identifiers
-      kIdentifierFlag = 1,  // Used to detect labels.
-      kIdentifierShift = 3,
-
-      kStringLiteralFlag = 2,  // Used to detect directive prologue.
-      kUnknownStringLiteral = kStringLiteralFlag,
-      kUseStrictString = kStringLiteralFlag | 8,
-      kStringLiteralMask = kUseStrictString,
-
-      // Below here applies if neither identifier nor string literal.
-      kThisExpression = 4,
-      kThisPropertyExpression = 8,
-      kStrictFunctionExpression = 12
-    };
-
-    explicit Expression(int expression_code) : code_(expression_code) { }
-
-    int code_;
-  };
-
   class Statement {
    public:
     static Statement Default() {
@@ -546,27 +658,6 @@ class PreParser : public ParserBase {
     bool is_generator_;
   };
 
-  // Report syntax error
-  void ReportMessageAt(Scanner::Location location,
-                       const char* message,
-                       Vector<const char*> args) {
-    ReportMessageAt(location.beg_pos,
-                    location.end_pos,
-                    message,
-                    args.length() > 0 ? args[0] : NULL);
-  }
-  void ReportMessageAt(Scanner::Location location,
-                       const char* type,
-                       const char* name_opt) {
-    log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
-  }
-  void ReportMessageAt(int start_pos,
-                       int end_pos,
-                       const char* type,
-                       const char* name_opt) {
-    log_->LogMessage(start_pos, end_pos, type, name_opt);
-  }
-
   // All ParseXXX functions take as the last argument an *ok parameter
   // which is set to false if parsing failed; it is unchanged otherwise.
   // By making the 'exception handling' explicit, we are forced to check
@@ -622,18 +713,8 @@ class PreParser : public ParserBase {
       bool* ok);
   void ParseLazyFunctionLiteralBody(bool* ok);
 
-  Identifier ParseIdentifier(AllowEvalOrArgumentsAsIdentifier, bool* ok);
-  Identifier ParseIdentifierOrStrictReservedWord(bool* is_strict_reserved,
-                                                 bool* ok);
-  Identifier ParseIdentifierName(bool* ok);
-  Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
-                                           bool* is_set,
-                                           bool* ok);
-
   // Logs the currently parsed literal as a symbol in the preparser data.
   void LogSymbol();
-  // Log the currently parsed identifier.
-  Identifier GetIdentifierSymbol();
   // Log the currently parsed string literal.
   Expression GetStringSymbol();
 
@@ -641,10 +722,6 @@ class PreParser : public ParserBase {
     scope_->set_language_mode(language_mode);
   }
 
-  virtual bool is_classic_mode() {
-    return scope_->language_mode() == CLASSIC_MODE;
-  }
-
   bool is_extended_mode() {
     return scope_->language_mode() == EXTENDED_MODE;
   }
@@ -658,6 +735,154 @@ class PreParser : public ParserBase {
   bool parenthesized_function_;
 };
 
+
+template<class Traits>
+void ParserBase<Traits>::ReportUnexpectedToken(Token::Value token) {
+  // We don't report stack overflows here, to avoid increasing the
+  // stack depth even further.  Instead we report it after parsing is
+  // over, in ParseProgram.
+  if (token == Token::ILLEGAL && stack_overflow()) {
+    return;
+  }
+  Scanner::Location source_location = scanner()->location();
+
+  // Four of the tokens are treated specially
+  switch (token) {
+    case Token::EOS:
+      return ReportMessageAt(source_location, "unexpected_eos");
+    case Token::NUMBER:
+      return ReportMessageAt(source_location, "unexpected_token_number");
+    case Token::STRING:
+      return ReportMessageAt(source_location, "unexpected_token_string");
+    case Token::IDENTIFIER:
+      return ReportMessageAt(source_location, "unexpected_token_identifier");
+    case Token::FUTURE_RESERVED_WORD:
+      return ReportMessageAt(source_location, "unexpected_reserved");
+    case Token::YIELD:
+    case Token::FUTURE_STRICT_RESERVED_WORD:
+      return ReportMessageAt(
+          source_location,
+          this->is_classic_mode() ? "unexpected_token_identifier"
+                                  : "unexpected_strict_reserved");
+    default:
+      const char* name = Token::String(token);
+      ASSERT(name != NULL);
+      Traits::ReportMessageAt(
+          source_location, "unexpected_token", Vector<const char*>(&name, 1));
+  }
+}
+
+
+template<class Traits>
+typename Traits::IdentifierType ParserBase<Traits>::ParseIdentifier(
+    AllowEvalOrArgumentsAsIdentifier allow_eval_or_arguments,
+    bool* ok) {
+  Token::Value next = Next();
+  if (next == Token::IDENTIFIER) {
+    typename Traits::IdentifierType name = this->GetSymbol();
+    if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
+        !this->is_classic_mode() && this->IsEvalOrArguments(name)) {
+      ReportMessageAt(scanner()->location(), "strict_eval_arguments");
+      *ok = false;
+    }
+    return name;
+  } else if (this->is_classic_mode() &&
+             (next == Token::FUTURE_STRICT_RESERVED_WORD ||
+              (next == Token::YIELD && !this->is_generator()))) {
+    return this->GetSymbol();
+  } else {
+    this->ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+}
+
+
+template <class Traits>
+typename Traits::IdentifierType ParserBase<
+    Traits>::ParseIdentifierOrStrictReservedWord(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::YIELD && !this->is_generator())) {
+    *is_strict_reserved = true;
+  } else {
+    ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+  return this->GetSymbol();
+}
+
+
+template <class Traits>
+typename Traits::IdentifierType ParserBase<Traits>::ParseIdentifierName(
+    bool* ok) {
+  Token::Value next = Next();
+  if (next != Token::IDENTIFIER && next != Token::FUTURE_RESERVED_WORD &&
+      next != Token::FUTURE_STRICT_RESERVED_WORD && !Token::IsKeyword(next)) {
+    this->ReportUnexpectedToken(next);
+    *ok = false;
+    return Traits::EmptyIdentifier();
+  }
+  return this->GetSymbol();
+}
+
+
+template <class Traits>
+typename Traits::IdentifierType
+ParserBase<Traits>::ParseIdentifierNameOrGetOrSet(bool* is_get,
+                                                  bool* is_set,
+                                                  bool* ok) {
+  typename Traits::IdentifierType result = ParseIdentifierName(ok);
+  if (!*ok) return Traits::EmptyIdentifier();
+  if (scanner()->is_literal_ascii() &&
+      scanner()->literal_length() == 3) {
+    const char* token = scanner()->literal_ascii_string().start();
+    *is_get = strncmp(token, "get", 3) == 0;
+    *is_set = !*is_get && strncmp(token, "set", 3) == 0;
+  }
+  return result;
+}
+
+
+template <typename Traits>
+void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
+    Token::Value property,
+    PropertyKind type,
+    bool* ok) {
+  int old;
+  if (property == Token::NUMBER) {
+    old = finder_.AddNumber(scanner()->literal_ascii_string(), type);
+  } else if (scanner()->is_literal_ascii()) {
+    old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type);
+  } else {
+    old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type);
+  }
+  PropertyKind old_type = static_cast<PropertyKind>(old);
+  if (HasConflict(old_type, type)) {
+    if (IsDataDataConflict(old_type, type)) {
+      // Both are data properties.
+      if (language_mode_ == CLASSIC_MODE) return;
+      parser()->ReportMessageAt(scanner()->location(),
+                               "strict_duplicate_property");
+    } else if (IsDataAccessorConflict(old_type, type)) {
+      // Both a data and an accessor property with the same name.
+      parser()->ReportMessageAt(scanner()->location(),
+                               "accessor_data_property");
+    } else {
+      ASSERT(IsAccessorAccessorConflict(old_type, type));
+      // Both accessors of the same type.
+      parser()->ReportMessageAt(scanner()->location(),
+                               "accessor_get_set");
+    }
+    *ok = false;
+  }
+}
+
+
 } }  // v8::internal
 
 #endif  // V8_PREPARSER_H
index 22d5056..f3f238c 100644 (file)
@@ -1108,8 +1108,9 @@ enum ParserSyncTestResult {
   kError
 };
 
-
-void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
+template <typename Traits>
+void SetParserFlags(i::ParserBase<Traits>* parser,
+                    i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
   parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
   parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));