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