blob: 893b575198bf0cf0cdd775d458ca310d1cddae76 [file] [log] [blame]
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00001// 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
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000031namespace v8 {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000032namespace preparser {
33
34// Preparsing checks a JavaScript program and emits preparse-data that helps
35// a later parsing to be faster.
ager@chromium.orgbeb25712010-11-29 08:02:25 +000036// See preparse-data.h for the data.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000037
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
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +000047namespace i = v8::internal;
48
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000049class PreParser {
50 public:
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051 enum PreParseResult {
52 kPreParseStackOverflow,
53 kPreParseSuccess
54 };
55
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000056 ~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.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000062 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();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000067 }
68
69 private:
70 enum ScopeType {
71 kTopLevelScope,
72 kFunctionScope
73 };
74
kasperl@chromium.orga5551262010-12-07 12:49:48 +000075 // 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
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000107 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
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000137 // 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 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000161
162 // Report syntax error
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000163 void ReportUnexpectedToken(i::Token::Value token);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000164 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);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000205 Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000206 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
219 Identifier GetIdentifierSymbol();
220 unsigned int HexDigitValue(char digit);
221 Expression GetStringSymbol();
222
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000223 i::Token::Value peek() {
224 if (stack_overflow_) return i::Token::ILLEGAL;
225 return scanner_->peek();
226 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000227
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000228 i::Token::Value Next() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000229 if (stack_overflow_) return i::Token::ILLEGAL;
230 {
231 int marker;
232 if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
233 // Further calls to peek/Next will return illegal token.
234 // The current one will still be returned. It might already
235 // have been seen using peek.
236 stack_overflow_ = true;
237 }
238 }
239 return scanner_->Next();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000240 }
241
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000242 void Consume(i::Token::Value token) { Next(); }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000243
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000244 void Expect(i::Token::Value token, bool* ok) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000245 if (Next() != token) {
246 *ok = false;
247 }
248 }
249
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000250 bool Check(i::Token::Value token) {
251 i::Token::Value next = peek();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000252 if (next == token) {
253 Consume(next);
254 return true;
255 }
256 return false;
257 }
258 void ExpectSemicolon(bool* ok);
259
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000260 static int Precedence(i::Token::Value tok, bool accept_IN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000261
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000262 i::JavaScriptScanner* scanner_;
263 i::ParserRecorder* log_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000264 Scope* scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000265 uintptr_t stack_limit_;
266 bool stack_overflow_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000267 bool allow_lazy_;
268};
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000269} } // v8::preparser
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000270
271#endif // V8_PREPARSER_H