blob: c0dcc0b4a1df3bdc9512c22341276be220e2468a [file] [log] [blame]
Ben Murdochb8e0da22011-05-16 14:20:40 +01001
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08002// Copyright 2010 the V8 project authors. All rights reserved.
3// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are
5// met:
6//
7// * Redistributions of source code must retain the above copyright
8// notice, this list of conditions and the following disclaimer.
9// * Redistributions in binary form must reproduce the above
10// copyright notice, this list of conditions and the following
11// disclaimer in the documentation and/or other materials provided
12// with the distribution.
13// * Neither the name of Google Inc. nor the names of its
14// contributors may be used to endorse or promote products derived
15// from this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "../include/v8stdint.h"
30#include "unicode.h"
31#include "globals.h"
32#include "checks.h"
33#include "allocation.h"
34#include "utils.h"
35#include "list.h"
36#include "scanner-base.h"
37#include "preparse-data.h"
38#include "preparser.h"
39
40namespace v8 {
41namespace preparser {
42
43// Preparsing checks a JavaScript program and emits preparse-data that helps
44// a later parsing to be faster.
45// See preparser-data.h for the data.
46
47// The PreParser checks that the syntax follows the grammar for JavaScript,
48// and collects some information about the program along the way.
49// The grammar check is only performed in order to understand the program
50// sufficiently to deduce some information about it, that can be used
51// to speed up later parsing. Finding errors is not the goal of pre-parsing,
52// rather it is to speed up properly written and correct programs.
53// That means that contextual checks (like a label being declared where
54// it is used) are generally omitted.
55
56namespace i = ::v8::internal;
57
58#define CHECK_OK ok); \
59 if (!*ok) return -1; \
60 ((void)0
61#define DUMMY ) // to make indentation work
62#undef DUMMY
63
64
65void PreParser::ReportUnexpectedToken(i::Token::Value token) {
66 // We don't report stack overflows here, to avoid increasing the
67 // stack depth even further. Instead we report it after parsing is
68 // over, in ParseProgram.
Ben Murdochb0fe1622011-05-05 13:52:32 +010069 if (token == i::Token::ILLEGAL && stack_overflow_) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080070 return;
71 }
72 i::JavaScriptScanner::Location source_location = scanner_->location();
73
74 // Four of the tokens are treated specially
75 switch (token) {
76 case i::Token::EOS:
77 return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
78 "unexpected_eos", NULL);
79 case i::Token::NUMBER:
80 return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
81 "unexpected_token_number", NULL);
82 case i::Token::STRING:
83 return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
84 "unexpected_token_string", NULL);
85 case i::Token::IDENTIFIER:
86 return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
87 "unexpected_token_identifier", NULL);
88 default:
89 const char* name = i::Token::String(token);
90 ReportMessageAt(source_location.beg_pos, source_location.end_pos,
91 "unexpected_token", name);
92 }
93}
94
95
Ben Murdochb0fe1622011-05-05 13:52:32 +010096PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
97 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080098 // SourceElements ::
99 // (Statement)* <end_token>
100
101 while (peek() != end_token) {
102 ParseStatement(CHECK_OK);
103 }
104 return kUnknownSourceElements;
105}
106
107
Ben Murdochb0fe1622011-05-05 13:52:32 +0100108PreParser::Statement PreParser::ParseStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800109 // Statement ::
110 // Block
111 // VariableStatement
112 // EmptyStatement
113 // ExpressionStatement
114 // IfStatement
115 // IterationStatement
116 // ContinueStatement
117 // BreakStatement
118 // ReturnStatement
119 // WithStatement
120 // LabelledStatement
121 // SwitchStatement
122 // ThrowStatement
123 // TryStatement
124 // DebuggerStatement
125
126 // Note: Since labels can only be used by 'break' and 'continue'
127 // statements, which themselves are only valid within blocks,
128 // iterations or 'switch' statements (i.e., BreakableStatements),
129 // labels can be simply ignored in all other cases; except for
130 // trivial labeled break statements 'label: break label' which is
131 // parsed into an empty statement.
132
133 // Keep the source position of the statement
134 switch (peek()) {
135 case i::Token::LBRACE:
136 return ParseBlock(ok);
137
138 case i::Token::CONST:
139 case i::Token::VAR:
140 return ParseVariableStatement(ok);
141
142 case i::Token::SEMICOLON:
143 Next();
144 return kUnknownStatement;
145
146 case i::Token::IF:
147 return ParseIfStatement(ok);
148
149 case i::Token::DO:
150 return ParseDoWhileStatement(ok);
151
152 case i::Token::WHILE:
153 return ParseWhileStatement(ok);
154
155 case i::Token::FOR:
156 return ParseForStatement(ok);
157
158 case i::Token::CONTINUE:
159 return ParseContinueStatement(ok);
160
161 case i::Token::BREAK:
162 return ParseBreakStatement(ok);
163
164 case i::Token::RETURN:
165 return ParseReturnStatement(ok);
166
167 case i::Token::WITH:
168 return ParseWithStatement(ok);
169
170 case i::Token::SWITCH:
171 return ParseSwitchStatement(ok);
172
173 case i::Token::THROW:
174 return ParseThrowStatement(ok);
175
176 case i::Token::TRY:
177 return ParseTryStatement(ok);
178
179 case i::Token::FUNCTION:
180 return ParseFunctionDeclaration(ok);
181
182 case i::Token::NATIVE:
183 return ParseNativeDeclaration(ok);
184
185 case i::Token::DEBUGGER:
186 return ParseDebuggerStatement(ok);
187
188 default:
189 return ParseExpressionOrLabelledStatement(ok);
190 }
191}
192
193
Ben Murdochb0fe1622011-05-05 13:52:32 +0100194PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800195 // FunctionDeclaration ::
196 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
197 Expect(i::Token::FUNCTION, CHECK_OK);
198 ParseIdentifier(CHECK_OK);
199 ParseFunctionLiteral(CHECK_OK);
200 return kUnknownStatement;
201}
202
203
204// Language extension which is only enabled for source files loaded
205// through the API's extension mechanism. A native function
206// declaration is resolved by looking up the function through a
207// callback provided by the extension.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100208PreParser::Statement PreParser::ParseNativeDeclaration(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800209 Expect(i::Token::NATIVE, CHECK_OK);
210 Expect(i::Token::FUNCTION, CHECK_OK);
211 ParseIdentifier(CHECK_OK);
212 Expect(i::Token::LPAREN, CHECK_OK);
213 bool done = (peek() == i::Token::RPAREN);
214 while (!done) {
215 ParseIdentifier(CHECK_OK);
216 done = (peek() == i::Token::RPAREN);
217 if (!done) {
218 Expect(i::Token::COMMA, CHECK_OK);
219 }
220 }
221 Expect(i::Token::RPAREN, CHECK_OK);
222 Expect(i::Token::SEMICOLON, CHECK_OK);
223 return kUnknownStatement;
224}
225
226
Ben Murdochb0fe1622011-05-05 13:52:32 +0100227PreParser::Statement PreParser::ParseBlock(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800228 // Block ::
229 // '{' Statement* '}'
230
231 // Note that a Block does not introduce a new execution scope!
232 // (ECMA-262, 3rd, 12.2)
233 //
234 Expect(i::Token::LBRACE, CHECK_OK);
235 while (peek() != i::Token::RBRACE) {
236 ParseStatement(CHECK_OK);
237 }
238 Expect(i::Token::RBRACE, CHECK_OK);
239 return kUnknownStatement;
240}
241
242
Ben Murdochb0fe1622011-05-05 13:52:32 +0100243PreParser::Statement PreParser::ParseVariableStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800244 // VariableStatement ::
245 // VariableDeclarations ';'
246
247 Statement result = ParseVariableDeclarations(true, NULL, CHECK_OK);
248 ExpectSemicolon(CHECK_OK);
249 return result;
250}
251
252
253// If the variable declaration declares exactly one non-const
254// variable, then *var is set to that variable. In all other cases,
255// *var is untouched; in particular, it is the caller's responsibility
256// to initialize it properly. This mechanism is also used for the parsing
257// of 'for-in' loops.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100258PreParser::Statement PreParser::ParseVariableDeclarations(bool accept_IN,
259 int* num_decl,
260 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800261 // VariableDeclarations ::
262 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
263
264 if (peek() == i::Token::VAR) {
265 Consume(i::Token::VAR);
266 } else if (peek() == i::Token::CONST) {
267 Consume(i::Token::CONST);
268 } else {
269 *ok = false;
270 return 0;
271 }
272
273 // The scope of a variable/const declared anywhere inside a function
274 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). .
275 int nvars = 0; // the number of variables declared
276 do {
277 // Parse variable name.
278 if (nvars > 0) Consume(i::Token::COMMA);
279 ParseIdentifier(CHECK_OK);
280 nvars++;
281 if (peek() == i::Token::ASSIGN) {
282 Expect(i::Token::ASSIGN, CHECK_OK);
283 ParseAssignmentExpression(accept_IN, CHECK_OK);
284 }
285 } while (peek() == i::Token::COMMA);
286
287 if (num_decl != NULL) *num_decl = nvars;
288 return kUnknownStatement;
289}
290
291
Ben Murdochb0fe1622011-05-05 13:52:32 +0100292PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800293 bool* ok) {
294 // ExpressionStatement | LabelledStatement ::
295 // Expression ';'
296 // Identifier ':' Statement
297
298 Expression expr = ParseExpression(true, CHECK_OK);
299 if (peek() == i::Token::COLON && expr == kIdentifierExpression) {
300 Consume(i::Token::COLON);
301 return ParseStatement(ok);
302 }
303 // Parsed expression statement.
304 ExpectSemicolon(CHECK_OK);
305 return kUnknownStatement;
306}
307
308
Ben Murdochb0fe1622011-05-05 13:52:32 +0100309PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800310 // IfStatement ::
311 // 'if' '(' Expression ')' Statement ('else' Statement)?
312
313 Expect(i::Token::IF, CHECK_OK);
314 Expect(i::Token::LPAREN, CHECK_OK);
315 ParseExpression(true, CHECK_OK);
316 Expect(i::Token::RPAREN, CHECK_OK);
317 ParseStatement(CHECK_OK);
318 if (peek() == i::Token::ELSE) {
319 Next();
320 ParseStatement(CHECK_OK);
321 }
322 return kUnknownStatement;
323}
324
325
Ben Murdochb0fe1622011-05-05 13:52:32 +0100326PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800327 // ContinueStatement ::
328 // 'continue' [no line terminator] Identifier? ';'
329
330 Expect(i::Token::CONTINUE, CHECK_OK);
331 i::Token::Value tok = peek();
332 if (!scanner_->has_line_terminator_before_next() &&
333 tok != i::Token::SEMICOLON &&
334 tok != i::Token::RBRACE &&
335 tok != i::Token::EOS) {
336 ParseIdentifier(CHECK_OK);
337 }
338 ExpectSemicolon(CHECK_OK);
339 return kUnknownStatement;
340}
341
342
Ben Murdochb0fe1622011-05-05 13:52:32 +0100343PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800344 // BreakStatement ::
345 // 'break' [no line terminator] Identifier? ';'
346
347 Expect(i::Token::BREAK, CHECK_OK);
348 i::Token::Value tok = peek();
349 if (!scanner_->has_line_terminator_before_next() &&
350 tok != i::Token::SEMICOLON &&
351 tok != i::Token::RBRACE &&
352 tok != i::Token::EOS) {
353 ParseIdentifier(CHECK_OK);
354 }
355 ExpectSemicolon(CHECK_OK);
356 return kUnknownStatement;
357}
358
359
Ben Murdochb0fe1622011-05-05 13:52:32 +0100360PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800361 // ReturnStatement ::
362 // 'return' [no line terminator] Expression? ';'
363
364 // Consume the return token. It is necessary to do the before
365 // reporting any errors on it, because of the way errors are
366 // reported (underlining).
367 Expect(i::Token::RETURN, CHECK_OK);
368
369 // An ECMAScript program is considered syntactically incorrect if it
370 // contains a return statement that is not within the body of a
371 // function. See ECMA-262, section 12.9, page 67.
372 // This is not handled during preparsing.
373
374 i::Token::Value tok = peek();
375 if (!scanner_->has_line_terminator_before_next() &&
376 tok != i::Token::SEMICOLON &&
377 tok != i::Token::RBRACE &&
378 tok != i::Token::EOS) {
379 ParseExpression(true, CHECK_OK);
380 }
381 ExpectSemicolon(CHECK_OK);
382 return kUnknownStatement;
383}
384
385
Ben Murdochb0fe1622011-05-05 13:52:32 +0100386PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800387 // WithStatement ::
388 // 'with' '(' Expression ')' Statement
389 Expect(i::Token::WITH, CHECK_OK);
390 Expect(i::Token::LPAREN, CHECK_OK);
391 ParseExpression(true, CHECK_OK);
392 Expect(i::Token::RPAREN, CHECK_OK);
393
394 scope_->EnterWith();
395 ParseStatement(CHECK_OK);
396 scope_->LeaveWith();
397 return kUnknownStatement;
398}
399
400
Ben Murdochb0fe1622011-05-05 13:52:32 +0100401PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800402 // SwitchStatement ::
403 // 'switch' '(' Expression ')' '{' CaseClause* '}'
404
405 Expect(i::Token::SWITCH, CHECK_OK);
406 Expect(i::Token::LPAREN, CHECK_OK);
407 ParseExpression(true, CHECK_OK);
408 Expect(i::Token::RPAREN, CHECK_OK);
409
410 Expect(i::Token::LBRACE, CHECK_OK);
411 i::Token::Value token = peek();
412 while (token != i::Token::RBRACE) {
413 if (token == i::Token::CASE) {
414 Expect(i::Token::CASE, CHECK_OK);
415 ParseExpression(true, CHECK_OK);
416 Expect(i::Token::COLON, CHECK_OK);
417 } else if (token == i::Token::DEFAULT) {
418 Expect(i::Token::DEFAULT, CHECK_OK);
419 Expect(i::Token::COLON, CHECK_OK);
420 } else {
421 ParseStatement(CHECK_OK);
422 }
423 token = peek();
424 }
425 Expect(i::Token::RBRACE, CHECK_OK);
426
427 return kUnknownStatement;
428}
429
430
Ben Murdochb0fe1622011-05-05 13:52:32 +0100431PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800432 // DoStatement ::
433 // 'do' Statement 'while' '(' Expression ')' ';'
434
435 Expect(i::Token::DO, CHECK_OK);
436 ParseStatement(CHECK_OK);
437 Expect(i::Token::WHILE, CHECK_OK);
438 Expect(i::Token::LPAREN, CHECK_OK);
439 ParseExpression(true, CHECK_OK);
440 Expect(i::Token::RPAREN, CHECK_OK);
441 return kUnknownStatement;
442}
443
444
Ben Murdochb0fe1622011-05-05 13:52:32 +0100445PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800446 // WhileStatement ::
447 // 'while' '(' Expression ')' Statement
448
449 Expect(i::Token::WHILE, CHECK_OK);
450 Expect(i::Token::LPAREN, CHECK_OK);
451 ParseExpression(true, CHECK_OK);
452 Expect(i::Token::RPAREN, CHECK_OK);
453 ParseStatement(CHECK_OK);
454 return kUnknownStatement;
455}
456
457
Ben Murdochb0fe1622011-05-05 13:52:32 +0100458PreParser::Statement PreParser::ParseForStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800459 // ForStatement ::
460 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
461
462 Expect(i::Token::FOR, CHECK_OK);
463 Expect(i::Token::LPAREN, CHECK_OK);
464 if (peek() != i::Token::SEMICOLON) {
465 if (peek() == i::Token::VAR || peek() == i::Token::CONST) {
466 int decl_count;
467 ParseVariableDeclarations(false, &decl_count, CHECK_OK);
468 if (peek() == i::Token::IN && decl_count == 1) {
469 Expect(i::Token::IN, CHECK_OK);
470 ParseExpression(true, CHECK_OK);
471 Expect(i::Token::RPAREN, CHECK_OK);
472
473 ParseStatement(CHECK_OK);
474 return kUnknownStatement;
475 }
476 } else {
477 ParseExpression(false, CHECK_OK);
478 if (peek() == i::Token::IN) {
479 Expect(i::Token::IN, CHECK_OK);
480 ParseExpression(true, CHECK_OK);
481 Expect(i::Token::RPAREN, CHECK_OK);
482
483 ParseStatement(CHECK_OK);
484 return kUnknownStatement;
485 }
486 }
487 }
488
489 // Parsed initializer at this point.
490 Expect(i::Token::SEMICOLON, CHECK_OK);
491
492 if (peek() != i::Token::SEMICOLON) {
493 ParseExpression(true, CHECK_OK);
494 }
495 Expect(i::Token::SEMICOLON, CHECK_OK);
496
497 if (peek() != i::Token::RPAREN) {
498 ParseExpression(true, CHECK_OK);
499 }
500 Expect(i::Token::RPAREN, CHECK_OK);
501
502 ParseStatement(CHECK_OK);
503 return kUnknownStatement;
504}
505
506
Ben Murdochb0fe1622011-05-05 13:52:32 +0100507PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800508 // ThrowStatement ::
509 // 'throw' [no line terminator] Expression ';'
510
511 Expect(i::Token::THROW, CHECK_OK);
512 if (scanner_->has_line_terminator_before_next()) {
513 i::JavaScriptScanner::Location pos = scanner_->location();
514 ReportMessageAt(pos.beg_pos, pos.end_pos,
515 "newline_after_throw", NULL);
516 *ok = false;
517 return kUnknownStatement;
518 }
519 ParseExpression(true, CHECK_OK);
520 ExpectSemicolon(CHECK_OK);
521
522 return kUnknownStatement;
523}
524
525
Ben Murdochb0fe1622011-05-05 13:52:32 +0100526PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800527 // TryStatement ::
528 // 'try' Block Catch
529 // 'try' Block Finally
530 // 'try' Block Catch Finally
531 //
532 // Catch ::
533 // 'catch' '(' Identifier ')' Block
534 //
535 // Finally ::
536 // 'finally' Block
537
538 // In preparsing, allow any number of catch/finally blocks, including zero
539 // of both.
540
541 Expect(i::Token::TRY, CHECK_OK);
542
543 ParseBlock(CHECK_OK);
544
545 bool catch_or_finally_seen = false;
546 if (peek() == i::Token::CATCH) {
547 Consume(i::Token::CATCH);
548 Expect(i::Token::LPAREN, CHECK_OK);
549 ParseIdentifier(CHECK_OK);
550 Expect(i::Token::RPAREN, CHECK_OK);
551 scope_->EnterWith();
552 ParseBlock(ok);
553 scope_->LeaveWith();
554 if (!*ok) return kUnknownStatement;
555 catch_or_finally_seen = true;
556 }
557 if (peek() == i::Token::FINALLY) {
558 Consume(i::Token::FINALLY);
559 ParseBlock(CHECK_OK);
560 catch_or_finally_seen = true;
561 }
562 if (!catch_or_finally_seen) {
563 *ok = false;
564 }
565 return kUnknownStatement;
566}
567
568
Ben Murdochb0fe1622011-05-05 13:52:32 +0100569PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800570 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
571 // contexts this is used as a statement which invokes the debugger as if a
572 // break point is present.
573 // DebuggerStatement ::
574 // 'debugger' ';'
575
576 Expect(i::Token::DEBUGGER, CHECK_OK);
577 ExpectSemicolon(CHECK_OK);
578 return kUnknownStatement;
579}
580
581
582// Precedence = 1
Ben Murdochb0fe1622011-05-05 13:52:32 +0100583PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800584 // Expression ::
585 // AssignmentExpression
586 // Expression ',' AssignmentExpression
587
588 Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
589 while (peek() == i::Token::COMMA) {
590 Expect(i::Token::COMMA, CHECK_OK);
591 ParseAssignmentExpression(accept_IN, CHECK_OK);
592 result = kUnknownExpression;
593 }
594 return result;
595}
596
597
598// Precedence = 2
Ben Murdochb0fe1622011-05-05 13:52:32 +0100599PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
600 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800601 // AssignmentExpression ::
602 // ConditionalExpression
603 // LeftHandSideExpression AssignmentOperator AssignmentExpression
604
605 Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
606
607 if (!i::Token::IsAssignmentOp(peek())) {
608 // Parsed conditional expression only (no assignment).
609 return expression;
610 }
611
612 i::Token::Value op = Next(); // Get assignment operator.
613 ParseAssignmentExpression(accept_IN, CHECK_OK);
614
615 if ((op == i::Token::ASSIGN) && (expression == kThisPropertyExpression)) {
616 scope_->AddProperty();
617 }
618
619 return kUnknownExpression;
620}
621
622
623// Precedence = 3
Ben Murdochb0fe1622011-05-05 13:52:32 +0100624PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
625 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800626 // ConditionalExpression ::
627 // LogicalOrExpression
628 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
629
630 // We start using the binary expression parser for prec >= 4 only!
631 Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
632 if (peek() != i::Token::CONDITIONAL) return expression;
633 Consume(i::Token::CONDITIONAL);
634 // In parsing the first assignment expression in conditional
635 // expressions we always accept the 'in' keyword; see ECMA-262,
636 // section 11.12, page 58.
637 ParseAssignmentExpression(true, CHECK_OK);
638 Expect(i::Token::COLON, CHECK_OK);
639 ParseAssignmentExpression(accept_IN, CHECK_OK);
640 return kUnknownExpression;
641}
642
643
644int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
645 if (tok == i::Token::IN && !accept_IN)
646 return 0; // 0 precedence will terminate binary expression parsing
647
648 return i::Token::Precedence(tok);
649}
650
651
652// Precedence >= 4
Ben Murdochb0fe1622011-05-05 13:52:32 +0100653PreParser::Expression PreParser::ParseBinaryExpression(int prec,
654 bool accept_IN,
655 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800656 Expression result = ParseUnaryExpression(CHECK_OK);
657 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
658 // prec1 >= 4
659 while (Precedence(peek(), accept_IN) == prec1) {
660 Next();
661 ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
662 result = kUnknownExpression;
663 }
664 }
665 return result;
666}
667
668
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800670 // UnaryExpression ::
671 // PostfixExpression
672 // 'delete' UnaryExpression
673 // 'void' UnaryExpression
674 // 'typeof' UnaryExpression
675 // '++' UnaryExpression
676 // '--' UnaryExpression
677 // '+' UnaryExpression
678 // '-' UnaryExpression
679 // '~' UnaryExpression
680 // '!' UnaryExpression
681
682 i::Token::Value op = peek();
683 if (i::Token::IsUnaryOp(op) || i::Token::IsCountOp(op)) {
684 op = Next();
685 ParseUnaryExpression(ok);
686 return kUnknownExpression;
687 } else {
688 return ParsePostfixExpression(ok);
689 }
690}
691
692
Ben Murdochb0fe1622011-05-05 13:52:32 +0100693PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800694 // PostfixExpression ::
695 // LeftHandSideExpression ('++' | '--')?
696
697 Expression expression = ParseLeftHandSideExpression(CHECK_OK);
698 if (!scanner_->has_line_terminator_before_next() &&
699 i::Token::IsCountOp(peek())) {
700 Next();
701 return kUnknownExpression;
702 }
703 return expression;
704}
705
706
Ben Murdochb0fe1622011-05-05 13:52:32 +0100707PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800708 // LeftHandSideExpression ::
709 // (NewExpression | MemberExpression) ...
710
711 Expression result;
712 if (peek() == i::Token::NEW) {
713 result = ParseNewExpression(CHECK_OK);
714 } else {
715 result = ParseMemberExpression(CHECK_OK);
716 }
717
718 while (true) {
719 switch (peek()) {
720 case i::Token::LBRACK: {
721 Consume(i::Token::LBRACK);
722 ParseExpression(true, CHECK_OK);
723 Expect(i::Token::RBRACK, CHECK_OK);
724 if (result == kThisExpression) {
725 result = kThisPropertyExpression;
726 } else {
727 result = kUnknownExpression;
728 }
729 break;
730 }
731
732 case i::Token::LPAREN: {
733 ParseArguments(CHECK_OK);
734 result = kUnknownExpression;
735 break;
736 }
737
738 case i::Token::PERIOD: {
739 Consume(i::Token::PERIOD);
740 ParseIdentifierName(CHECK_OK);
741 if (result == kThisExpression) {
742 result = kThisPropertyExpression;
743 } else {
744 result = kUnknownExpression;
745 }
746 break;
747 }
748
749 default:
750 return result;
751 }
752 }
753}
754
755
Ben Murdochb0fe1622011-05-05 13:52:32 +0100756PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800757 // NewExpression ::
758 // ('new')+ MemberExpression
759
760 // The grammar for new expressions is pretty warped. The keyword
761 // 'new' can either be a part of the new expression (where it isn't
762 // followed by an argument list) or a part of the member expression,
763 // where it must be followed by an argument list. To accommodate
764 // this, we parse the 'new' keywords greedily and keep track of how
765 // many we have parsed. This information is then passed on to the
766 // member expression parser, which is only allowed to match argument
767 // lists as long as it has 'new' prefixes left
768 unsigned new_count = 0;
769 do {
770 Consume(i::Token::NEW);
771 new_count++;
772 } while (peek() == i::Token::NEW);
773
774 return ParseMemberWithNewPrefixesExpression(new_count, ok);
775}
776
777
Ben Murdochb0fe1622011-05-05 13:52:32 +0100778PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800779 return ParseMemberWithNewPrefixesExpression(0, ok);
780}
781
782
Ben Murdochb0fe1622011-05-05 13:52:32 +0100783PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800784 unsigned new_count, bool* ok) {
785 // MemberExpression ::
786 // (PrimaryExpression | FunctionLiteral)
787 // ('[' Expression ']' | '.' Identifier | Arguments)*
788
789 // Parse the initial primary or function expression.
790 Expression result = kUnknownExpression;
791 if (peek() == i::Token::FUNCTION) {
792 Consume(i::Token::FUNCTION);
793 if (peek() == i::Token::IDENTIFIER) {
794 ParseIdentifier(CHECK_OK);
795 }
796 result = ParseFunctionLiteral(CHECK_OK);
797 } else {
798 result = ParsePrimaryExpression(CHECK_OK);
799 }
800
801 while (true) {
802 switch (peek()) {
803 case i::Token::LBRACK: {
804 Consume(i::Token::LBRACK);
805 ParseExpression(true, CHECK_OK);
806 Expect(i::Token::RBRACK, CHECK_OK);
807 if (result == kThisExpression) {
808 result = kThisPropertyExpression;
809 } else {
810 result = kUnknownExpression;
811 }
812 break;
813 }
814 case i::Token::PERIOD: {
815 Consume(i::Token::PERIOD);
816 ParseIdentifierName(CHECK_OK);
817 if (result == kThisExpression) {
818 result = kThisPropertyExpression;
819 } else {
820 result = kUnknownExpression;
821 }
822 break;
823 }
824 case i::Token::LPAREN: {
825 if (new_count == 0) return result;
826 // Consume one of the new prefixes (already parsed).
827 ParseArguments(CHECK_OK);
828 new_count--;
829 result = kUnknownExpression;
830 break;
831 }
832 default:
833 return result;
834 }
835 }
836}
837
838
Ben Murdochb0fe1622011-05-05 13:52:32 +0100839PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800840 // PrimaryExpression ::
841 // 'this'
842 // 'null'
843 // 'true'
844 // 'false'
845 // Identifier
846 // Number
847 // String
848 // ArrayLiteral
849 // ObjectLiteral
850 // RegExpLiteral
851 // '(' Expression ')'
852
853 Expression result = kUnknownExpression;
854 switch (peek()) {
855 case i::Token::THIS: {
856 Next();
857 result = kThisExpression;
858 break;
859 }
860
861 case i::Token::IDENTIFIER: {
862 ParseIdentifier(CHECK_OK);
863 result = kIdentifierExpression;
864 break;
865 }
866
867 case i::Token::NULL_LITERAL:
868 case i::Token::TRUE_LITERAL:
869 case i::Token::FALSE_LITERAL:
870 case i::Token::NUMBER: {
871 Next();
872 break;
873 }
874 case i::Token::STRING: {
875 Next();
876 result = GetStringSymbol();
877 break;
878 }
879
880 case i::Token::ASSIGN_DIV:
881 result = ParseRegExpLiteral(true, CHECK_OK);
882 break;
883
884 case i::Token::DIV:
885 result = ParseRegExpLiteral(false, CHECK_OK);
886 break;
887
888 case i::Token::LBRACK:
889 result = ParseArrayLiteral(CHECK_OK);
890 break;
891
892 case i::Token::LBRACE:
893 result = ParseObjectLiteral(CHECK_OK);
894 break;
895
896 case i::Token::LPAREN:
897 Consume(i::Token::LPAREN);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100898 parenthesized_function_ = (peek() == i::Token::FUNCTION);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800899 result = ParseExpression(true, CHECK_OK);
900 Expect(i::Token::RPAREN, CHECK_OK);
901 if (result == kIdentifierExpression) result = kUnknownExpression;
902 break;
903
904 case i::Token::MOD:
905 result = ParseV8Intrinsic(CHECK_OK);
906 break;
907
908 default: {
909 Next();
910 *ok = false;
911 return kUnknownExpression;
912 }
913 }
914
915 return result;
916}
917
918
Ben Murdochb0fe1622011-05-05 13:52:32 +0100919PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800920 // ArrayLiteral ::
921 // '[' Expression? (',' Expression?)* ']'
922 Expect(i::Token::LBRACK, CHECK_OK);
923 while (peek() != i::Token::RBRACK) {
924 if (peek() != i::Token::COMMA) {
925 ParseAssignmentExpression(true, CHECK_OK);
926 }
927 if (peek() != i::Token::RBRACK) {
928 Expect(i::Token::COMMA, CHECK_OK);
929 }
930 }
931 Expect(i::Token::RBRACK, CHECK_OK);
932
933 scope_->NextMaterializedLiteralIndex();
934 return kUnknownExpression;
935}
936
937
Ben Murdochb0fe1622011-05-05 13:52:32 +0100938PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800939 // ObjectLiteral ::
940 // '{' (
941 // ((IdentifierName | String | Number) ':' AssignmentExpression)
942 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
943 // )*[','] '}'
944
945 Expect(i::Token::LBRACE, CHECK_OK);
946 while (peek() != i::Token::RBRACE) {
947 i::Token::Value next = peek();
948 switch (next) {
949 case i::Token::IDENTIFIER: {
950 bool is_getter = false;
951 bool is_setter = false;
952 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
953 if ((is_getter || is_setter) && peek() != i::Token::COLON) {
954 i::Token::Value name = Next();
Steve Block9fac8402011-05-12 15:51:54 +0100955 bool is_keyword = i::Token::IsKeyword(name);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800956 if (name != i::Token::IDENTIFIER &&
957 name != i::Token::NUMBER &&
958 name != i::Token::STRING &&
Steve Block9fac8402011-05-12 15:51:54 +0100959 !is_keyword) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800960 *ok = false;
961 return kUnknownExpression;
962 }
Steve Block9fac8402011-05-12 15:51:54 +0100963 if (!is_keyword) {
964 LogSymbol();
965 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800966 ParseFunctionLiteral(CHECK_OK);
967 if (peek() != i::Token::RBRACE) {
968 Expect(i::Token::COMMA, CHECK_OK);
969 }
970 continue; // restart the while
971 }
972 break;
973 }
974 case i::Token::STRING:
975 Consume(next);
976 GetStringSymbol();
977 break;
978 case i::Token::NUMBER:
979 Consume(next);
980 break;
981 default:
982 if (i::Token::IsKeyword(next)) {
983 Consume(next);
984 } else {
985 // Unexpected token.
986 *ok = false;
987 return kUnknownExpression;
988 }
989 }
990
991 Expect(i::Token::COLON, CHECK_OK);
992 ParseAssignmentExpression(true, CHECK_OK);
993
994 // TODO(1240767): Consider allowing trailing comma.
995 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
996 }
997 Expect(i::Token::RBRACE, CHECK_OK);
998
999 scope_->NextMaterializedLiteralIndex();
1000 return kUnknownExpression;
1001}
1002
1003
Ben Murdochb0fe1622011-05-05 13:52:32 +01001004PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
1005 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001006 if (!scanner_->ScanRegExpPattern(seen_equal)) {
1007 Next();
1008 i::JavaScriptScanner::Location location = scanner_->location();
1009 ReportMessageAt(location.beg_pos, location.end_pos,
1010 "unterminated_regexp", NULL);
1011 *ok = false;
1012 return kUnknownExpression;
1013 }
1014
1015 scope_->NextMaterializedLiteralIndex();
1016
1017 if (!scanner_->ScanRegExpFlags()) {
1018 Next();
1019 i::JavaScriptScanner::Location location = scanner_->location();
1020 ReportMessageAt(location.beg_pos, location.end_pos,
1021 "invalid_regexp_flags", NULL);
1022 *ok = false;
1023 return kUnknownExpression;
1024 }
1025 Next();
1026 return kUnknownExpression;
1027}
1028
1029
Ben Murdochb0fe1622011-05-05 13:52:32 +01001030PreParser::Arguments PreParser::ParseArguments(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001031 // Arguments ::
1032 // '(' (AssignmentExpression)*[','] ')'
1033
1034 Expect(i::Token::LPAREN, CHECK_OK);
1035 bool done = (peek() == i::Token::RPAREN);
1036 int argc = 0;
1037 while (!done) {
1038 ParseAssignmentExpression(true, CHECK_OK);
1039 argc++;
1040 done = (peek() == i::Token::RPAREN);
1041 if (!done) Expect(i::Token::COMMA, CHECK_OK);
1042 }
1043 Expect(i::Token::RPAREN, CHECK_OK);
1044 return argc;
1045}
1046
1047
Ben Murdochb0fe1622011-05-05 13:52:32 +01001048PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001049 // Function ::
1050 // '(' FormalParameterList? ')' '{' FunctionBody '}'
1051
1052 // Parse function body.
1053 ScopeType outer_scope_type = scope_->type();
1054 bool inside_with = scope_->IsInsideWith();
1055 Scope function_scope(&scope_, kFunctionScope);
1056
1057 // FormalParameterList ::
1058 // '(' (Identifier)*[','] ')'
1059 Expect(i::Token::LPAREN, CHECK_OK);
1060 bool done = (peek() == i::Token::RPAREN);
1061 while (!done) {
1062 ParseIdentifier(CHECK_OK);
1063 done = (peek() == i::Token::RPAREN);
1064 if (!done) {
1065 Expect(i::Token::COMMA, CHECK_OK);
1066 }
1067 }
1068 Expect(i::Token::RPAREN, CHECK_OK);
1069
1070 Expect(i::Token::LBRACE, CHECK_OK);
1071 int function_block_pos = scanner_->location().beg_pos;
1072
1073 // Determine if the function will be lazily compiled.
1074 // Currently only happens to top-level functions.
1075 // Optimistically assume that all top-level functions are lazily compiled.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001076 bool is_lazily_compiled = (outer_scope_type == kTopLevelScope &&
1077 !inside_with && allow_lazy_ &&
1078 !parenthesized_function_);
1079 parenthesized_function_ = false;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001080
1081 if (is_lazily_compiled) {
1082 log_->PauseRecording();
1083 ParseSourceElements(i::Token::RBRACE, ok);
1084 log_->ResumeRecording();
1085 if (!*ok) return kUnknownExpression;
1086
1087 Expect(i::Token::RBRACE, CHECK_OK);
1088
Ben Murdochb0fe1622011-05-05 13:52:32 +01001089 // Position right after terminal '}'.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001090 int end_pos = scanner_->location().end_pos;
1091 log_->LogFunction(function_block_pos, end_pos,
1092 function_scope.materialized_literal_count(),
1093 function_scope.expected_properties());
1094 } else {
1095 ParseSourceElements(i::Token::RBRACE, CHECK_OK);
1096 Expect(i::Token::RBRACE, CHECK_OK);
1097 }
1098 return kUnknownExpression;
1099}
1100
1101
Ben Murdochb0fe1622011-05-05 13:52:32 +01001102PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001103 // CallRuntime ::
1104 // '%' Identifier Arguments
1105
1106 Expect(i::Token::MOD, CHECK_OK);
1107 ParseIdentifier(CHECK_OK);
1108 ParseArguments(CHECK_OK);
1109
1110 return kUnknownExpression;
1111}
1112
1113
1114void PreParser::ExpectSemicolon(bool* ok) {
1115 // Check for automatic semicolon insertion according to
1116 // the rules given in ECMA-262, section 7.9, page 21.
1117 i::Token::Value tok = peek();
1118 if (tok == i::Token::SEMICOLON) {
1119 Next();
1120 return;
1121 }
1122 if (scanner_->has_line_terminator_before_next() ||
1123 tok == i::Token::RBRACE ||
1124 tok == i::Token::EOS) {
1125 return;
1126 }
1127 Expect(i::Token::SEMICOLON, ok);
1128}
1129
1130
Steve Block9fac8402011-05-12 15:51:54 +01001131void PreParser::LogSymbol() {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001132 int identifier_pos = scanner_->location().beg_pos;
Steve Block9fac8402011-05-12 15:51:54 +01001133 if (scanner_->is_literal_ascii()) {
1134 log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
1135 } else {
1136 log_->LogUC16Symbol(identifier_pos, scanner_->literal_uc16_string());
1137 }
1138}
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001139
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001140
Steve Block9fac8402011-05-12 15:51:54 +01001141PreParser::Identifier PreParser::GetIdentifierSymbol() {
1142 LogSymbol();
1143 return kUnknownIdentifier;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001144}
1145
1146
Ben Murdochb0fe1622011-05-05 13:52:32 +01001147PreParser::Expression PreParser::GetStringSymbol() {
Steve Block9fac8402011-05-12 15:51:54 +01001148 LogSymbol();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001149 return kUnknownExpression;
1150}
1151
1152
Ben Murdochb0fe1622011-05-05 13:52:32 +01001153PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001154 Expect(i::Token::IDENTIFIER, ok);
1155 if (!*ok) return kUnknownIdentifier;
1156 return GetIdentifierSymbol();
1157}
1158
1159
Ben Murdochb0fe1622011-05-05 13:52:32 +01001160PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001161 i::Token::Value next = Next();
1162 if (i::Token::IsKeyword(next)) {
1163 int pos = scanner_->location().beg_pos;
1164 const char* keyword = i::Token::String(next);
Steve Block9fac8402011-05-12 15:51:54 +01001165 log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
1166 i::StrLength(keyword)));
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001167 return kUnknownExpression;
1168 }
1169 if (next == i::Token::IDENTIFIER) {
1170 return GetIdentifierSymbol();
1171 }
1172 *ok = false;
1173 return kUnknownIdentifier;
1174}
1175
1176
1177// This function reads an identifier and determines whether or not it
1178// is 'get' or 'set'. The reason for not using ParseIdentifier and
1179// checking on the output is that this involves heap allocation which
1180// we can't do during preparsing.
Ben Murdochb0fe1622011-05-05 13:52:32 +01001181PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
1182 bool* is_set,
1183 bool* ok) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001184 Expect(i::Token::IDENTIFIER, CHECK_OK);
Steve Block9fac8402011-05-12 15:51:54 +01001185 if (scanner_->is_literal_ascii() && scanner_->literal_length() == 3) {
1186 const char* token = scanner_->literal_ascii_string().start();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001187 *is_get = strncmp(token, "get", 3) == 0;
1188 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
1189 }
1190 return GetIdentifierSymbol();
1191}
1192
1193#undef CHECK_OK
1194} } // v8::preparser