OLD | NEW |
| (Empty) |
1 // Copyright 2011 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <cmath> | |
6 | |
7 #include "src/allocation.h" | |
8 #include "src/base/logging.h" | |
9 #include "src/conversions-inl.h" | |
10 #include "src/conversions.h" | |
11 #include "src/globals.h" | |
12 #include "src/hashmap.h" | |
13 #include "src/list.h" | |
14 #include "src/preparse-data.h" | |
15 #include "src/preparse-data-format.h" | |
16 #include "src/preparser.h" | |
17 #include "src/unicode.h" | |
18 #include "src/utils.h" | |
19 | |
20 namespace v8 { | |
21 namespace internal { | |
22 | |
23 void PreParserTraits::ReportMessageAt(Scanner::Location location, | |
24 MessageTemplate::Template message, | |
25 const char* arg, | |
26 ParseErrorType error_type) { | |
27 ReportMessageAt(location.beg_pos, location.end_pos, message, arg, error_type); | |
28 } | |
29 | |
30 | |
31 void PreParserTraits::ReportMessageAt(int start_pos, int end_pos, | |
32 MessageTemplate::Template message, | |
33 const char* arg, | |
34 ParseErrorType error_type) { | |
35 pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg, error_type); | |
36 } | |
37 | |
38 | |
39 PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) { | |
40 if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) { | |
41 return PreParserIdentifier::FutureReserved(); | |
42 } else if (scanner->current_token() == | |
43 Token::FUTURE_STRICT_RESERVED_WORD) { | |
44 return PreParserIdentifier::FutureStrictReserved(); | |
45 } else if (scanner->current_token() == Token::LET) { | |
46 return PreParserIdentifier::Let(); | |
47 } else if (scanner->current_token() == Token::STATIC) { | |
48 return PreParserIdentifier::Static(); | |
49 } else if (scanner->current_token() == Token::YIELD) { | |
50 return PreParserIdentifier::Yield(); | |
51 } | |
52 if (scanner->UnescapedLiteralMatches("eval", 4)) { | |
53 return PreParserIdentifier::Eval(); | |
54 } | |
55 if (scanner->UnescapedLiteralMatches("arguments", 9)) { | |
56 return PreParserIdentifier::Arguments(); | |
57 } | |
58 if (scanner->UnescapedLiteralMatches("undefined", 9)) { | |
59 return PreParserIdentifier::Undefined(); | |
60 } | |
61 if (scanner->LiteralMatches("prototype", 9)) { | |
62 return PreParserIdentifier::Prototype(); | |
63 } | |
64 if (scanner->LiteralMatches("constructor", 11)) { | |
65 return PreParserIdentifier::Constructor(); | |
66 } | |
67 return PreParserIdentifier::Default(); | |
68 } | |
69 | |
70 | |
71 PreParserIdentifier PreParserTraits::GetNumberAsSymbol(Scanner* scanner) { | |
72 return PreParserIdentifier::Default(); | |
73 } | |
74 | |
75 | |
76 PreParserExpression PreParserTraits::ExpressionFromString( | |
77 int pos, Scanner* scanner, PreParserFactory* factory) { | |
78 if (scanner->UnescapedLiteralMatches("use strict", 10)) { | |
79 return PreParserExpression::UseStrictStringLiteral(); | |
80 } else if (scanner->UnescapedLiteralMatches("use strong", 10)) { | |
81 return PreParserExpression::UseStrongStringLiteral(); | |
82 } | |
83 return PreParserExpression::StringLiteral(); | |
84 } | |
85 | |
86 | |
87 PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) { | |
88 return pre_parser_->ParseV8Intrinsic(ok); | |
89 } | |
90 | |
91 | |
92 PreParserExpression PreParserTraits::ParseFunctionLiteral( | |
93 PreParserIdentifier name, Scanner::Location function_name_location, | |
94 FunctionNameValidity function_name_validity, FunctionKind kind, | |
95 int function_token_position, FunctionLiteral::FunctionType type, | |
96 FunctionLiteral::ArityRestriction arity_restriction, | |
97 LanguageMode language_mode, bool* ok) { | |
98 return pre_parser_->ParseFunctionLiteral( | |
99 name, function_name_location, function_name_validity, kind, | |
100 function_token_position, type, arity_restriction, language_mode, ok); | |
101 } | |
102 | |
103 | |
104 PreParser::PreParseResult PreParser::PreParseLazyFunction( | |
105 LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters, | |
106 ParserRecorder* log, Scanner::BookmarkScope* bookmark) { | |
107 log_ = log; | |
108 // Lazy functions always have trivial outer scopes (no with/catch scopes). | |
109 Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE); | |
110 PreParserFactory top_factory(NULL); | |
111 FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction, | |
112 &top_factory); | |
113 scope_->SetLanguageMode(language_mode); | |
114 Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind); | |
115 if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters(); | |
116 PreParserFactory function_factory(NULL); | |
117 FunctionState function_state(&function_state_, &scope_, function_scope, kind, | |
118 &function_factory); | |
119 DCHECK_EQ(Token::LBRACE, scanner()->current_token()); | |
120 bool ok = true; | |
121 int start_position = peek_position(); | |
122 ParseLazyFunctionLiteralBody(&ok, bookmark); | |
123 if (bookmark && bookmark->HasBeenReset()) { | |
124 // Do nothing, as we've just aborted scanning this function. | |
125 } else if (stack_overflow()) { | |
126 return kPreParseStackOverflow; | |
127 } else if (!ok) { | |
128 ReportUnexpectedToken(scanner()->current_token()); | |
129 } else { | |
130 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | |
131 if (is_strict(scope_->language_mode())) { | |
132 int end_pos = scanner()->location().end_pos; | |
133 CheckStrictOctalLiteral(start_position, end_pos, &ok); | |
134 if (!ok) return kPreParseSuccess; | |
135 | |
136 if (is_strong(scope_->language_mode()) && IsSubclassConstructor(kind)) { | |
137 if (!function_state.super_location().IsValid()) { | |
138 ReportMessageAt(Scanner::Location(start_position, start_position + 1), | |
139 MessageTemplate::kStrongSuperCallMissing, | |
140 kReferenceError); | |
141 return kPreParseSuccess; | |
142 } | |
143 } | |
144 } | |
145 } | |
146 return kPreParseSuccess; | |
147 } | |
148 | |
149 | |
150 PreParserExpression PreParserTraits::ParseClassLiteral( | |
151 PreParserIdentifier name, Scanner::Location class_name_location, | |
152 bool name_is_strict_reserved, int pos, bool* ok) { | |
153 return pre_parser_->ParseClassLiteral(name, class_name_location, | |
154 name_is_strict_reserved, pos, ok); | |
155 } | |
156 | |
157 | |
158 // Preparsing checks a JavaScript program and emits preparse-data that helps | |
159 // a later parsing to be faster. | |
160 // See preparser-data.h for the data. | |
161 | |
162 // The PreParser checks that the syntax follows the grammar for JavaScript, | |
163 // and collects some information about the program along the way. | |
164 // The grammar check is only performed in order to understand the program | |
165 // sufficiently to deduce some information about it, that can be used | |
166 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | |
167 // rather it is to speed up properly written and correct programs. | |
168 // That means that contextual checks (like a label being declared where | |
169 // it is used) are generally omitted. | |
170 | |
171 | |
172 PreParser::Statement PreParser::ParseStatementListItem(bool* ok) { | |
173 // ECMA 262 6th Edition | |
174 // StatementListItem[Yield, Return] : | |
175 // Statement[?Yield, ?Return] | |
176 // Declaration[?Yield] | |
177 // | |
178 // Declaration[Yield] : | |
179 // HoistableDeclaration[?Yield] | |
180 // ClassDeclaration[?Yield] | |
181 // LexicalDeclaration[In, ?Yield] | |
182 // | |
183 // HoistableDeclaration[Yield, Default] : | |
184 // FunctionDeclaration[?Yield, ?Default] | |
185 // GeneratorDeclaration[?Yield, ?Default] | |
186 // | |
187 // LexicalDeclaration[In, Yield] : | |
188 // LetOrConst BindingList[?In, ?Yield] ; | |
189 | |
190 switch (peek()) { | |
191 case Token::FUNCTION: | |
192 return ParseFunctionDeclaration(ok); | |
193 case Token::CLASS: | |
194 return ParseClassDeclaration(ok); | |
195 case Token::CONST: | |
196 if (allow_const()) { | |
197 return ParseVariableStatement(kStatementListItem, ok); | |
198 } | |
199 break; | |
200 case Token::LET: | |
201 if (IsNextLetKeyword()) { | |
202 return ParseVariableStatement(kStatementListItem, ok); | |
203 } | |
204 break; | |
205 default: | |
206 break; | |
207 } | |
208 return ParseStatement(ok); | |
209 } | |
210 | |
211 | |
212 void PreParser::ParseStatementList(int end_token, bool* ok, | |
213 Scanner::BookmarkScope* bookmark) { | |
214 // SourceElements :: | |
215 // (Statement)* <end_token> | |
216 | |
217 // Bookkeeping for trial parse if bookmark is set: | |
218 DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet()); | |
219 bool maybe_reset = bookmark != nullptr; | |
220 int count_statements = 0; | |
221 | |
222 bool directive_prologue = true; | |
223 while (peek() != end_token) { | |
224 if (directive_prologue && peek() != Token::STRING) { | |
225 directive_prologue = false; | |
226 } | |
227 bool starts_with_identifier = peek() == Token::IDENTIFIER; | |
228 Scanner::Location token_loc = scanner()->peek_location(); | |
229 Scanner::Location old_this_loc = function_state_->this_location(); | |
230 Scanner::Location old_super_loc = function_state_->super_location(); | |
231 Statement statement = ParseStatementListItem(ok); | |
232 if (!*ok) return; | |
233 | |
234 if (is_strong(language_mode()) && scope_->is_function_scope() && | |
235 IsClassConstructor(function_state_->kind())) { | |
236 Scanner::Location this_loc = function_state_->this_location(); | |
237 Scanner::Location super_loc = function_state_->super_location(); | |
238 if (this_loc.beg_pos != old_this_loc.beg_pos && | |
239 this_loc.beg_pos != token_loc.beg_pos) { | |
240 ReportMessageAt(this_loc, MessageTemplate::kStrongConstructorThis); | |
241 *ok = false; | |
242 return; | |
243 } | |
244 if (super_loc.beg_pos != old_super_loc.beg_pos && | |
245 super_loc.beg_pos != token_loc.beg_pos) { | |
246 ReportMessageAt(super_loc, MessageTemplate::kStrongConstructorSuper); | |
247 *ok = false; | |
248 return; | |
249 } | |
250 } | |
251 | |
252 if (directive_prologue) { | |
253 bool use_strict_found = statement.IsUseStrictLiteral(); | |
254 bool use_strong_found = | |
255 statement.IsUseStrongLiteral() && allow_strong_mode(); | |
256 | |
257 if (use_strict_found) { | |
258 scope_->SetLanguageMode( | |
259 static_cast<LanguageMode>(scope_->language_mode() | STRICT)); | |
260 } else if (use_strong_found) { | |
261 scope_->SetLanguageMode(static_cast<LanguageMode>( | |
262 scope_->language_mode() | STRONG)); | |
263 if (IsClassConstructor(function_state_->kind())) { | |
264 // "use strong" cannot occur in a class constructor body, to avoid | |
265 // unintuitive strong class object semantics. | |
266 PreParserTraits::ReportMessageAt( | |
267 token_loc, MessageTemplate::kStrongConstructorDirective); | |
268 *ok = false; | |
269 return; | |
270 } | |
271 } else if (!statement.IsStringLiteral()) { | |
272 directive_prologue = false; | |
273 } | |
274 | |
275 if ((use_strict_found || use_strong_found) && | |
276 !scope_->HasSimpleParameters()) { | |
277 // TC39 deemed "use strict" directives to be an error when occurring | |
278 // in the body of a function with non-simple parameter list, on | |
279 // 29/7/2015. https://goo.gl/ueA7Ln | |
280 // | |
281 // In V8, this also applies to "use strong " directives. | |
282 PreParserTraits::ReportMessageAt( | |
283 token_loc, MessageTemplate::kIllegalLanguageModeDirective, | |
284 use_strict_found ? "use strict" : "use strong"); | |
285 *ok = false; | |
286 return; | |
287 } | |
288 } | |
289 | |
290 // If we're allowed to reset to a bookmark, we will do so when we see a long | |
291 // and trivial function. | |
292 // Our current definition of 'long and trivial' is: | |
293 // - over 200 statements | |
294 // - all starting with an identifier (i.e., no if, for, while, etc.) | |
295 if (maybe_reset && (!starts_with_identifier || | |
296 ++count_statements > kLazyParseTrialLimit)) { | |
297 if (count_statements > kLazyParseTrialLimit) { | |
298 bookmark->Reset(); | |
299 return; | |
300 } | |
301 maybe_reset = false; | |
302 } | |
303 } | |
304 } | |
305 | |
306 | |
307 #define CHECK_OK ok); \ | |
308 if (!*ok) return Statement::Default(); \ | |
309 ((void)0 | |
310 #define DUMMY ) // to make indentation work | |
311 #undef DUMMY | |
312 | |
313 | |
314 PreParser::Statement PreParser::ParseStatement(bool* ok) { | |
315 // Statement :: | |
316 // EmptyStatement | |
317 // ... | |
318 | |
319 if (peek() == Token::SEMICOLON) { | |
320 Next(); | |
321 return Statement::Default(); | |
322 } | |
323 return ParseSubStatement(ok); | |
324 } | |
325 | |
326 | |
327 PreParser::Statement PreParser::ParseSubStatement(bool* ok) { | |
328 // Statement :: | |
329 // Block | |
330 // VariableStatement | |
331 // EmptyStatement | |
332 // ExpressionStatement | |
333 // IfStatement | |
334 // IterationStatement | |
335 // ContinueStatement | |
336 // BreakStatement | |
337 // ReturnStatement | |
338 // WithStatement | |
339 // LabelledStatement | |
340 // SwitchStatement | |
341 // ThrowStatement | |
342 // TryStatement | |
343 // DebuggerStatement | |
344 | |
345 // Note: Since labels can only be used by 'break' and 'continue' | |
346 // statements, which themselves are only valid within blocks, | |
347 // iterations or 'switch' statements (i.e., BreakableStatements), | |
348 // labels can be simply ignored in all other cases; except for | |
349 // trivial labeled break statements 'label: break label' which is | |
350 // parsed into an empty statement. | |
351 | |
352 // Keep the source position of the statement | |
353 switch (peek()) { | |
354 case Token::LBRACE: | |
355 return ParseBlock(ok); | |
356 | |
357 case Token::SEMICOLON: | |
358 if (is_strong(language_mode())) { | |
359 PreParserTraits::ReportMessageAt(scanner()->peek_location(), | |
360 MessageTemplate::kStrongEmpty); | |
361 *ok = false; | |
362 return Statement::Default(); | |
363 } | |
364 Next(); | |
365 return Statement::Default(); | |
366 | |
367 case Token::IF: | |
368 return ParseIfStatement(ok); | |
369 | |
370 case Token::DO: | |
371 return ParseDoWhileStatement(ok); | |
372 | |
373 case Token::WHILE: | |
374 return ParseWhileStatement(ok); | |
375 | |
376 case Token::FOR: | |
377 return ParseForStatement(ok); | |
378 | |
379 case Token::CONTINUE: | |
380 return ParseContinueStatement(ok); | |
381 | |
382 case Token::BREAK: | |
383 return ParseBreakStatement(ok); | |
384 | |
385 case Token::RETURN: | |
386 return ParseReturnStatement(ok); | |
387 | |
388 case Token::WITH: | |
389 return ParseWithStatement(ok); | |
390 | |
391 case Token::SWITCH: | |
392 return ParseSwitchStatement(ok); | |
393 | |
394 case Token::THROW: | |
395 return ParseThrowStatement(ok); | |
396 | |
397 case Token::TRY: | |
398 return ParseTryStatement(ok); | |
399 | |
400 case Token::FUNCTION: { | |
401 Scanner::Location start_location = scanner()->peek_location(); | |
402 Statement statement = ParseFunctionDeclaration(CHECK_OK); | |
403 Scanner::Location end_location = scanner()->location(); | |
404 if (is_strict(language_mode())) { | |
405 PreParserTraits::ReportMessageAt(start_location.beg_pos, | |
406 end_location.end_pos, | |
407 MessageTemplate::kStrictFunction); | |
408 *ok = false; | |
409 return Statement::Default(); | |
410 } else { | |
411 return statement; | |
412 } | |
413 } | |
414 | |
415 case Token::DEBUGGER: | |
416 return ParseDebuggerStatement(ok); | |
417 | |
418 case Token::VAR: | |
419 return ParseVariableStatement(kStatement, ok); | |
420 | |
421 case Token::CONST: | |
422 // In ES6 CONST is not allowed as a Statement, only as a | |
423 // LexicalDeclaration, however we continue to allow it in sloppy mode for | |
424 // backwards compatibility. | |
425 if (is_sloppy(language_mode()) && allow_legacy_const()) { | |
426 return ParseVariableStatement(kStatement, ok); | |
427 } | |
428 | |
429 // Fall through. | |
430 default: | |
431 return ParseExpressionOrLabelledStatement(ok); | |
432 } | |
433 } | |
434 | |
435 | |
436 PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) { | |
437 // FunctionDeclaration :: | |
438 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' | |
439 // GeneratorDeclaration :: | |
440 // 'function' '*' Identifier '(' FormalParameterListopt ')' | |
441 // '{' FunctionBody '}' | |
442 Expect(Token::FUNCTION, CHECK_OK); | |
443 int pos = position(); | |
444 bool is_generator = Check(Token::MUL); | |
445 bool is_strict_reserved = false; | |
446 Identifier name = ParseIdentifierOrStrictReservedWord( | |
447 &is_strict_reserved, CHECK_OK); | |
448 ParseFunctionLiteral(name, scanner()->location(), | |
449 is_strict_reserved ? kFunctionNameIsStrictReserved | |
450 : kFunctionNameValidityUnknown, | |
451 is_generator ? FunctionKind::kGeneratorFunction | |
452 : FunctionKind::kNormalFunction, | |
453 pos, FunctionLiteral::DECLARATION, | |
454 FunctionLiteral::NORMAL_ARITY, language_mode(), | |
455 CHECK_OK); | |
456 return Statement::FunctionDeclaration(); | |
457 } | |
458 | |
459 | |
460 PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) { | |
461 Expect(Token::CLASS, CHECK_OK); | |
462 if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { | |
463 ReportMessage(MessageTemplate::kSloppyLexical); | |
464 *ok = false; | |
465 return Statement::Default(); | |
466 } | |
467 | |
468 int pos = position(); | |
469 bool is_strict_reserved = false; | |
470 Identifier name = | |
471 ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); | |
472 ParseClassLiteral(name, scanner()->location(), is_strict_reserved, pos, | |
473 CHECK_OK); | |
474 return Statement::Default(); | |
475 } | |
476 | |
477 | |
478 PreParser::Statement PreParser::ParseBlock(bool* ok) { | |
479 // Block :: | |
480 // '{' StatementList '}' | |
481 | |
482 Expect(Token::LBRACE, CHECK_OK); | |
483 Statement final = Statement::Default(); | |
484 while (peek() != Token::RBRACE) { | |
485 final = ParseStatementListItem(CHECK_OK); | |
486 } | |
487 Expect(Token::RBRACE, ok); | |
488 return final; | |
489 } | |
490 | |
491 | |
492 PreParser::Statement PreParser::ParseVariableStatement( | |
493 VariableDeclarationContext var_context, | |
494 bool* ok) { | |
495 // VariableStatement :: | |
496 // VariableDeclarations ';' | |
497 | |
498 Statement result = ParseVariableDeclarations( | |
499 var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK); | |
500 ExpectSemicolon(CHECK_OK); | |
501 return result; | |
502 } | |
503 | |
504 | |
505 // If the variable declaration declares exactly one non-const | |
506 // variable, then *var is set to that variable. In all other cases, | |
507 // *var is untouched; in particular, it is the caller's responsibility | |
508 // to initialize it properly. This mechanism is also used for the parsing | |
509 // of 'for-in' loops. | |
510 PreParser::Statement PreParser::ParseVariableDeclarations( | |
511 VariableDeclarationContext var_context, int* num_decl, bool* is_lexical, | |
512 bool* is_binding_pattern, Scanner::Location* first_initializer_loc, | |
513 Scanner::Location* bindings_loc, bool* ok) { | |
514 // VariableDeclarations :: | |
515 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | |
516 // | |
517 // The ES6 Draft Rev3 specifies the following grammar for const declarations | |
518 // | |
519 // ConstDeclaration :: | |
520 // const ConstBinding (',' ConstBinding)* ';' | |
521 // ConstBinding :: | |
522 // Identifier '=' AssignmentExpression | |
523 // | |
524 // TODO(ES6): | |
525 // ConstBinding :: | |
526 // BindingPattern '=' AssignmentExpression | |
527 bool require_initializer = false; | |
528 bool lexical = false; | |
529 bool is_pattern = false; | |
530 if (peek() == Token::VAR) { | |
531 if (is_strong(language_mode())) { | |
532 Scanner::Location location = scanner()->peek_location(); | |
533 ReportMessageAt(location, MessageTemplate::kStrongVar); | |
534 *ok = false; | |
535 return Statement::Default(); | |
536 } | |
537 Consume(Token::VAR); | |
538 } else if (peek() == Token::CONST && allow_const()) { | |
539 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads: | |
540 // | |
541 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';' | |
542 // | |
543 // * It is a Syntax Error if the code that matches this production is not | |
544 // contained in extended code. | |
545 // | |
546 // However disallowing const in sloppy mode will break compatibility with | |
547 // existing pages. Therefore we keep allowing const with the old | |
548 // non-harmony semantics in sloppy mode. | |
549 Consume(Token::CONST); | |
550 if (is_strict(language_mode()) || | |
551 (allow_harmony_sloppy() && !allow_legacy_const())) { | |
552 DCHECK(var_context != kStatement); | |
553 require_initializer = true; | |
554 lexical = true; | |
555 } | |
556 } else if (peek() == Token::LET && allow_let()) { | |
557 Consume(Token::LET); | |
558 DCHECK(var_context != kStatement); | |
559 lexical = true; | |
560 } else { | |
561 *ok = false; | |
562 return Statement::Default(); | |
563 } | |
564 | |
565 // The scope of a var/const declared variable anywhere inside a function | |
566 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope | |
567 // of a let declared variable is the scope of the immediately enclosing | |
568 // block. | |
569 int nvars = 0; // the number of variables declared | |
570 int bindings_start = peek_position(); | |
571 do { | |
572 // Parse binding pattern. | |
573 if (nvars > 0) Consume(Token::COMMA); | |
574 int decl_pos = peek_position(); | |
575 PreParserExpression pattern = PreParserExpression::Default(); | |
576 { | |
577 ExpressionClassifier pattern_classifier; | |
578 Token::Value next = peek(); | |
579 pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK); | |
580 | |
581 ValidateBindingPattern(&pattern_classifier, CHECK_OK); | |
582 if (lexical) { | |
583 ValidateLetPattern(&pattern_classifier, CHECK_OK); | |
584 } | |
585 | |
586 if (!allow_harmony_destructuring_bind() && !pattern.IsIdentifier()) { | |
587 ReportUnexpectedToken(next); | |
588 *ok = false; | |
589 return Statement::Default(); | |
590 } | |
591 } | |
592 | |
593 is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral(); | |
594 | |
595 bool is_for_iteration_variable = | |
596 var_context == kForStatement && | |
597 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); | |
598 | |
599 Scanner::Location variable_loc = scanner()->location(); | |
600 nvars++; | |
601 if (Check(Token::ASSIGN)) { | |
602 ExpressionClassifier classifier; | |
603 ParseAssignmentExpression(var_context != kForStatement, &classifier, | |
604 CHECK_OK); | |
605 ValidateExpression(&classifier, CHECK_OK); | |
606 | |
607 variable_loc.end_pos = scanner()->location().end_pos; | |
608 if (first_initializer_loc && !first_initializer_loc->IsValid()) { | |
609 *first_initializer_loc = variable_loc; | |
610 } | |
611 } else if ((require_initializer || is_pattern) && | |
612 !is_for_iteration_variable) { | |
613 PreParserTraits::ReportMessageAt( | |
614 Scanner::Location(decl_pos, scanner()->location().end_pos), | |
615 MessageTemplate::kDeclarationMissingInitializer, | |
616 is_pattern ? "destructuring" : "const"); | |
617 *ok = false; | |
618 return Statement::Default(); | |
619 } | |
620 } while (peek() == Token::COMMA); | |
621 | |
622 if (bindings_loc) { | |
623 *bindings_loc = | |
624 Scanner::Location(bindings_start, scanner()->location().end_pos); | |
625 } | |
626 | |
627 if (num_decl != nullptr) *num_decl = nvars; | |
628 if (is_lexical != nullptr) *is_lexical = lexical; | |
629 if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern; | |
630 return Statement::Default(); | |
631 } | |
632 | |
633 | |
634 PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) { | |
635 // ExpressionStatement | LabelledStatement :: | |
636 // Expression ';' | |
637 // Identifier ':' Statement | |
638 | |
639 switch (peek()) { | |
640 case Token::FUNCTION: | |
641 case Token::LBRACE: | |
642 UNREACHABLE(); // Always handled by the callers. | |
643 case Token::CLASS: | |
644 ReportUnexpectedToken(Next()); | |
645 *ok = false; | |
646 return Statement::Default(); | |
647 | |
648 case Token::THIS: | |
649 if (!FLAG_strong_this) break; | |
650 // Fall through. | |
651 case Token::SUPER: | |
652 if (is_strong(language_mode()) && | |
653 IsClassConstructor(function_state_->kind())) { | |
654 bool is_this = peek() == Token::THIS; | |
655 Expression expr = Expression::Default(); | |
656 ExpressionClassifier classifier; | |
657 if (is_this) { | |
658 expr = ParseStrongInitializationExpression(&classifier, CHECK_OK); | |
659 } else { | |
660 expr = ParseStrongSuperCallExpression(&classifier, CHECK_OK); | |
661 } | |
662 ValidateExpression(&classifier, CHECK_OK); | |
663 switch (peek()) { | |
664 case Token::SEMICOLON: | |
665 Consume(Token::SEMICOLON); | |
666 break; | |
667 case Token::RBRACE: | |
668 case Token::EOS: | |
669 break; | |
670 default: | |
671 if (!scanner()->HasAnyLineTerminatorBeforeNext()) { | |
672 ReportMessageAt(function_state_->this_location(), | |
673 is_this | |
674 ? MessageTemplate::kStrongConstructorThis | |
675 : MessageTemplate::kStrongConstructorSuper); | |
676 *ok = false; | |
677 return Statement::Default(); | |
678 } | |
679 } | |
680 return Statement::ExpressionStatement(expr); | |
681 } | |
682 break; | |
683 | |
684 // TODO(arv): Handle `let [` | |
685 // https://code.google.com/p/v8/issues/detail?id=3847 | |
686 | |
687 default: | |
688 break; | |
689 } | |
690 | |
691 bool starts_with_identifier = peek_any_identifier(); | |
692 ExpressionClassifier classifier; | |
693 Expression expr = ParseExpression(true, &classifier, CHECK_OK); | |
694 ValidateExpression(&classifier, CHECK_OK); | |
695 | |
696 // Even if the expression starts with an identifier, it is not necessarily an | |
697 // identifier. For example, "foo + bar" starts with an identifier but is not | |
698 // an identifier. | |
699 if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) { | |
700 // Expression is a single identifier, and not, e.g., a parenthesized | |
701 // identifier. | |
702 DCHECK(!expr.AsIdentifier().IsFutureReserved()); | |
703 DCHECK(is_sloppy(language_mode()) || | |
704 !IsFutureStrictReserved(expr.AsIdentifier())); | |
705 Consume(Token::COLON); | |
706 Statement statement = ParseStatement(ok); | |
707 return statement.IsJumpStatement() ? Statement::Default() : statement; | |
708 // Preparsing is disabled for extensions (because the extension details | |
709 // aren't passed to lazily compiled functions), so we don't | |
710 // accept "native function" in the preparser. | |
711 } | |
712 // Parsed expression statement. | |
713 // Detect attempts at 'let' declarations in sloppy mode. | |
714 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
715 is_sloppy(language_mode()) && expr.IsIdentifier() && | |
716 expr.AsIdentifier().IsLet()) { | |
717 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
718 *ok = false; | |
719 return Statement::Default(); | |
720 } | |
721 ExpectSemicolon(CHECK_OK); | |
722 return Statement::ExpressionStatement(expr); | |
723 } | |
724 | |
725 | |
726 PreParser::Statement PreParser::ParseIfStatement(bool* ok) { | |
727 // IfStatement :: | |
728 // 'if' '(' Expression ')' Statement ('else' Statement)? | |
729 | |
730 Expect(Token::IF, CHECK_OK); | |
731 Expect(Token::LPAREN, CHECK_OK); | |
732 ParseExpression(true, CHECK_OK); | |
733 Expect(Token::RPAREN, CHECK_OK); | |
734 Statement stat = ParseSubStatement(CHECK_OK); | |
735 if (peek() == Token::ELSE) { | |
736 Next(); | |
737 Statement else_stat = ParseSubStatement(CHECK_OK); | |
738 stat = (stat.IsJumpStatement() && else_stat.IsJumpStatement()) ? | |
739 Statement::Jump() : Statement::Default(); | |
740 } else { | |
741 stat = Statement::Default(); | |
742 } | |
743 return stat; | |
744 } | |
745 | |
746 | |
747 PreParser::Statement PreParser::ParseContinueStatement(bool* ok) { | |
748 // ContinueStatement :: | |
749 // 'continue' [no line terminator] Identifier? ';' | |
750 | |
751 Expect(Token::CONTINUE, CHECK_OK); | |
752 Token::Value tok = peek(); | |
753 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
754 tok != Token::SEMICOLON && | |
755 tok != Token::RBRACE && | |
756 tok != Token::EOS) { | |
757 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
758 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
759 } | |
760 ExpectSemicolon(CHECK_OK); | |
761 return Statement::Jump(); | |
762 } | |
763 | |
764 | |
765 PreParser::Statement PreParser::ParseBreakStatement(bool* ok) { | |
766 // BreakStatement :: | |
767 // 'break' [no line terminator] Identifier? ';' | |
768 | |
769 Expect(Token::BREAK, CHECK_OK); | |
770 Token::Value tok = peek(); | |
771 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
772 tok != Token::SEMICOLON && | |
773 tok != Token::RBRACE && | |
774 tok != Token::EOS) { | |
775 // ECMA allows "eval" or "arguments" as labels even in strict mode. | |
776 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
777 } | |
778 ExpectSemicolon(CHECK_OK); | |
779 return Statement::Jump(); | |
780 } | |
781 | |
782 | |
783 PreParser::Statement PreParser::ParseReturnStatement(bool* ok) { | |
784 // ReturnStatement :: | |
785 // 'return' [no line terminator] Expression? ';' | |
786 | |
787 // Consume the return token. It is necessary to do before | |
788 // reporting any errors on it, because of the way errors are | |
789 // reported (underlining). | |
790 Expect(Token::RETURN, CHECK_OK); | |
791 function_state_->set_return_location(scanner()->location()); | |
792 | |
793 // An ECMAScript program is considered syntactically incorrect if it | |
794 // contains a return statement that is not within the body of a | |
795 // function. See ECMA-262, section 12.9, page 67. | |
796 // This is not handled during preparsing. | |
797 | |
798 Token::Value tok = peek(); | |
799 if (!scanner()->HasAnyLineTerminatorBeforeNext() && | |
800 tok != Token::SEMICOLON && | |
801 tok != Token::RBRACE && | |
802 tok != Token::EOS) { | |
803 if (is_strong(language_mode()) && | |
804 IsClassConstructor(function_state_->kind())) { | |
805 int pos = peek_position(); | |
806 ReportMessageAt(Scanner::Location(pos, pos + 1), | |
807 MessageTemplate::kStrongConstructorReturnValue); | |
808 *ok = false; | |
809 return Statement::Default(); | |
810 } | |
811 ParseExpression(true, CHECK_OK); | |
812 } | |
813 ExpectSemicolon(CHECK_OK); | |
814 return Statement::Jump(); | |
815 } | |
816 | |
817 | |
818 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { | |
819 // WithStatement :: | |
820 // 'with' '(' Expression ')' Statement | |
821 Expect(Token::WITH, CHECK_OK); | |
822 if (is_strict(language_mode())) { | |
823 ReportMessageAt(scanner()->location(), MessageTemplate::kStrictWith); | |
824 *ok = false; | |
825 return Statement::Default(); | |
826 } | |
827 Expect(Token::LPAREN, CHECK_OK); | |
828 ParseExpression(true, CHECK_OK); | |
829 Expect(Token::RPAREN, CHECK_OK); | |
830 | |
831 Scope* with_scope = NewScope(scope_, WITH_SCOPE); | |
832 BlockState block_state(&scope_, with_scope); | |
833 ParseSubStatement(CHECK_OK); | |
834 return Statement::Default(); | |
835 } | |
836 | |
837 | |
838 PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) { | |
839 // SwitchStatement :: | |
840 // 'switch' '(' Expression ')' '{' CaseClause* '}' | |
841 | |
842 Expect(Token::SWITCH, CHECK_OK); | |
843 Expect(Token::LPAREN, CHECK_OK); | |
844 ParseExpression(true, CHECK_OK); | |
845 Expect(Token::RPAREN, CHECK_OK); | |
846 | |
847 Expect(Token::LBRACE, CHECK_OK); | |
848 Token::Value token = peek(); | |
849 while (token != Token::RBRACE) { | |
850 if (token == Token::CASE) { | |
851 Expect(Token::CASE, CHECK_OK); | |
852 ParseExpression(true, CHECK_OK); | |
853 } else { | |
854 Expect(Token::DEFAULT, CHECK_OK); | |
855 } | |
856 Expect(Token::COLON, CHECK_OK); | |
857 token = peek(); | |
858 Statement statement = Statement::Jump(); | |
859 while (token != Token::CASE && | |
860 token != Token::DEFAULT && | |
861 token != Token::RBRACE) { | |
862 statement = ParseStatementListItem(CHECK_OK); | |
863 token = peek(); | |
864 } | |
865 if (is_strong(language_mode()) && !statement.IsJumpStatement() && | |
866 token != Token::RBRACE) { | |
867 ReportMessageAt(scanner()->location(), | |
868 MessageTemplate::kStrongSwitchFallthrough); | |
869 *ok = false; | |
870 return Statement::Default(); | |
871 } | |
872 } | |
873 Expect(Token::RBRACE, ok); | |
874 return Statement::Default(); | |
875 } | |
876 | |
877 | |
878 PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) { | |
879 // DoStatement :: | |
880 // 'do' Statement 'while' '(' Expression ')' ';' | |
881 | |
882 Expect(Token::DO, CHECK_OK); | |
883 ParseSubStatement(CHECK_OK); | |
884 Expect(Token::WHILE, CHECK_OK); | |
885 Expect(Token::LPAREN, CHECK_OK); | |
886 ParseExpression(true, CHECK_OK); | |
887 Expect(Token::RPAREN, ok); | |
888 if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON); | |
889 return Statement::Default(); | |
890 } | |
891 | |
892 | |
893 PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { | |
894 // WhileStatement :: | |
895 // 'while' '(' Expression ')' Statement | |
896 | |
897 Expect(Token::WHILE, CHECK_OK); | |
898 Expect(Token::LPAREN, CHECK_OK); | |
899 ParseExpression(true, CHECK_OK); | |
900 Expect(Token::RPAREN, CHECK_OK); | |
901 ParseSubStatement(ok); | |
902 return Statement::Default(); | |
903 } | |
904 | |
905 | |
906 PreParser::Statement PreParser::ParseForStatement(bool* ok) { | |
907 // ForStatement :: | |
908 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement | |
909 | |
910 Expect(Token::FOR, CHECK_OK); | |
911 Expect(Token::LPAREN, CHECK_OK); | |
912 bool is_let_identifier_expression = false; | |
913 if (peek() != Token::SEMICOLON) { | |
914 ForEachStatement::VisitMode mode; | |
915 if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) || | |
916 (peek() == Token::LET && IsNextLetKeyword())) { | |
917 int decl_count; | |
918 bool is_lexical; | |
919 bool is_binding_pattern; | |
920 Scanner::Location first_initializer_loc = Scanner::Location::invalid(); | |
921 Scanner::Location bindings_loc = Scanner::Location::invalid(); | |
922 ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical, | |
923 &is_binding_pattern, &first_initializer_loc, | |
924 &bindings_loc, CHECK_OK); | |
925 bool accept_IN = decl_count >= 1; | |
926 if (accept_IN && CheckInOrOf(&mode, ok)) { | |
927 if (!*ok) return Statement::Default(); | |
928 if (decl_count != 1) { | |
929 const char* loop_type = | |
930 mode == ForEachStatement::ITERATE ? "for-of" : "for-in"; | |
931 PreParserTraits::ReportMessageAt( | |
932 bindings_loc, MessageTemplate::kForInOfLoopMultiBindings, | |
933 loop_type); | |
934 *ok = false; | |
935 return Statement::Default(); | |
936 } | |
937 if (first_initializer_loc.IsValid() && | |
938 (is_strict(language_mode()) || mode == ForEachStatement::ITERATE || | |
939 is_lexical || is_binding_pattern)) { | |
940 if (mode == ForEachStatement::ITERATE) { | |
941 ReportMessageAt(first_initializer_loc, | |
942 MessageTemplate::kForOfLoopInitializer); | |
943 } else { | |
944 // TODO(caitp): This should be an error in sloppy mode, too. | |
945 ReportMessageAt(first_initializer_loc, | |
946 MessageTemplate::kForInLoopInitializer); | |
947 } | |
948 *ok = false; | |
949 return Statement::Default(); | |
950 } | |
951 ParseExpression(true, CHECK_OK); | |
952 Expect(Token::RPAREN, CHECK_OK); | |
953 ParseSubStatement(CHECK_OK); | |
954 return Statement::Default(); | |
955 } | |
956 } else { | |
957 int lhs_beg_pos = peek_position(); | |
958 Expression lhs = ParseExpression(false, CHECK_OK); | |
959 int lhs_end_pos = scanner()->location().end_pos; | |
960 is_let_identifier_expression = | |
961 lhs.IsIdentifier() && lhs.AsIdentifier().IsLet(); | |
962 if (CheckInOrOf(&mode, ok)) { | |
963 if (!*ok) return Statement::Default(); | |
964 lhs = CheckAndRewriteReferenceExpression( | |
965 lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, | |
966 kSyntaxError, CHECK_OK); | |
967 ParseExpression(true, CHECK_OK); | |
968 Expect(Token::RPAREN, CHECK_OK); | |
969 ParseSubStatement(CHECK_OK); | |
970 return Statement::Default(); | |
971 } | |
972 } | |
973 } | |
974 | |
975 // Parsed initializer at this point. | |
976 // Detect attempts at 'let' declarations in sloppy mode. | |
977 if (!allow_harmony_sloppy_let() && peek() == Token::IDENTIFIER && | |
978 is_sloppy(language_mode()) && is_let_identifier_expression) { | |
979 ReportMessage(MessageTemplate::kSloppyLexical, NULL); | |
980 *ok = false; | |
981 return Statement::Default(); | |
982 } | |
983 Expect(Token::SEMICOLON, CHECK_OK); | |
984 | |
985 if (peek() != Token::SEMICOLON) { | |
986 ParseExpression(true, CHECK_OK); | |
987 } | |
988 Expect(Token::SEMICOLON, CHECK_OK); | |
989 | |
990 if (peek() != Token::RPAREN) { | |
991 ParseExpression(true, CHECK_OK); | |
992 } | |
993 Expect(Token::RPAREN, CHECK_OK); | |
994 | |
995 ParseSubStatement(ok); | |
996 return Statement::Default(); | |
997 } | |
998 | |
999 | |
1000 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { | |
1001 // ThrowStatement :: | |
1002 // 'throw' [no line terminator] Expression ';' | |
1003 | |
1004 Expect(Token::THROW, CHECK_OK); | |
1005 if (scanner()->HasAnyLineTerminatorBeforeNext()) { | |
1006 ReportMessageAt(scanner()->location(), MessageTemplate::kNewlineAfterThrow); | |
1007 *ok = false; | |
1008 return Statement::Default(); | |
1009 } | |
1010 ParseExpression(true, CHECK_OK); | |
1011 ExpectSemicolon(ok); | |
1012 return Statement::Jump(); | |
1013 } | |
1014 | |
1015 | |
1016 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { | |
1017 // TryStatement :: | |
1018 // 'try' Block Catch | |
1019 // 'try' Block Finally | |
1020 // 'try' Block Catch Finally | |
1021 // | |
1022 // Catch :: | |
1023 // 'catch' '(' Identifier ')' Block | |
1024 // | |
1025 // Finally :: | |
1026 // 'finally' Block | |
1027 | |
1028 Expect(Token::TRY, CHECK_OK); | |
1029 | |
1030 ParseBlock(CHECK_OK); | |
1031 | |
1032 Token::Value tok = peek(); | |
1033 if (tok != Token::CATCH && tok != Token::FINALLY) { | |
1034 ReportMessageAt(scanner()->location(), MessageTemplate::kNoCatchOrFinally); | |
1035 *ok = false; | |
1036 return Statement::Default(); | |
1037 } | |
1038 if (tok == Token::CATCH) { | |
1039 Consume(Token::CATCH); | |
1040 Expect(Token::LPAREN, CHECK_OK); | |
1041 ExpressionClassifier pattern_classifier; | |
1042 ParsePrimaryExpression(&pattern_classifier, CHECK_OK); | |
1043 ValidateBindingPattern(&pattern_classifier, CHECK_OK); | |
1044 Expect(Token::RPAREN, CHECK_OK); | |
1045 { | |
1046 // TODO(adamk): Make this CATCH_SCOPE | |
1047 Scope* with_scope = NewScope(scope_, WITH_SCOPE); | |
1048 BlockState block_state(&scope_, with_scope); | |
1049 ParseBlock(CHECK_OK); | |
1050 } | |
1051 tok = peek(); | |
1052 } | |
1053 if (tok == Token::FINALLY) { | |
1054 Consume(Token::FINALLY); | |
1055 ParseBlock(CHECK_OK); | |
1056 } | |
1057 return Statement::Default(); | |
1058 } | |
1059 | |
1060 | |
1061 PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) { | |
1062 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser | |
1063 // contexts this is used as a statement which invokes the debugger as if a | |
1064 // break point is present. | |
1065 // DebuggerStatement :: | |
1066 // 'debugger' ';' | |
1067 | |
1068 Expect(Token::DEBUGGER, CHECK_OK); | |
1069 ExpectSemicolon(ok); | |
1070 return Statement::Default(); | |
1071 } | |
1072 | |
1073 | |
1074 #undef CHECK_OK | |
1075 #define CHECK_OK ok); \ | |
1076 if (!*ok) return Expression::Default(); \ | |
1077 ((void)0 | |
1078 #define DUMMY ) // to make indentation work | |
1079 #undef DUMMY | |
1080 | |
1081 | |
1082 PreParser::Expression PreParser::ParseFunctionLiteral( | |
1083 Identifier function_name, Scanner::Location function_name_location, | |
1084 FunctionNameValidity function_name_validity, FunctionKind kind, | |
1085 int function_token_pos, FunctionLiteral::FunctionType function_type, | |
1086 FunctionLiteral::ArityRestriction arity_restriction, | |
1087 LanguageMode language_mode, bool* ok) { | |
1088 // Function :: | |
1089 // '(' FormalParameterList? ')' '{' FunctionBody '}' | |
1090 | |
1091 // Parse function body. | |
1092 bool outer_is_script_scope = scope_->is_script_scope(); | |
1093 Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind); | |
1094 function_scope->SetLanguageMode(language_mode); | |
1095 PreParserFactory factory(NULL); | |
1096 FunctionState function_state(&function_state_, &scope_, function_scope, kind, | |
1097 &factory); | |
1098 DuplicateFinder duplicate_finder(scanner()->unicode_cache()); | |
1099 ExpressionClassifier formals_classifier(&duplicate_finder); | |
1100 | |
1101 Expect(Token::LPAREN, CHECK_OK); | |
1102 int start_position = scanner()->location().beg_pos; | |
1103 function_scope->set_start_position(start_position); | |
1104 PreParserFormalParameters formals(function_scope); | |
1105 ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK); | |
1106 Expect(Token::RPAREN, CHECK_OK); | |
1107 int formals_end_position = scanner()->location().end_pos; | |
1108 | |
1109 CheckArityRestrictions(formals.arity, arity_restriction, | |
1110 formals.has_rest, start_position, | |
1111 formals_end_position, CHECK_OK); | |
1112 | |
1113 // See Parser::ParseFunctionLiteral for more information about lazy parsing | |
1114 // and lazy compilation. | |
1115 bool is_lazily_parsed = | |
1116 (outer_is_script_scope && allow_lazy() && !parenthesized_function_); | |
1117 parenthesized_function_ = false; | |
1118 | |
1119 Expect(Token::LBRACE, CHECK_OK); | |
1120 if (is_lazily_parsed) { | |
1121 ParseLazyFunctionLiteralBody(CHECK_OK); | |
1122 } else { | |
1123 ParseStatementList(Token::RBRACE, CHECK_OK); | |
1124 } | |
1125 Expect(Token::RBRACE, CHECK_OK); | |
1126 | |
1127 // Parsing the body may change the language mode in our scope. | |
1128 language_mode = function_scope->language_mode(); | |
1129 | |
1130 // Validate name and parameter names. We can do this only after parsing the | |
1131 // function, since the function can declare itself strict. | |
1132 CheckFunctionName(language_mode, function_name, function_name_validity, | |
1133 function_name_location, CHECK_OK); | |
1134 const bool allow_duplicate_parameters = | |
1135 is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind); | |
1136 ValidateFormalParameters(&formals_classifier, language_mode, | |
1137 allow_duplicate_parameters, CHECK_OK); | |
1138 | |
1139 if (is_strict(language_mode)) { | |
1140 int end_position = scanner()->location().end_pos; | |
1141 CheckStrictOctalLiteral(start_position, end_position, CHECK_OK); | |
1142 } | |
1143 | |
1144 if (is_strong(language_mode) && IsSubclassConstructor(kind)) { | |
1145 if (!function_state.super_location().IsValid()) { | |
1146 ReportMessageAt(function_name_location, | |
1147 MessageTemplate::kStrongSuperCallMissing, | |
1148 kReferenceError); | |
1149 *ok = false; | |
1150 return Expression::Default(); | |
1151 } | |
1152 } | |
1153 | |
1154 return Expression::Default(); | |
1155 } | |
1156 | |
1157 | |
1158 void PreParser::ParseLazyFunctionLiteralBody(bool* ok, | |
1159 Scanner::BookmarkScope* bookmark) { | |
1160 int body_start = position(); | |
1161 ParseStatementList(Token::RBRACE, ok, bookmark); | |
1162 if (!*ok) return; | |
1163 if (bookmark && bookmark->HasBeenReset()) return; | |
1164 | |
1165 // Position right after terminal '}'. | |
1166 DCHECK_EQ(Token::RBRACE, scanner()->peek()); | |
1167 int body_end = scanner()->peek_location().end_pos; | |
1168 log_->LogFunction(body_start, body_end, | |
1169 function_state_->materialized_literal_count(), | |
1170 function_state_->expected_property_count(), language_mode(), | |
1171 scope_->uses_super_property(), scope_->calls_eval()); | |
1172 } | |
1173 | |
1174 | |
1175 PreParserExpression PreParser::ParseClassLiteral( | |
1176 PreParserIdentifier name, Scanner::Location class_name_location, | |
1177 bool name_is_strict_reserved, int pos, bool* ok) { | |
1178 // All parts of a ClassDeclaration and ClassExpression are strict code. | |
1179 if (name_is_strict_reserved) { | |
1180 ReportMessageAt(class_name_location, | |
1181 MessageTemplate::kUnexpectedStrictReserved); | |
1182 *ok = false; | |
1183 return EmptyExpression(); | |
1184 } | |
1185 if (IsEvalOrArguments(name)) { | |
1186 ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments); | |
1187 *ok = false; | |
1188 return EmptyExpression(); | |
1189 } | |
1190 LanguageMode class_language_mode = language_mode(); | |
1191 if (is_strong(class_language_mode) && IsUndefined(name)) { | |
1192 ReportMessageAt(class_name_location, MessageTemplate::kStrongUndefined); | |
1193 *ok = false; | |
1194 return EmptyExpression(); | |
1195 } | |
1196 | |
1197 Scope* scope = NewScope(scope_, BLOCK_SCOPE); | |
1198 BlockState block_state(&scope_, scope); | |
1199 scope_->SetLanguageMode( | |
1200 static_cast<LanguageMode>(class_language_mode | STRICT)); | |
1201 // TODO(marja): Make PreParser use scope names too. | |
1202 // scope_->SetScopeName(name); | |
1203 | |
1204 bool has_extends = Check(Token::EXTENDS); | |
1205 if (has_extends) { | |
1206 ExpressionClassifier classifier; | |
1207 ParseLeftHandSideExpression(&classifier, CHECK_OK); | |
1208 ValidateExpression(&classifier, CHECK_OK); | |
1209 } | |
1210 | |
1211 ClassLiteralChecker checker(this); | |
1212 bool has_seen_constructor = false; | |
1213 | |
1214 Expect(Token::LBRACE, CHECK_OK); | |
1215 while (peek() != Token::RBRACE) { | |
1216 if (Check(Token::SEMICOLON)) continue; | |
1217 const bool in_class = true; | |
1218 const bool is_static = false; | |
1219 bool is_computed_name = false; // Classes do not care about computed | |
1220 // property names here. | |
1221 ExpressionClassifier classifier; | |
1222 ParsePropertyDefinition(&checker, in_class, has_extends, is_static, | |
1223 &is_computed_name, &has_seen_constructor, | |
1224 &classifier, CHECK_OK); | |
1225 ValidateExpression(&classifier, CHECK_OK); | |
1226 } | |
1227 | |
1228 Expect(Token::RBRACE, CHECK_OK); | |
1229 | |
1230 return Expression::Default(); | |
1231 } | |
1232 | |
1233 | |
1234 PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { | |
1235 // CallRuntime :: | |
1236 // '%' Identifier Arguments | |
1237 Expect(Token::MOD, CHECK_OK); | |
1238 if (!allow_natives()) { | |
1239 *ok = false; | |
1240 return Expression::Default(); | |
1241 } | |
1242 // Allow "eval" or "arguments" for backward compatibility. | |
1243 ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK); | |
1244 Scanner::Location spread_pos; | |
1245 ExpressionClassifier classifier; | |
1246 ParseArguments(&spread_pos, &classifier, ok); | |
1247 ValidateExpression(&classifier, CHECK_OK); | |
1248 | |
1249 DCHECK(!spread_pos.IsValid()); | |
1250 | |
1251 return Expression::Default(); | |
1252 } | |
1253 | |
1254 | |
1255 PreParserExpression PreParser::ParseDoExpression(bool* ok) { | |
1256 // AssignmentExpression :: | |
1257 // do '{' StatementList '}' | |
1258 Expect(Token::DO, CHECK_OK); | |
1259 Expect(Token::LBRACE, CHECK_OK); | |
1260 Scope* block_scope = NewScope(scope_, BLOCK_SCOPE); | |
1261 { | |
1262 BlockState block_state(&scope_, block_scope); | |
1263 while (peek() != Token::RBRACE) { | |
1264 ParseStatementListItem(CHECK_OK); | |
1265 } | |
1266 Expect(Token::RBRACE, CHECK_OK); | |
1267 return PreParserExpression::Default(); | |
1268 } | |
1269 } | |
1270 | |
1271 #undef CHECK_OK | |
1272 | |
1273 | |
1274 } // namespace internal | |
1275 } // namespace v8 | |
OLD | NEW |