preparser.h 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef V8_PREPARSER_H
#define V8_PREPARSER_H

namespace v8 {
namespace preparser {

// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
36
// See preparse-data-format.h for the data format.
37 38 39 40 41 42 43 44 45 46

// The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way.
// The grammar check is only performed in order to understand the program
// sufficiently to deduce some information about it, that can be used
// to speed up later parsing. Finding errors is not the goal of pre-parsing,
// 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.

47 48
namespace i = v8::internal;

49 50
class PreParser {
 public:
51 52 53 54 55
  enum PreParseResult {
    kPreParseStackOverflow,
    kPreParseSuccess
  };

56 57 58 59 60 61
  ~PreParser() { }

  // Pre-parse the program from the character stream; returns true on
  // success (even if parsing failed, the pre-parse data successfully
  // captured the syntax error), and false if a stack-overflow happened
  // during parsing.
62 63 64 65 66
  static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner,
                                        i::ParserRecorder* log,
                                        bool allow_lazy,
                                        uintptr_t stack_limit) {
    return PreParser(scanner, log, stack_limit, allow_lazy).PreParse();
67 68 69 70 71 72 73 74
  }

 private:
  enum ScopeType {
    kTopLevelScope,
    kFunctionScope
  };

75 76 77 78 79 80 81 82
  // Types that allow us to recognize simple this-property assignments.
  // A simple this-property assignment is a statement on the form
  // "this.propertyName = {primitive constant or function parameter name);"
  // where propertyName isn't "__proto__".
  // The result is only relevant if the function body contains only
  // simple this-property assignments.

  enum StatementType {
83 84 85
    kUnknownStatement,
    kStringLiteralExpressionStatement,
    kUseStrictExpressionStatement
86 87 88 89 90 91
  };

  enum ExpressionType {
    kUnknownExpression,
    kIdentifierExpression,  // Used to detect labels.
    kThisExpression,
92 93 94
    kThisPropertyExpression,
    kStringLiteralExpression,
    kUseStrictString
95 96 97 98 99 100 101
  };

  enum IdentifierType {
    kUnknownIdentifier
  };

  enum SourceElementTypes {
102 103 104
    kUnknownSourceElements,
    kDirectivePrologue,
    kUseStrictDirective
105 106 107 108 109 110 111 112
  };

  typedef int SourceElements;
  typedef int Expression;
  typedef int Statement;
  typedef int Identifier;
  typedef int Arguments;

113 114 115 116 117 118 119 120
  class Scope {
   public:
    Scope(Scope** variable, ScopeType type)
        : variable_(variable),
          prev_(*variable),
          type_(type),
          materialized_literal_count_(0),
          expected_properties_(0),
121 122
          with_nesting_count_(0),
          strict_((prev_ != NULL) && prev_->is_strict()) {
123 124 125 126 127 128 129 130 131
      *variable = this;
    }
    ~Scope() { *variable_ = prev_; }
    void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
    void AddProperty() { expected_properties_++; }
    ScopeType type() { return type_; }
    int expected_properties() { return expected_properties_; }
    int materialized_literal_count() { return materialized_literal_count_; }
    bool IsInsideWith() { return with_nesting_count_ != 0; }
132 133
    bool is_strict() { return strict_; }
    void set_strict() { strict_ = true; }
134 135 136 137 138 139 140 141 142 143
    void EnterWith() { with_nesting_count_++; }
    void LeaveWith() { with_nesting_count_--; }

   private:
    Scope** const variable_;
    Scope* const prev_;
    const ScopeType type_;
    int materialized_literal_count_;
    int expected_properties_;
    int with_nesting_count_;
144
    bool strict_;
145 146
  };

147 148 149 150 151 152 153 154 155 156
  // Private constructor only used in PreParseProgram.
  PreParser(i::JavaScriptScanner* scanner,
            i::ParserRecorder* log,
            uintptr_t stack_limit,
            bool allow_lazy)
      : scanner_(scanner),
        log_(log),
        scope_(NULL),
        stack_limit_(stack_limit),
        stack_overflow_(false),
157 158
        allow_lazy_(true),
        parenthesized_function_(false) { }
159 160 161 162 163 164

  // Preparse the program. Only called in PreParseProgram after creating
  // the instance.
  PreParseResult PreParse() {
    Scope top_scope(&scope_, kTopLevelScope);
    bool ok = true;
165
    int start_position = scanner_->peek_location().beg_pos;
166 167 168 169
    ParseSourceElements(i::Token::EOS, &ok);
    if (stack_overflow_) return kPreParseStackOverflow;
    if (!ok) {
      ReportUnexpectedToken(scanner_->current_token());
170 171
    } else if (scope_->is_strict()) {
      CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
172 173 174
    }
    return kPreParseSuccess;
  }
175 176

  // Report syntax error
177
  void ReportUnexpectedToken(i::Token::Value token);
178 179 180 181 182 183 184
  void ReportMessageAt(int start_pos,
                       int end_pos,
                       const char* type,
                       const char* name_opt) {
    log_->LogMessage(start_pos, end_pos, type, name_opt);
  }

185 186
  void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
  // 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
  // for failure at the call sites.
  SourceElements ParseSourceElements(int end_token, bool* ok);
  Statement ParseStatement(bool* ok);
  Statement ParseFunctionDeclaration(bool* ok);
  Statement ParseNativeDeclaration(bool* ok);
  Statement ParseBlock(bool* ok);
  Statement ParseVariableStatement(bool* ok);
  Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
  Statement ParseExpressionOrLabelledStatement(bool* ok);
  Statement ParseIfStatement(bool* ok);
  Statement ParseContinueStatement(bool* ok);
  Statement ParseBreakStatement(bool* ok);
  Statement ParseReturnStatement(bool* ok);
  Statement ParseWithStatement(bool* ok);
  Statement ParseSwitchStatement(bool* ok);
  Statement ParseDoWhileStatement(bool* ok);
  Statement ParseWhileStatement(bool* ok);
  Statement ParseForStatement(bool* ok);
  Statement ParseThrowStatement(bool* ok);
  Statement ParseTryStatement(bool* ok);
  Statement ParseDebuggerStatement(bool* ok);

  Expression ParseExpression(bool accept_IN, bool* ok);
  Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
  Expression ParseConditionalExpression(bool accept_IN, bool* ok);
  Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
  Expression ParseUnaryExpression(bool* ok);
  Expression ParsePostfixExpression(bool* ok);
  Expression ParseLeftHandSideExpression(bool* ok);
  Expression ParseNewExpression(bool* ok);
  Expression ParseMemberExpression(bool* ok);
221
  Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
222 223 224 225 226 227 228 229 230 231 232 233 234
  Expression ParsePrimaryExpression(bool* ok);
  Expression ParseArrayLiteral(bool* ok);
  Expression ParseObjectLiteral(bool* ok);
  Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
  Expression ParseV8Intrinsic(bool* ok);

  Arguments ParseArguments(bool* ok);
  Expression ParseFunctionLiteral(bool* ok);

  Identifier ParseIdentifier(bool* ok);
  Identifier ParseIdentifierName(bool* ok);
  Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);

235 236 237
  // Logs the currently parsed literal as a symbol in the preparser data.
  void LogSymbol();
  // Log the currently parsed identifier.
238
  Identifier GetIdentifierSymbol();
239
  // Log the currently parsed string literal.
240 241
  Expression GetStringSymbol();

242 243 244 245
  i::Token::Value peek() {
    if (stack_overflow_) return i::Token::ILLEGAL;
    return scanner_->peek();
  }
246

247
  i::Token::Value Next() {
248 249 250 251 252 253 254 255 256 257 258
    if (stack_overflow_) return i::Token::ILLEGAL;
    {
      int marker;
      if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
        // Further calls to peek/Next will return illegal token.
        // The current one will still be returned. It might already
        // have been seen using peek.
        stack_overflow_ = true;
      }
    }
    return scanner_->Next();
259 260
  }

261 262
  bool peek_any_identifier();

263 264 265 266 267 268
  void set_strict_mode() {
    scope_->set_strict();
  }

  bool is_strict_mode() { return scope_->is_strict(); }

269
  void Consume(i::Token::Value token) { Next(); }
270

271
  void Expect(i::Token::Value token, bool* ok) {
272 273 274 275 276
    if (Next() != token) {
      *ok = false;
    }
  }

277 278
  bool Check(i::Token::Value token) {
    i::Token::Value next = peek();
279 280 281 282 283 284 285 286
    if (next == token) {
      Consume(next);
      return true;
    }
    return false;
  }
  void ExpectSemicolon(bool* ok);

287
  static int Precedence(i::Token::Value tok, bool accept_IN);
288

289 290
  i::JavaScriptScanner* scanner_;
  i::ParserRecorder* log_;
291
  Scope* scope_;
292 293
  uintptr_t stack_limit_;
  bool stack_overflow_;
294
  bool allow_lazy_;
295
  bool parenthesized_function_;
296
};
297
} }  // v8::preparser
298 299

#endif  // V8_PREPARSER_H