Home | History | Annotate | Download | only in src
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_PREPARSER_H
     29 #define V8_PREPARSER_H
     30 
     31 namespace v8 {
     32 namespace preparser {
     33 
     34 // Preparsing checks a JavaScript program and emits preparse-data that helps
     35 // a later parsing to be faster.
     36 // See preparse-data.h for the data.
     37 
     38 // The PreParser checks that the syntax follows the grammar for JavaScript,
     39 // and collects some information about the program along the way.
     40 // The grammar check is only performed in order to understand the program
     41 // sufficiently to deduce some information about it, that can be used
     42 // to speed up later parsing. Finding errors is not the goal of pre-parsing,
     43 // rather it is to speed up properly written and correct programs.
     44 // That means that contextual checks (like a label being declared where
     45 // it is used) are generally omitted.
     46 
     47 namespace i = v8::internal;
     48 
     49 class PreParser {
     50  public:
     51   enum PreParseResult {
     52     kPreParseStackOverflow,
     53     kPreParseSuccess
     54   };
     55 
     56   ~PreParser() { }
     57 
     58   // Pre-parse the program from the character stream; returns true on
     59   // success (even if parsing failed, the pre-parse data successfully
     60   // captured the syntax error), and false if a stack-overflow happened
     61   // during parsing.
     62   static PreParseResult PreParseProgram(i::JavaScriptScanner* scanner,
     63                                         i::ParserRecorder* log,
     64                                         bool allow_lazy,
     65                                         uintptr_t stack_limit) {
     66     return PreParser(scanner, log, stack_limit, allow_lazy).PreParse();
     67   }
     68 
     69  private:
     70   enum ScopeType {
     71     kTopLevelScope,
     72     kFunctionScope
     73   };
     74 
     75   // Types that allow us to recognize simple this-property assignments.
     76   // A simple this-property assignment is a statement on the form
     77   // "this.propertyName = {primitive constant or function parameter name);"
     78   // where propertyName isn't "__proto__".
     79   // The result is only relevant if the function body contains only
     80   // simple this-property assignments.
     81 
     82   enum StatementType {
     83     kUnknownStatement
     84   };
     85 
     86   enum ExpressionType {
     87     kUnknownExpression,
     88     kIdentifierExpression,  // Used to detect labels.
     89     kThisExpression,
     90     kThisPropertyExpression
     91   };
     92 
     93   enum IdentifierType {
     94     kUnknownIdentifier
     95   };
     96 
     97   enum SourceElementTypes {
     98     kUnknownSourceElements
     99   };
    100 
    101   typedef int SourceElements;
    102   typedef int Expression;
    103   typedef int Statement;
    104   typedef int Identifier;
    105   typedef int Arguments;
    106 
    107   class Scope {
    108    public:
    109     Scope(Scope** variable, ScopeType type)
    110         : variable_(variable),
    111           prev_(*variable),
    112           type_(type),
    113           materialized_literal_count_(0),
    114           expected_properties_(0),
    115           with_nesting_count_(0) {
    116       *variable = this;
    117     }
    118     ~Scope() { *variable_ = prev_; }
    119     void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
    120     void AddProperty() { expected_properties_++; }
    121     ScopeType type() { return type_; }
    122     int expected_properties() { return expected_properties_; }
    123     int materialized_literal_count() { return materialized_literal_count_; }
    124     bool IsInsideWith() { return with_nesting_count_ != 0; }
    125     void EnterWith() { with_nesting_count_++; }
    126     void LeaveWith() { with_nesting_count_--; }
    127 
    128    private:
    129     Scope** const variable_;
    130     Scope* const prev_;
    131     const ScopeType type_;
    132     int materialized_literal_count_;
    133     int expected_properties_;
    134     int with_nesting_count_;
    135   };
    136 
    137   // Private constructor only used in PreParseProgram.
    138   PreParser(i::JavaScriptScanner* scanner,
    139             i::ParserRecorder* log,
    140             uintptr_t stack_limit,
    141             bool allow_lazy)
    142       : scanner_(scanner),
    143         log_(log),
    144         scope_(NULL),
    145         stack_limit_(stack_limit),
    146         stack_overflow_(false),
    147         allow_lazy_(true),
    148         parenthesized_function_(false) { }
    149 
    150   // Preparse the program. Only called in PreParseProgram after creating
    151   // the instance.
    152   PreParseResult PreParse() {
    153     Scope top_scope(&scope_, kTopLevelScope);
    154     bool ok = true;
    155     ParseSourceElements(i::Token::EOS, &ok);
    156     if (stack_overflow_) return kPreParseStackOverflow;
    157     if (!ok) {
    158       ReportUnexpectedToken(scanner_->current_token());
    159     }
    160     return kPreParseSuccess;
    161   }
    162 
    163   // Report syntax error
    164   void ReportUnexpectedToken(i::Token::Value token);
    165   void ReportMessageAt(int start_pos,
    166                        int end_pos,
    167                        const char* type,
    168                        const char* name_opt) {
    169     log_->LogMessage(start_pos, end_pos, type, name_opt);
    170   }
    171 
    172   // All ParseXXX functions take as the last argument an *ok parameter
    173   // which is set to false if parsing failed; it is unchanged otherwise.
    174   // By making the 'exception handling' explicit, we are forced to check
    175   // for failure at the call sites.
    176   SourceElements ParseSourceElements(int end_token, bool* ok);
    177   Statement ParseStatement(bool* ok);
    178   Statement ParseFunctionDeclaration(bool* ok);
    179   Statement ParseNativeDeclaration(bool* ok);
    180   Statement ParseBlock(bool* ok);
    181   Statement ParseVariableStatement(bool* ok);
    182   Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
    183   Statement ParseExpressionOrLabelledStatement(bool* ok);
    184   Statement ParseIfStatement(bool* ok);
    185   Statement ParseContinueStatement(bool* ok);
    186   Statement ParseBreakStatement(bool* ok);
    187   Statement ParseReturnStatement(bool* ok);
    188   Statement ParseWithStatement(bool* ok);
    189   Statement ParseSwitchStatement(bool* ok);
    190   Statement ParseDoWhileStatement(bool* ok);
    191   Statement ParseWhileStatement(bool* ok);
    192   Statement ParseForStatement(bool* ok);
    193   Statement ParseThrowStatement(bool* ok);
    194   Statement ParseTryStatement(bool* ok);
    195   Statement ParseDebuggerStatement(bool* ok);
    196 
    197   Expression ParseExpression(bool accept_IN, bool* ok);
    198   Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
    199   Expression ParseConditionalExpression(bool accept_IN, bool* ok);
    200   Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
    201   Expression ParseUnaryExpression(bool* ok);
    202   Expression ParsePostfixExpression(bool* ok);
    203   Expression ParseLeftHandSideExpression(bool* ok);
    204   Expression ParseNewExpression(bool* ok);
    205   Expression ParseMemberExpression(bool* ok);
    206   Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
    207   Expression ParsePrimaryExpression(bool* ok);
    208   Expression ParseArrayLiteral(bool* ok);
    209   Expression ParseObjectLiteral(bool* ok);
    210   Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
    211   Expression ParseV8Intrinsic(bool* ok);
    212 
    213   Arguments ParseArguments(bool* ok);
    214   Expression ParseFunctionLiteral(bool* ok);
    215 
    216   Identifier ParseIdentifier(bool* ok);
    217   Identifier ParseIdentifierName(bool* ok);
    218   Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
    219 
    220   // Logs the currently parsed literal as a symbol in the preparser data.
    221   void LogSymbol();
    222   // Log the currently parsed identifier.
    223   Identifier GetIdentifierSymbol();
    224   // Log the currently parsed string literal.
    225   Expression GetStringSymbol();
    226 
    227   i::Token::Value peek() {
    228     if (stack_overflow_) return i::Token::ILLEGAL;
    229     return scanner_->peek();
    230   }
    231 
    232   i::Token::Value Next() {
    233     if (stack_overflow_) return i::Token::ILLEGAL;
    234     {
    235       int marker;
    236       if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
    237         // Further calls to peek/Next will return illegal token.
    238         // The current one will still be returned. It might already
    239         // have been seen using peek.
    240         stack_overflow_ = true;
    241       }
    242     }
    243     return scanner_->Next();
    244   }
    245 
    246   bool peek_any_identifier();
    247 
    248   void Consume(i::Token::Value token) { Next(); }
    249 
    250   void Expect(i::Token::Value token, bool* ok) {
    251     if (Next() != token) {
    252       *ok = false;
    253     }
    254   }
    255 
    256   bool Check(i::Token::Value token) {
    257     i::Token::Value next = peek();
    258     if (next == token) {
    259       Consume(next);
    260       return true;
    261     }
    262     return false;
    263   }
    264   void ExpectSemicolon(bool* ok);
    265 
    266   static int Precedence(i::Token::Value tok, bool accept_IN);
    267 
    268   i::JavaScriptScanner* scanner_;
    269   i::ParserRecorder* log_;
    270   Scope* scope_;
    271   uintptr_t stack_limit_;
    272   bool stack_overflow_;
    273   bool allow_lazy_;
    274   bool parenthesized_function_;
    275 };
    276 } }  // v8::preparser
    277 
    278 #endif  // V8_PREPARSER_H
    279