blob: 536e6d4f431050037970bd725126f8e9569a48eb [file] [log] [blame]
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001// 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
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080031namespace v8 {
32namespace preparser {
33
34// Preparsing checks a JavaScript program and emits preparse-data that helps
35// a later parsing to be faster.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080036// See preparse-data.h for the data.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080037
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
47namespace i = v8::internal;
48
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080049class PreParser {
50 public:
Ben Murdochb0fe1622011-05-05 13:52:32 +010051 enum PreParseResult {
52 kPreParseStackOverflow,
53 kPreParseSuccess
54 };
55
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080056 ~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.
Ben Murdochb0fe1622011-05-05 13:52:32 +010062 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();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -080067 }
68
69 private:
70 enum ScopeType {
71 kTopLevelScope,
72 kFunctionScope
73 };
74
Ben Murdochb0fe1622011-05-05 13:52:32 +010075 // 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
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800107 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
Ben Murdochb0fe1622011-05-05 13:52:32 +0100137 // 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
149 // Preparse the program. Only called in PreParseProgram after creating
150 // the instance.
151 PreParseResult PreParse() {
152 Scope top_scope(&scope_, kTopLevelScope);
153 bool ok = true;
154 ParseSourceElements(i::Token::EOS, &ok);
155 if (stack_overflow_) return kPreParseStackOverflow;
156 if (!ok) {
157 ReportUnexpectedToken(scanner_->current_token());
158 }
159 return kPreParseSuccess;
160 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800161
162 // Report syntax error
163 void ReportUnexpectedToken(i::Token::Value token);
164 void ReportMessageAt(int start_pos,
165 int end_pos,
166 const char* type,
167 const char* name_opt) {
168 log_->LogMessage(start_pos, end_pos, type, name_opt);
169 }
170
171 // All ParseXXX functions take as the last argument an *ok parameter
172 // which is set to false if parsing failed; it is unchanged otherwise.
173 // By making the 'exception handling' explicit, we are forced to check
174 // for failure at the call sites.
175 SourceElements ParseSourceElements(int end_token, bool* ok);
176 Statement ParseStatement(bool* ok);
177 Statement ParseFunctionDeclaration(bool* ok);
178 Statement ParseNativeDeclaration(bool* ok);
179 Statement ParseBlock(bool* ok);
180 Statement ParseVariableStatement(bool* ok);
181 Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
182 Statement ParseExpressionOrLabelledStatement(bool* ok);
183 Statement ParseIfStatement(bool* ok);
184 Statement ParseContinueStatement(bool* ok);
185 Statement ParseBreakStatement(bool* ok);
186 Statement ParseReturnStatement(bool* ok);
187 Statement ParseWithStatement(bool* ok);
188 Statement ParseSwitchStatement(bool* ok);
189 Statement ParseDoWhileStatement(bool* ok);
190 Statement ParseWhileStatement(bool* ok);
191 Statement ParseForStatement(bool* ok);
192 Statement ParseThrowStatement(bool* ok);
193 Statement ParseTryStatement(bool* ok);
194 Statement ParseDebuggerStatement(bool* ok);
195
196 Expression ParseExpression(bool accept_IN, bool* ok);
197 Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
198 Expression ParseConditionalExpression(bool accept_IN, bool* ok);
199 Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
200 Expression ParseUnaryExpression(bool* ok);
201 Expression ParsePostfixExpression(bool* ok);
202 Expression ParseLeftHandSideExpression(bool* ok);
203 Expression ParseNewExpression(bool* ok);
204 Expression ParseMemberExpression(bool* ok);
205 Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
206 Expression ParsePrimaryExpression(bool* ok);
207 Expression ParseArrayLiteral(bool* ok);
208 Expression ParseObjectLiteral(bool* ok);
209 Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
210 Expression ParseV8Intrinsic(bool* ok);
211
212 Arguments ParseArguments(bool* ok);
213 Expression ParseFunctionLiteral(bool* ok);
214
215 Identifier ParseIdentifier(bool* ok);
216 Identifier ParseIdentifierName(bool* ok);
217 Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
218
Steve Block9fac8402011-05-12 15:51:54 +0100219 // Logs the currently parsed literal as a symbol in the preparser data.
220 void LogSymbol();
221 // Log the currently parsed identifier.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800222 Identifier GetIdentifierSymbol();
Steve Block9fac8402011-05-12 15:51:54 +0100223 // Log the currently parsed string literal.
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800224 Expression GetStringSymbol();
225
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226 i::Token::Value peek() {
227 if (stack_overflow_) return i::Token::ILLEGAL;
228 return scanner_->peek();
229 }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800230
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800231 i::Token::Value Next() {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100232 if (stack_overflow_) return i::Token::ILLEGAL;
233 {
234 int marker;
235 if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
236 // Further calls to peek/Next will return illegal token.
237 // The current one will still be returned. It might already
238 // have been seen using peek.
239 stack_overflow_ = true;
240 }
241 }
242 return scanner_->Next();
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800243 }
244
Ben Murdochb0fe1622011-05-05 13:52:32 +0100245 void Consume(i::Token::Value token) { Next(); }
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800246
247 void Expect(i::Token::Value token, bool* ok) {
248 if (Next() != token) {
249 *ok = false;
250 }
251 }
252
253 bool Check(i::Token::Value token) {
254 i::Token::Value next = peek();
255 if (next == token) {
256 Consume(next);
257 return true;
258 }
259 return false;
260 }
261 void ExpectSemicolon(bool* ok);
262
263 static int Precedence(i::Token::Value tok, bool accept_IN);
264
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800265 i::JavaScriptScanner* scanner_;
266 i::ParserRecorder* log_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800267 Scope* scope_;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100268 uintptr_t stack_limit_;
269 bool stack_overflow_;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800270 bool allow_lazy_;
271};
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800272} } // v8::preparser
273
274#endif // V8_PREPARSER_H