blob: 3d72c97e2691862349b16416591314641ee4695a [file] [log] [blame]
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001// Copyright 2011 the V8 project authors. All rights reserved.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +00002// 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.
lrn@chromium.org1c092762011-05-09 09:42:16 +000036// See preparse-data-format.h for the data format.
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:
ager@chromium.orgea91cc52011-05-23 06:06:11 +000070 // These types form an algebra over syntactic categories that is just
71 // rich enough to let us recognize and propagate the constructs that
72 // are either being counted in the preparser data, or is important
73 // to throw the correct syntax error exceptions.
74
lrn@chromium.orgfa943b72010-11-03 08:14:36 +000075 enum ScopeType {
76 kTopLevelScope,
77 kFunctionScope
78 };
79
ager@chromium.orgea91cc52011-05-23 06:06:11 +000080 class Expression;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000081
ager@chromium.orgea91cc52011-05-23 06:06:11 +000082 class Identifier {
83 public:
84 static Identifier Default() {
85 return Identifier(kUnknownIdentifier);
86 }
87 static Identifier Eval() {
88 return Identifier(kEvalIdentifier);
89 }
90 static Identifier Arguments() {
91 return Identifier(kArgumentsIdentifier);
92 }
93 static Identifier FutureReserved() {
94 return Identifier(kFutureReservedIdentifier);
95 }
ager@chromium.org04921a82011-06-27 13:21:41 +000096 static Identifier FutureStrictReserved() {
97 return Identifier(kFutureStrictReservedIdentifier);
98 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +000099 bool IsEval() { return type_ == kEvalIdentifier; }
100 bool IsArguments() { return type_ == kArgumentsIdentifier; }
101 bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
102 bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
ager@chromium.org04921a82011-06-27 13:21:41 +0000103 bool IsFutureStrictReserved() {
104 return type_ == kFutureStrictReservedIdentifier;
105 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000106 bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000107
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000108 private:
109 enum Type {
110 kUnknownIdentifier,
111 kFutureReservedIdentifier,
ager@chromium.org04921a82011-06-27 13:21:41 +0000112 kFutureStrictReservedIdentifier,
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000113 kEvalIdentifier,
114 kArgumentsIdentifier
115 };
116 explicit Identifier(Type type) : type_(type) { }
117 Type type_;
118
119 friend class Expression;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000120 };
121
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000122 // Bits 0 and 1 are used to identify the type of expression:
123 // If bit 0 is set, it's an identifier.
124 // if bit 1 is set, it's a string literal.
125 // If neither is set, it's no particular type, and both set isn't
126 // use yet.
127 // Bit 2 is used to mark the expression as being parenthesized,
128 // so "(foo)" isn't recognized as a pure identifier (and possible label).
129 class Expression {
130 public:
131 static Expression Default() {
132 return Expression(kUnknownExpression);
133 }
134
135 static Expression FromIdentifier(Identifier id) {
136 return Expression(kIdentifierFlag | (id.type_ << kIdentifierShift));
137 }
138
139 static Expression StringLiteral() {
140 return Expression(kUnknownStringLiteral);
141 }
142
143 static Expression UseStrictStringLiteral() {
144 return Expression(kUseStrictString);
145 }
146
147 static Expression This() {
148 return Expression(kThisExpression);
149 }
150
151 static Expression ThisProperty() {
152 return Expression(kThisPropertyExpression);
153 }
154
155 static Expression StrictFunction() {
156 return Expression(kStrictFunctionExpression);
157 }
158
159 bool IsIdentifier() {
160 return (code_ & kIdentifierFlag) != 0;
161 }
162
163 // Only works corretly if it is actually an identifier expression.
164 PreParser::Identifier AsIdentifier() {
165 return PreParser::Identifier(
166 static_cast<PreParser::Identifier::Type>(code_ >> kIdentifierShift));
167 }
168
169 bool IsParenthesized() {
170 // If bit 0 or 1 is set, we interpret bit 2 as meaning parenthesized.
171 return (code_ & 7) > 4;
172 }
173
174 bool IsRawIdentifier() {
175 return !IsParenthesized() && IsIdentifier();
176 }
177
178 bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; }
179
180 bool IsRawStringLiteral() {
181 return !IsParenthesized() && IsStringLiteral();
182 }
183
184 bool IsUseStrictLiteral() {
185 return (code_ & kStringLiteralMask) == kUseStrictString;
186 }
187
188 bool IsThis() {
189 return code_ == kThisExpression;
190 }
191
192 bool IsThisProperty() {
193 return code_ == kThisPropertyExpression;
194 }
195
196 bool IsStrictFunction() {
197 return code_ == kStrictFunctionExpression;
198 }
199
200 Expression Parenthesize() {
201 int type = code_ & 3;
202 if (type != 0) {
203 // Identifiers and string literals can be parenthesized.
204 // They no longer work as labels or directive prologues,
205 // but are still recognized in other contexts.
206 return Expression(code_ | kParentesizedExpressionFlag);
207 }
208 // For other types of expressions, it's not important to remember
209 // the parentheses.
210 return *this;
211 }
212
213 private:
214 // First two/three bits are used as flags.
215 // Bit 0 and 1 represent identifiers or strings literals, and are
216 // mutually exclusive, but can both be absent.
217 // If bit 0 or 1 are set, bit 2 marks that the expression has
218 // been wrapped in parentheses (a string literal can no longer
219 // be a directive prologue, and an identifier can no longer be
220 // a label.
221 enum {
222 kUnknownExpression = 0,
223 // Identifiers
224 kIdentifierFlag = 1, // Used to detect labels.
225 kIdentifierShift = 3,
226
227 kStringLiteralFlag = 2, // Used to detect directive prologue.
228 kUnknownStringLiteral = kStringLiteralFlag,
229 kUseStrictString = kStringLiteralFlag | 8,
230 kStringLiteralMask = kUseStrictString,
231
232 kParentesizedExpressionFlag = 4, // Only if identifier or string literal.
233
234 // Below here applies if neither identifier nor string literal.
235 kThisExpression = 4,
236 kThisPropertyExpression = 8,
237 kStrictFunctionExpression = 12
238 };
239
240 explicit Expression(int expression_code) : code_(expression_code) { }
241
242 int code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000243 };
244
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000245 class Statement {
246 public:
247 static Statement Default() {
248 return Statement(kUnknownStatement);
249 }
250
danno@chromium.org40cb8782011-05-25 07:58:50 +0000251 static Statement FunctionDeclaration() {
252 return Statement(kFunctionDeclaration);
253 }
254
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000255 // Creates expression statement from expression.
256 // Preserves being an unparenthesized string literal, possibly
257 // "use strict".
258 static Statement ExpressionStatement(Expression expression) {
259 if (!expression.IsParenthesized()) {
260 if (expression.IsUseStrictLiteral()) {
261 return Statement(kUseStrictExpressionStatement);
262 }
263 if (expression.IsStringLiteral()) {
264 return Statement(kStringLiteralExpressionStatement);
265 }
266 }
267 return Default();
268 }
269
270 bool IsStringLiteral() {
271 return code_ != kUnknownStatement;
272 }
273
274 bool IsUseStrictLiteral() {
275 return code_ == kUseStrictExpressionStatement;
276 }
277
danno@chromium.org40cb8782011-05-25 07:58:50 +0000278 bool IsFunctionDeclaration() {
279 return code_ == kFunctionDeclaration;
280 }
281
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000282 private:
283 enum Type {
284 kUnknownStatement,
285 kStringLiteralExpressionStatement,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000286 kUseStrictExpressionStatement,
287 kFunctionDeclaration
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000288 };
289
290 explicit Statement(Type code) : code_(code) {}
291 Type code_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292 };
293
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000294 enum SourceElements {
295 kUnknownSourceElements
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000296 };
297
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000298 typedef int Arguments;
299
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000300 class Scope {
301 public:
302 Scope(Scope** variable, ScopeType type)
303 : variable_(variable),
304 prev_(*variable),
305 type_(type),
306 materialized_literal_count_(0),
307 expected_properties_(0),
lrn@chromium.org1c092762011-05-09 09:42:16 +0000308 with_nesting_count_(0),
309 strict_((prev_ != NULL) && prev_->is_strict()) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000310 *variable = this;
311 }
312 ~Scope() { *variable_ = prev_; }
313 void NextMaterializedLiteralIndex() { materialized_literal_count_++; }
314 void AddProperty() { expected_properties_++; }
315 ScopeType type() { return type_; }
316 int expected_properties() { return expected_properties_; }
317 int materialized_literal_count() { return materialized_literal_count_; }
318 bool IsInsideWith() { return with_nesting_count_ != 0; }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000319 bool is_strict() { return strict_; }
320 void set_strict() { strict_ = true; }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000321 void EnterWith() { with_nesting_count_++; }
322 void LeaveWith() { with_nesting_count_--; }
323
324 private:
325 Scope** const variable_;
326 Scope* const prev_;
327 const ScopeType type_;
328 int materialized_literal_count_;
329 int expected_properties_;
330 int with_nesting_count_;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000331 bool strict_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000332 };
333
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000334 // Private constructor only used in PreParseProgram.
335 PreParser(i::JavaScriptScanner* scanner,
336 i::ParserRecorder* log,
337 uintptr_t stack_limit,
338 bool allow_lazy)
339 : scanner_(scanner),
340 log_(log),
341 scope_(NULL),
342 stack_limit_(stack_limit),
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000343 strict_mode_violation_location_(i::Scanner::Location::invalid()),
344 strict_mode_violation_type_(NULL),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000345 stack_overflow_(false),
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000346 allow_lazy_(true),
347 parenthesized_function_(false) { }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000348
349 // Preparse the program. Only called in PreParseProgram after creating
350 // the instance.
351 PreParseResult PreParse() {
352 Scope top_scope(&scope_, kTopLevelScope);
353 bool ok = true;
lrn@chromium.org1c092762011-05-09 09:42:16 +0000354 int start_position = scanner_->peek_location().beg_pos;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000355 ParseSourceElements(i::Token::EOS, &ok);
356 if (stack_overflow_) return kPreParseStackOverflow;
357 if (!ok) {
358 ReportUnexpectedToken(scanner_->current_token());
lrn@chromium.org1c092762011-05-09 09:42:16 +0000359 } else if (scope_->is_strict()) {
360 CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000361 }
362 return kPreParseSuccess;
363 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000364
365 // Report syntax error
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000366 void ReportUnexpectedToken(i::Token::Value token);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000367 void ReportMessageAt(int start_pos,
368 int end_pos,
369 const char* type,
370 const char* name_opt) {
371 log_->LogMessage(start_pos, end_pos, type, name_opt);
372 }
373
lrn@chromium.org1c092762011-05-09 09:42:16 +0000374 void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
375
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000376 // All ParseXXX functions take as the last argument an *ok parameter
377 // which is set to false if parsing failed; it is unchanged otherwise.
378 // By making the 'exception handling' explicit, we are forced to check
379 // for failure at the call sites.
380 SourceElements ParseSourceElements(int end_token, bool* ok);
381 Statement ParseStatement(bool* ok);
382 Statement ParseFunctionDeclaration(bool* ok);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000383 Statement ParseBlock(bool* ok);
384 Statement ParseVariableStatement(bool* ok);
385 Statement ParseVariableDeclarations(bool accept_IN, int* num_decl, bool* ok);
386 Statement ParseExpressionOrLabelledStatement(bool* ok);
387 Statement ParseIfStatement(bool* ok);
388 Statement ParseContinueStatement(bool* ok);
389 Statement ParseBreakStatement(bool* ok);
390 Statement ParseReturnStatement(bool* ok);
391 Statement ParseWithStatement(bool* ok);
392 Statement ParseSwitchStatement(bool* ok);
393 Statement ParseDoWhileStatement(bool* ok);
394 Statement ParseWhileStatement(bool* ok);
395 Statement ParseForStatement(bool* ok);
396 Statement ParseThrowStatement(bool* ok);
397 Statement ParseTryStatement(bool* ok);
398 Statement ParseDebuggerStatement(bool* ok);
399
400 Expression ParseExpression(bool accept_IN, bool* ok);
401 Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
402 Expression ParseConditionalExpression(bool accept_IN, bool* ok);
403 Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
404 Expression ParseUnaryExpression(bool* ok);
405 Expression ParsePostfixExpression(bool* ok);
406 Expression ParseLeftHandSideExpression(bool* ok);
407 Expression ParseNewExpression(bool* ok);
408 Expression ParseMemberExpression(bool* ok);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000409 Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000410 Expression ParsePrimaryExpression(bool* ok);
411 Expression ParseArrayLiteral(bool* ok);
412 Expression ParseObjectLiteral(bool* ok);
413 Expression ParseRegExpLiteral(bool seen_equal, bool* ok);
414 Expression ParseV8Intrinsic(bool* ok);
415
416 Arguments ParseArguments(bool* ok);
417 Expression ParseFunctionLiteral(bool* ok);
418
419 Identifier ParseIdentifier(bool* ok);
420 Identifier ParseIdentifierName(bool* ok);
ager@chromium.org04921a82011-06-27 13:21:41 +0000421 Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
422 bool* is_set,
423 bool* ok);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000424
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000425 // Logs the currently parsed literal as a symbol in the preparser data.
426 void LogSymbol();
427 // Log the currently parsed identifier.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000428 Identifier GetIdentifierSymbol();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000429 // Log the currently parsed string literal.
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000430 Expression GetStringSymbol();
431
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000432 i::Token::Value peek() {
433 if (stack_overflow_) return i::Token::ILLEGAL;
434 return scanner_->peek();
435 }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000436
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000437 i::Token::Value Next() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000438 if (stack_overflow_) return i::Token::ILLEGAL;
439 {
440 int marker;
441 if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
442 // Further calls to peek/Next will return illegal token.
443 // The current one will still be returned. It might already
444 // have been seen using peek.
445 stack_overflow_ = true;
446 }
447 }
448 return scanner_->Next();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000449 }
450
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000451 bool peek_any_identifier();
452
lrn@chromium.org1c092762011-05-09 09:42:16 +0000453 void set_strict_mode() {
454 scope_->set_strict();
455 }
456
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000457 bool strict_mode() { return scope_->is_strict(); }
lrn@chromium.org1c092762011-05-09 09:42:16 +0000458
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000459 void Consume(i::Token::Value token) { Next(); }
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000460
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000461 void Expect(i::Token::Value token, bool* ok) {
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000462 if (Next() != token) {
463 *ok = false;
464 }
465 }
466
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000467 bool Check(i::Token::Value token) {
468 i::Token::Value next = peek();
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000469 if (next == token) {
470 Consume(next);
471 return true;
472 }
473 return false;
474 }
475 void ExpectSemicolon(bool* ok);
476
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000477 static int Precedence(i::Token::Value tok, bool accept_IN);
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000478
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000479 void SetStrictModeViolation(i::Scanner::Location,
480 const char* type,
481 bool *ok);
482
483 void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok);
484
485 void StrictModeIdentifierViolation(i::Scanner::Location,
486 const char* eval_args_type,
487 Identifier identifier,
488 bool* ok);
489
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000490 i::JavaScriptScanner* scanner_;
491 i::ParserRecorder* log_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000492 Scope* scope_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000493 uintptr_t stack_limit_;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000494 i::Scanner::Location strict_mode_violation_location_;
495 const char* strict_mode_violation_type_;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496 bool stack_overflow_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000497 bool allow_lazy_;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000498 bool parenthesized_function_;
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000499};
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000500} } // v8::preparser
lrn@chromium.orgfa943b72010-11-03 08:14:36 +0000501
502#endif // V8_PREPARSER_H