• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~PreParser()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.
PreParseProgram(i::JavaScriptScanner * scanner,i::ParserRecorder * log,bool allow_lazy,uintptr_t stack_limit)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:
Scope(Scope ** variable,ScopeType type)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     }
~Scope()118     ~Scope() { *variable_ = prev_; }
NextMaterializedLiteralIndex()119     void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
AddProperty()120     void AddProperty() { expected_properties_++; }
type()121     ScopeType type() { return type_; }
expected_properties()122     int expected_properties() { return expected_properties_; }
materialized_literal_count()123     int materialized_literal_count() { return materialized_literal_count_; }
IsInsideWith()124     bool IsInsideWith() { return with_nesting_count_ != 0; }
EnterWith()125     void EnterWith() { with_nesting_count_++; }
LeaveWith()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.
PreParser(i::JavaScriptScanner * scanner,i::ParserRecorder * log,uintptr_t stack_limit,bool allow_lazy)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.
PreParse()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);
ReportMessageAt(int start_pos,int end_pos,const char * type,const char * name_opt)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 
peek()227   i::Token::Value peek() {
228     if (stack_overflow_) return i::Token::ILLEGAL;
229     return scanner_->peek();
230   }
231 
Next()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 
Consume(i::Token::Value token)248   void Consume(i::Token::Value token) { Next(); }
249 
Expect(i::Token::Value token,bool * ok)250   void Expect(i::Token::Value token, bool* ok) {
251     if (Next() != token) {
252       *ok = false;
253     }
254   }
255 
Check(i::Token::Value token)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