blob: 3268e3c508bc2fb6887564b5d03e5675c2f46d2a [file] [log] [blame]
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001// Copyright 2011 the V8 project authors. All rights reserved.
ager@chromium.orgbeb25712010-11-29 08:02:25 +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
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000028#include <cmath>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000029
ricow@chromium.org55ee8072011-09-08 16:33:10 +000030#include "../include/v8stdint.h"
31
32#include "allocation.h"
33#include "checks.h"
34#include "conversions.h"
35#include "conversions-inl.h"
36#include "globals.h"
37#include "hashmap.h"
38#include "list.h"
lrn@chromium.org1c092762011-05-09 09:42:16 +000039#include "preparse-data-format.h"
ager@chromium.orgbeb25712010-11-29 08:02:25 +000040#include "preparse-data.h"
41#include "preparser.h"
ricow@chromium.org55ee8072011-09-08 16:33:10 +000042#include "unicode.h"
43#include "utils.h"
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +000044
ricow@chromium.org55ee8072011-09-08 16:33:10 +000045#ifdef _MSC_VER
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000046namespace std {
47
ricow@chromium.org55ee8072011-09-08 16:33:10 +000048// Usually defined in math.h, but not in MSVC.
49// Abstracted to work
50int isfinite(double value);
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000051
52} // namespace std
ricow@chromium.org55ee8072011-09-08 16:33:10 +000053#endif
54
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000055namespace v8 {
56
ager@chromium.orgbeb25712010-11-29 08:02:25 +000057namespace preparser {
58
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000059PreParser::PreParseResult PreParser::PreParseLazyFunction(
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000060 i::LanguageMode mode, bool is_generator, i::ParserRecorder* log) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000061 log_ = log;
62 // Lazy functions always have trivial outer scopes (no with/catch scopes).
63 Scope top_scope(&scope_, kTopLevelScope);
64 set_language_mode(mode);
65 Scope function_scope(&scope_, kFunctionScope);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000066 function_scope.set_is_generator(is_generator);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000067 ASSERT_EQ(i::Token::LBRACE, scanner_->current_token());
68 bool ok = true;
69 int start_position = scanner_->peek_location().beg_pos;
70 ParseLazyFunctionLiteralBody(&ok);
71 if (stack_overflow_) return kPreParseStackOverflow;
72 if (!ok) {
73 ReportUnexpectedToken(scanner_->current_token());
74 } else {
75 ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
76 if (!is_classic_mode()) {
77 int end_pos = scanner_->location().end_pos;
78 CheckOctalLiteral(start_position, end_pos, &ok);
79 if (ok) {
80 CheckDelayedStrictModeViolation(start_position, end_pos, &ok);
81 }
82 }
83 }
84 return kPreParseSuccess;
85}
86
87
ager@chromium.orgbeb25712010-11-29 08:02:25 +000088// Preparsing checks a JavaScript program and emits preparse-data that helps
89// a later parsing to be faster.
90// See preparser-data.h for the data.
91
92// The PreParser checks that the syntax follows the grammar for JavaScript,
93// and collects some information about the program along the way.
94// The grammar check is only performed in order to understand the program
95// sufficiently to deduce some information about it, that can be used
96// to speed up later parsing. Finding errors is not the goal of pre-parsing,
97// rather it is to speed up properly written and correct programs.
98// That means that contextual checks (like a label being declared where
99// it is used) are generally omitted.
100
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000101void PreParser::ReportUnexpectedToken(i::Token::Value token) {
102 // We don't report stack overflows here, to avoid increasing the
103 // stack depth even further. Instead we report it after parsing is
104 // over, in ParseProgram.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000105 if (token == i::Token::ILLEGAL && stack_overflow_) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000106 return;
107 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000108 i::Scanner::Location source_location = scanner_->location();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000109
110 // Four of the tokens are treated specially
111 switch (token) {
112 case i::Token::EOS:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000113 return ReportMessageAt(source_location, "unexpected_eos", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000114 case i::Token::NUMBER:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000115 return ReportMessageAt(source_location, "unexpected_token_number", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000116 case i::Token::STRING:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000117 return ReportMessageAt(source_location, "unexpected_token_string", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000118 case i::Token::IDENTIFIER:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000119 return ReportMessageAt(source_location,
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000120 "unexpected_token_identifier", NULL);
ager@chromium.org04921a82011-06-27 13:21:41 +0000121 case i::Token::FUTURE_RESERVED_WORD:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000122 return ReportMessageAt(source_location, "unexpected_reserved", NULL);
ager@chromium.org04921a82011-06-27 13:21:41 +0000123 case i::Token::FUTURE_STRICT_RESERVED_WORD:
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000124 return ReportMessageAt(source_location,
ager@chromium.org04921a82011-06-27 13:21:41 +0000125 "unexpected_strict_reserved", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000126 default:
127 const char* name = i::Token::String(token);
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000128 ReportMessageAt(source_location, "unexpected_token", name);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000129 }
130}
131
132
lrn@chromium.org1c092762011-05-09 09:42:16 +0000133// Checks whether octal literal last seen is between beg_pos and end_pos.
134// If so, reports an error.
135void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
136 i::Scanner::Location octal = scanner_->octal_position();
137 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000138 ReportMessageAt(octal, "strict_octal_literal", NULL);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000139 scanner_->clear_octal_position();
140 *ok = false;
141 }
142}
143
144
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000145#define CHECK_OK ok); \
146 if (!*ok) return kUnknownSourceElements; \
147 ((void)0
148#define DUMMY ) // to make indentation work
149#undef DUMMY
150
151
danno@chromium.orgb6451162011-08-17 14:33:23 +0000152PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000153 // (Ecma 262 5th Edition, clause 14):
154 // SourceElement:
155 // Statement
156 // FunctionDeclaration
157 //
158 // In harmony mode we allow additionally the following productions
159 // SourceElement:
160 // LetDeclaration
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000161 // ConstDeclaration
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000162 // GeneratorDeclaration
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000163
danno@chromium.orgb6451162011-08-17 14:33:23 +0000164 switch (peek()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000165 case i::Token::FUNCTION:
166 return ParseFunctionDeclaration(ok);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000167 case i::Token::LET:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000168 case i::Token::CONST:
danno@chromium.orgb6451162011-08-17 14:33:23 +0000169 return ParseVariableStatement(kSourceElement, ok);
170 default:
171 return ParseStatement(ok);
172 }
173}
174
175
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000176PreParser::SourceElements PreParser::ParseSourceElements(int end_token,
177 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000178 // SourceElements ::
179 // (Statement)* <end_token>
180
lrn@chromium.org1c092762011-05-09 09:42:16 +0000181 bool allow_directive_prologue = true;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000182 while (peek() != end_token) {
danno@chromium.orgb6451162011-08-17 14:33:23 +0000183 Statement statement = ParseSourceElement(CHECK_OK);
lrn@chromium.org1c092762011-05-09 09:42:16 +0000184 if (allow_directive_prologue) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000185 if (statement.IsUseStrictLiteral()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000186 set_language_mode(allow_harmony_scoping() ?
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000187 i::EXTENDED_MODE : i::STRICT_MODE);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000188 } else if (!statement.IsStringLiteral()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +0000189 allow_directive_prologue = false;
190 }
191 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000192 }
193 return kUnknownSourceElements;
194}
195
196
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000197#undef CHECK_OK
198#define CHECK_OK ok); \
199 if (!*ok) return Statement::Default(); \
200 ((void)0
201#define DUMMY ) // to make indentation work
202#undef DUMMY
203
204
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000205PreParser::Statement PreParser::ParseStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000206 // Statement ::
207 // Block
208 // VariableStatement
209 // EmptyStatement
210 // ExpressionStatement
211 // IfStatement
212 // IterationStatement
213 // ContinueStatement
214 // BreakStatement
215 // ReturnStatement
216 // WithStatement
217 // LabelledStatement
218 // SwitchStatement
219 // ThrowStatement
220 // TryStatement
221 // DebuggerStatement
222
223 // Note: Since labels can only be used by 'break' and 'continue'
224 // statements, which themselves are only valid within blocks,
225 // iterations or 'switch' statements (i.e., BreakableStatements),
226 // labels can be simply ignored in all other cases; except for
227 // trivial labeled break statements 'label: break label' which is
228 // parsed into an empty statement.
229
230 // Keep the source position of the statement
231 switch (peek()) {
232 case i::Token::LBRACE:
233 return ParseBlock(ok);
234
235 case i::Token::CONST:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000236 case i::Token::LET:
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000237 case i::Token::VAR:
danno@chromium.orgb6451162011-08-17 14:33:23 +0000238 return ParseVariableStatement(kStatement, ok);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000239
240 case i::Token::SEMICOLON:
241 Next();
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000242 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000243
244 case i::Token::IF:
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000245 return ParseIfStatement(ok);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000246
247 case i::Token::DO:
248 return ParseDoWhileStatement(ok);
249
250 case i::Token::WHILE:
251 return ParseWhileStatement(ok);
252
253 case i::Token::FOR:
254 return ParseForStatement(ok);
255
256 case i::Token::CONTINUE:
257 return ParseContinueStatement(ok);
258
259 case i::Token::BREAK:
260 return ParseBreakStatement(ok);
261
262 case i::Token::RETURN:
263 return ParseReturnStatement(ok);
264
265 case i::Token::WITH:
266 return ParseWithStatement(ok);
267
268 case i::Token::SWITCH:
269 return ParseSwitchStatement(ok);
270
271 case i::Token::THROW:
272 return ParseThrowStatement(ok);
273
274 case i::Token::TRY:
275 return ParseTryStatement(ok);
276
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000277 case i::Token::FUNCTION: {
278 i::Scanner::Location start_location = scanner_->peek_location();
279 Statement statement = ParseFunctionDeclaration(CHECK_OK);
280 i::Scanner::Location end_location = scanner_->location();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000281 if (!is_classic_mode()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000282 ReportMessageAt(start_location.beg_pos, end_location.end_pos,
283 "strict_function", NULL);
284 *ok = false;
285 return Statement::Default();
286 } else {
287 return statement;
288 }
289 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000290
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000291 case i::Token::DEBUGGER:
292 return ParseDebuggerStatement(ok);
293
294 default:
295 return ParseExpressionOrLabelledStatement(ok);
296 }
297}
298
299
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000300PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000301 // FunctionDeclaration ::
302 // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000303 // GeneratorDeclaration ::
304 // 'function' '*' Identifier '(' FormalParameterListopt ')'
305 // '{' FunctionBody '}'
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000306 Expect(i::Token::FUNCTION, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000307
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000308 bool is_generator = allow_generators_ && Check(i::Token::MUL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000309 Identifier identifier = ParseIdentifier(CHECK_OK);
310 i::Scanner::Location location = scanner_->location();
311
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000312 Expression function_value = ParseFunctionLiteral(is_generator, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000313
314 if (function_value.IsStrictFunction() &&
315 !identifier.IsValidStrictVariable()) {
316 // Strict mode violation, using either reserved word or eval/arguments
317 // as name of strict function.
318 const char* type = "strict_function_name";
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000319 if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000320 type = "strict_reserved_word";
321 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000322 ReportMessageAt(location, type, NULL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000323 *ok = false;
324 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000325 return Statement::FunctionDeclaration();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000326}
327
328
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000329PreParser::Statement PreParser::ParseBlock(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000330 // Block ::
331 // '{' Statement* '}'
332
333 // Note that a Block does not introduce a new execution scope!
334 // (ECMA-262, 3rd, 12.2)
335 //
336 Expect(i::Token::LBRACE, CHECK_OK);
337 while (peek() != i::Token::RBRACE) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000338 if (is_extended_mode()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000339 ParseSourceElement(CHECK_OK);
340 } else {
341 ParseStatement(CHECK_OK);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000342 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000343 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000344 Expect(i::Token::RBRACE, ok);
345 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000346}
347
348
danno@chromium.orgb6451162011-08-17 14:33:23 +0000349PreParser::Statement PreParser::ParseVariableStatement(
350 VariableDeclarationContext var_context,
351 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000352 // VariableStatement ::
353 // VariableDeclarations ';'
354
danno@chromium.orgb6451162011-08-17 14:33:23 +0000355 Statement result = ParseVariableDeclarations(var_context,
356 NULL,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000357 NULL,
danno@chromium.orgb6451162011-08-17 14:33:23 +0000358 CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000359 ExpectSemicolon(CHECK_OK);
360 return result;
361}
362
363
364// If the variable declaration declares exactly one non-const
365// variable, then *var is set to that variable. In all other cases,
366// *var is untouched; in particular, it is the caller's responsibility
367// to initialize it properly. This mechanism is also used for the parsing
368// of 'for-in' loops.
danno@chromium.orgb6451162011-08-17 14:33:23 +0000369PreParser::Statement PreParser::ParseVariableDeclarations(
370 VariableDeclarationContext var_context,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000371 VariableDeclarationProperties* decl_props,
danno@chromium.orgb6451162011-08-17 14:33:23 +0000372 int* num_decl,
373 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000374 // VariableDeclarations ::
375 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000376 //
377 // The ES6 Draft Rev3 specifies the following grammar for const declarations
378 //
379 // ConstDeclaration ::
380 // const ConstBinding (',' ConstBinding)* ';'
381 // ConstBinding ::
382 // Identifier '=' AssignmentExpression
383 //
384 // TODO(ES6):
385 // ConstBinding ::
386 // BindingPattern '=' AssignmentExpression
387 bool require_initializer = false;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000388 if (peek() == i::Token::VAR) {
389 Consume(i::Token::VAR);
390 } else if (peek() == i::Token::CONST) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000391 // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
392 //
393 // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
394 //
395 // * It is a Syntax Error if the code that matches this production is not
396 // contained in extended code.
397 //
398 // However disallowing const in classic mode will break compatibility with
399 // existing pages. Therefore we keep allowing const with the old
400 // non-harmony semantics in classic mode.
401 Consume(i::Token::CONST);
402 switch (language_mode()) {
403 case i::CLASSIC_MODE:
404 break;
405 case i::STRICT_MODE: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000406 i::Scanner::Location location = scanner_->peek_location();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000407 ReportMessageAt(location, "strict_const", NULL);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000408 *ok = false;
409 return Statement::Default();
410 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000411 case i::EXTENDED_MODE:
412 if (var_context != kSourceElement &&
413 var_context != kForStatement) {
414 i::Scanner::Location location = scanner_->peek_location();
415 ReportMessageAt(location.beg_pos, location.end_pos,
416 "unprotected_const", NULL);
417 *ok = false;
418 return Statement::Default();
419 }
420 require_initializer = true;
421 break;
422 }
423 } else if (peek() == i::Token::LET) {
424 // ES6 Draft Rev4 section 12.2.1:
425 //
426 // LetDeclaration : let LetBindingList ;
427 //
428 // * It is a Syntax Error if the code that matches this production is not
429 // contained in extended code.
430 if (!is_extended_mode()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000431 i::Scanner::Location location = scanner_->peek_location();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000432 ReportMessageAt(location.beg_pos, location.end_pos,
433 "illegal_let", NULL);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000434 *ok = false;
435 return Statement::Default();
436 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000437 Consume(i::Token::LET);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000438 if (var_context != kSourceElement &&
439 var_context != kForStatement) {
440 i::Scanner::Location location = scanner_->peek_location();
441 ReportMessageAt(location.beg_pos, location.end_pos,
442 "unprotected_let", NULL);
443 *ok = false;
444 return Statement::Default();
445 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000446 } else {
447 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000448 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000449 }
450
danno@chromium.orgb6451162011-08-17 14:33:23 +0000451 // The scope of a var/const declared variable anywhere inside a function
452 // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
453 // of a let declared variable is the scope of the immediately enclosing
454 // block.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000455 int nvars = 0; // the number of variables declared
456 do {
457 // Parse variable name.
458 if (nvars > 0) Consume(i::Token::COMMA);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000459 Identifier identifier = ParseIdentifier(CHECK_OK);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000460 if (!is_classic_mode() && !identifier.IsValidStrictVariable()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000461 StrictModeIdentifierViolation(scanner_->location(),
462 "strict_var_name",
463 identifier,
464 ok);
465 return Statement::Default();
466 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000467 nvars++;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 if (peek() == i::Token::ASSIGN || require_initializer) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000469 Expect(i::Token::ASSIGN, CHECK_OK);
danno@chromium.orgb6451162011-08-17 14:33:23 +0000470 ParseAssignmentExpression(var_context != kForStatement, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471 if (decl_props != NULL) *decl_props = kHasInitializers;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000472 }
473 } while (peek() == i::Token::COMMA);
474
475 if (num_decl != NULL) *num_decl = nvars;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000476 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000477}
478
479
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000480PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000481 // ExpressionStatement | LabelledStatement ::
482 // Expression ';'
483 // Identifier ':' Statement
484
485 Expression expr = ParseExpression(true, CHECK_OK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000486 if (expr.IsRawIdentifier()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000487 ASSERT(!expr.AsIdentifier().IsFutureReserved());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000488 ASSERT(is_classic_mode() ||
489 (!expr.AsIdentifier().IsFutureStrictReserved() &&
490 !expr.AsIdentifier().IsYield()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000491 if (peek() == i::Token::COLON) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000492 Consume(i::Token::COLON);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000493 return ParseStatement(ok);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000494 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000495 // Preparsing is disabled for extensions (because the extension details
496 // aren't passed to lazily compiled functions), so we don't
497 // accept "native function" in the preparser.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000498 }
499 // Parsed expression statement.
500 ExpectSemicolon(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000501 return Statement::ExpressionStatement(expr);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000502}
503
504
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000506 // IfStatement ::
507 // 'if' '(' Expression ')' Statement ('else' Statement)?
508
509 Expect(i::Token::IF, CHECK_OK);
510 Expect(i::Token::LPAREN, CHECK_OK);
511 ParseExpression(true, CHECK_OK);
512 Expect(i::Token::RPAREN, CHECK_OK);
513 ParseStatement(CHECK_OK);
514 if (peek() == i::Token::ELSE) {
515 Next();
516 ParseStatement(CHECK_OK);
517 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000518 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000519}
520
521
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000522PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000523 // ContinueStatement ::
524 // 'continue' [no line terminator] Identifier? ';'
525
526 Expect(i::Token::CONTINUE, CHECK_OK);
527 i::Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000528 if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000529 tok != i::Token::SEMICOLON &&
530 tok != i::Token::RBRACE &&
531 tok != i::Token::EOS) {
532 ParseIdentifier(CHECK_OK);
533 }
534 ExpectSemicolon(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000535 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000536}
537
538
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000540 // BreakStatement ::
541 // 'break' [no line terminator] Identifier? ';'
542
543 Expect(i::Token::BREAK, CHECK_OK);
544 i::Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000545 if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000546 tok != i::Token::SEMICOLON &&
547 tok != i::Token::RBRACE &&
548 tok != i::Token::EOS) {
549 ParseIdentifier(CHECK_OK);
550 }
551 ExpectSemicolon(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000552 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000553}
554
555
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000557 // ReturnStatement ::
558 // 'return' [no line terminator] Expression? ';'
559
560 // Consume the return token. It is necessary to do the before
561 // reporting any errors on it, because of the way errors are
562 // reported (underlining).
563 Expect(i::Token::RETURN, CHECK_OK);
564
565 // An ECMAScript program is considered syntactically incorrect if it
566 // contains a return statement that is not within the body of a
567 // function. See ECMA-262, section 12.9, page 67.
568 // This is not handled during preparsing.
569
570 i::Token::Value tok = peek();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000571 if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000572 tok != i::Token::SEMICOLON &&
573 tok != i::Token::RBRACE &&
574 tok != i::Token::EOS) {
575 ParseExpression(true, CHECK_OK);
576 }
577 ExpectSemicolon(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000578 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000579}
580
581
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000582PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000583 // WithStatement ::
584 // 'with' '(' Expression ')' Statement
585 Expect(i::Token::WITH, CHECK_OK);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000586 if (!is_classic_mode()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000587 i::Scanner::Location location = scanner_->location();
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000588 ReportMessageAt(location, "strict_mode_with", NULL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000589 *ok = false;
590 return Statement::Default();
591 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000592 Expect(i::Token::LPAREN, CHECK_OK);
593 ParseExpression(true, CHECK_OK);
594 Expect(i::Token::RPAREN, CHECK_OK);
595
danno@chromium.org2c26cb12012-05-03 09:06:43 +0000596 Scope::InsideWith iw(scope_);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000597 ParseStatement(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000598 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000599}
600
601
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000603 // SwitchStatement ::
604 // 'switch' '(' Expression ')' '{' CaseClause* '}'
605
606 Expect(i::Token::SWITCH, CHECK_OK);
607 Expect(i::Token::LPAREN, CHECK_OK);
608 ParseExpression(true, CHECK_OK);
609 Expect(i::Token::RPAREN, CHECK_OK);
610
611 Expect(i::Token::LBRACE, CHECK_OK);
612 i::Token::Value token = peek();
613 while (token != i::Token::RBRACE) {
614 if (token == i::Token::CASE) {
615 Expect(i::Token::CASE, CHECK_OK);
616 ParseExpression(true, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000617 } else {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000618 Expect(i::Token::DEFAULT, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000619 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000620 Expect(i::Token::COLON, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000621 token = peek();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000622 while (token != i::Token::CASE &&
623 token != i::Token::DEFAULT &&
624 token != i::Token::RBRACE) {
625 ParseStatement(CHECK_OK);
626 token = peek();
627 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000628 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000629 Expect(i::Token::RBRACE, ok);
630 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000631}
632
633
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000634PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000635 // DoStatement ::
636 // 'do' Statement 'while' '(' Expression ')' ';'
637
638 Expect(i::Token::DO, CHECK_OK);
639 ParseStatement(CHECK_OK);
640 Expect(i::Token::WHILE, CHECK_OK);
641 Expect(i::Token::LPAREN, CHECK_OK);
642 ParseExpression(true, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000643 Expect(i::Token::RPAREN, ok);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000644 if (peek() == i::Token::SEMICOLON) Consume(i::Token::SEMICOLON);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000645 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000646}
647
648
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000649PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000650 // WhileStatement ::
651 // 'while' '(' Expression ')' Statement
652
653 Expect(i::Token::WHILE, CHECK_OK);
654 Expect(i::Token::LPAREN, CHECK_OK);
655 ParseExpression(true, CHECK_OK);
656 Expect(i::Token::RPAREN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000657 ParseStatement(ok);
658 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000659}
660
661
danno@chromium.org41728482013-06-12 22:31:22 +0000662bool PreParser::CheckInOrOf(bool accept_OF) {
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000663 if (peek() == i::Token::IN ||
danno@chromium.org41728482013-06-12 22:31:22 +0000664 (allow_for_of() && accept_OF && peek() == i::Token::IDENTIFIER &&
danno@chromium.org1fd77d52013-06-07 16:01:45 +0000665 scanner_->is_next_contextual_keyword(v8::internal::CStrVector("of")))) {
666 Next();
667 return true;
668 }
669 return false;
670}
671
672
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000673PreParser::Statement PreParser::ParseForStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000674 // ForStatement ::
675 // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
676
677 Expect(i::Token::FOR, CHECK_OK);
678 Expect(i::Token::LPAREN, CHECK_OK);
679 if (peek() != i::Token::SEMICOLON) {
danno@chromium.orgb6451162011-08-17 14:33:23 +0000680 if (peek() == i::Token::VAR || peek() == i::Token::CONST ||
681 peek() == i::Token::LET) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000682 bool is_let = peek() == i::Token::LET;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000683 int decl_count;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000684 VariableDeclarationProperties decl_props = kHasNoInitializers;
685 ParseVariableDeclarations(
686 kForStatement, &decl_props, &decl_count, CHECK_OK);
danno@chromium.org41728482013-06-12 22:31:22 +0000687 bool has_initializers = decl_props == kHasInitializers;
688 bool accept_IN = decl_count == 1 && !(is_let && has_initializers);
689 bool accept_OF = !has_initializers;
690 if (accept_IN && CheckInOrOf(accept_OF)) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000691 ParseExpression(true, CHECK_OK);
692 Expect(i::Token::RPAREN, CHECK_OK);
693
694 ParseStatement(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000695 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000696 }
697 } else {
danno@chromium.org41728482013-06-12 22:31:22 +0000698 Expression lhs = ParseExpression(false, CHECK_OK);
699 if (CheckInOrOf(lhs.IsIdentifier())) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000700 ParseExpression(true, CHECK_OK);
701 Expect(i::Token::RPAREN, CHECK_OK);
702
703 ParseStatement(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000704 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000705 }
706 }
707 }
708
709 // Parsed initializer at this point.
710 Expect(i::Token::SEMICOLON, CHECK_OK);
711
712 if (peek() != i::Token::SEMICOLON) {
713 ParseExpression(true, CHECK_OK);
714 }
715 Expect(i::Token::SEMICOLON, CHECK_OK);
716
717 if (peek() != i::Token::RPAREN) {
718 ParseExpression(true, CHECK_OK);
719 }
720 Expect(i::Token::RPAREN, CHECK_OK);
721
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000722 ParseStatement(ok);
723 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000724}
725
726
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000727PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000728 // ThrowStatement ::
729 // 'throw' [no line terminator] Expression ';'
730
731 Expect(i::Token::THROW, CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000732 if (scanner_->HasAnyLineTerminatorBeforeNext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000733 i::Scanner::Location pos = scanner_->location();
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000734 ReportMessageAt(pos, "newline_after_throw", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000735 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000736 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000737 }
738 ParseExpression(true, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000739 ExpectSemicolon(ok);
740 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000741}
742
743
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000744PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000745 // TryStatement ::
746 // 'try' Block Catch
747 // 'try' Block Finally
748 // 'try' Block Catch Finally
749 //
750 // Catch ::
751 // 'catch' '(' Identifier ')' Block
752 //
753 // Finally ::
754 // 'finally' Block
755
756 // In preparsing, allow any number of catch/finally blocks, including zero
757 // of both.
758
759 Expect(i::Token::TRY, CHECK_OK);
760
761 ParseBlock(CHECK_OK);
762
763 bool catch_or_finally_seen = false;
764 if (peek() == i::Token::CATCH) {
765 Consume(i::Token::CATCH);
766 Expect(i::Token::LPAREN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000767 Identifier id = ParseIdentifier(CHECK_OK);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000768 if (!is_classic_mode() && !id.IsValidStrictVariable()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000769 StrictModeIdentifierViolation(scanner_->location(),
770 "strict_catch_variable",
771 id,
772 ok);
773 return Statement::Default();
774 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000775 Expect(i::Token::RPAREN, CHECK_OK);
danno@chromium.org2c26cb12012-05-03 09:06:43 +0000776 { Scope::InsideWith iw(scope_);
777 ParseBlock(CHECK_OK);
778 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000779 catch_or_finally_seen = true;
780 }
781 if (peek() == i::Token::FINALLY) {
782 Consume(i::Token::FINALLY);
783 ParseBlock(CHECK_OK);
784 catch_or_finally_seen = true;
785 }
786 if (!catch_or_finally_seen) {
787 *ok = false;
788 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000789 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000790}
791
792
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000793PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000794 // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
795 // contexts this is used as a statement which invokes the debugger as if a
796 // break point is present.
797 // DebuggerStatement ::
798 // 'debugger' ';'
799
800 Expect(i::Token::DEBUGGER, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000801 ExpectSemicolon(ok);
802 return Statement::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000803}
804
805
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000806#undef CHECK_OK
807#define CHECK_OK ok); \
808 if (!*ok) return Expression::Default(); \
809 ((void)0
810#define DUMMY ) // to make indentation work
811#undef DUMMY
812
813
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000814// Precedence = 1
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000815PreParser::Expression PreParser::ParseExpression(bool accept_IN, bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000816 // Expression ::
817 // AssignmentExpression
818 // Expression ',' AssignmentExpression
819
820 Expression result = ParseAssignmentExpression(accept_IN, CHECK_OK);
821 while (peek() == i::Token::COMMA) {
822 Expect(i::Token::COMMA, CHECK_OK);
823 ParseAssignmentExpression(accept_IN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000824 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000825 }
826 return result;
827}
828
829
830// Precedence = 2
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000831PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
832 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000833 // AssignmentExpression ::
834 // ConditionalExpression
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000835 // YieldExpression
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000836 // LeftHandSideExpression AssignmentOperator AssignmentExpression
837
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000838 if (scope_->is_generator() && peek() == i::Token::YIELD) {
839 return ParseYieldExpression(ok);
840 }
841
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000842 i::Scanner::Location before = scanner_->peek_location();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000843 Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
844
845 if (!i::Token::IsAssignmentOp(peek())) {
846 // Parsed conditional expression only (no assignment).
847 return expression;
848 }
849
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000850 if (!is_classic_mode() &&
851 expression.IsIdentifier() &&
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000852 expression.AsIdentifier().IsEvalOrArguments()) {
853 i::Scanner::Location after = scanner_->location();
854 ReportMessageAt(before.beg_pos, after.end_pos,
855 "strict_lhs_assignment", NULL);
856 *ok = false;
857 return Expression::Default();
858 }
859
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000860 i::Token::Value op = Next(); // Get assignment operator.
861 ParseAssignmentExpression(accept_IN, CHECK_OK);
862
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000863 if ((op == i::Token::ASSIGN) && expression.IsThisProperty()) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000864 scope_->AddProperty();
865 }
866
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000867 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000868}
869
870
871// Precedence = 3
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000872PreParser::Expression PreParser::ParseYieldExpression(bool* ok) {
873 // YieldExpression ::
874 // 'yield' '*'? AssignmentExpression
875 Consume(i::Token::YIELD);
876 Check(i::Token::MUL);
877
878 ParseAssignmentExpression(false, CHECK_OK);
879
880 return Expression::Default();
881}
882
883
884// Precedence = 3
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000885PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
886 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000887 // ConditionalExpression ::
888 // LogicalOrExpression
889 // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression
890
891 // We start using the binary expression parser for prec >= 4 only!
892 Expression expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
893 if (peek() != i::Token::CONDITIONAL) return expression;
894 Consume(i::Token::CONDITIONAL);
895 // In parsing the first assignment expression in conditional
896 // expressions we always accept the 'in' keyword; see ECMA-262,
897 // section 11.12, page 58.
898 ParseAssignmentExpression(true, CHECK_OK);
899 Expect(i::Token::COLON, CHECK_OK);
900 ParseAssignmentExpression(accept_IN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000901 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000902}
903
904
905int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
906 if (tok == i::Token::IN && !accept_IN)
907 return 0; // 0 precedence will terminate binary expression parsing
908
909 return i::Token::Precedence(tok);
910}
911
912
913// Precedence >= 4
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000914PreParser::Expression PreParser::ParseBinaryExpression(int prec,
915 bool accept_IN,
916 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000917 Expression result = ParseUnaryExpression(CHECK_OK);
918 for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
919 // prec1 >= 4
920 while (Precedence(peek(), accept_IN) == prec1) {
921 Next();
922 ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000923 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000924 }
925 }
926 return result;
927}
928
929
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000930PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000931 // UnaryExpression ::
932 // PostfixExpression
933 // 'delete' UnaryExpression
934 // 'void' UnaryExpression
935 // 'typeof' UnaryExpression
936 // '++' UnaryExpression
937 // '--' UnaryExpression
938 // '+' UnaryExpression
939 // '-' UnaryExpression
940 // '~' UnaryExpression
941 // '!' UnaryExpression
942
943 i::Token::Value op = peek();
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000944 if (i::Token::IsUnaryOp(op)) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000945 op = Next();
946 ParseUnaryExpression(ok);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000947 return Expression::Default();
948 } else if (i::Token::IsCountOp(op)) {
949 op = Next();
950 i::Scanner::Location before = scanner_->peek_location();
951 Expression expression = ParseUnaryExpression(CHECK_OK);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000952 if (!is_classic_mode() &&
953 expression.IsIdentifier() &&
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000954 expression.AsIdentifier().IsEvalOrArguments()) {
955 i::Scanner::Location after = scanner_->location();
956 ReportMessageAt(before.beg_pos, after.end_pos,
957 "strict_lhs_prefix", NULL);
958 *ok = false;
959 }
960 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000961 } else {
962 return ParsePostfixExpression(ok);
963 }
964}
965
966
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000967PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000968 // PostfixExpression ::
969 // LeftHandSideExpression ('++' | '--')?
970
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000971 i::Scanner::Location before = scanner_->peek_location();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000972 Expression expression = ParseLeftHandSideExpression(CHECK_OK);
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +0000973 if (!scanner_->HasAnyLineTerminatorBeforeNext() &&
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000974 i::Token::IsCountOp(peek())) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000975 if (!is_classic_mode() &&
976 expression.IsIdentifier() &&
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000977 expression.AsIdentifier().IsEvalOrArguments()) {
978 i::Scanner::Location after = scanner_->location();
979 ReportMessageAt(before.beg_pos, after.end_pos,
980 "strict_lhs_postfix", NULL);
981 *ok = false;
982 return Expression::Default();
983 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000984 Next();
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000985 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000986 }
987 return expression;
988}
989
990
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000991PreParser::Expression PreParser::ParseLeftHandSideExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000992 // LeftHandSideExpression ::
993 // (NewExpression | MemberExpression) ...
994
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000995 Expression result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000996 if (peek() == i::Token::NEW) {
997 result = ParseNewExpression(CHECK_OK);
998 } else {
999 result = ParseMemberExpression(CHECK_OK);
1000 }
1001
1002 while (true) {
1003 switch (peek()) {
1004 case i::Token::LBRACK: {
1005 Consume(i::Token::LBRACK);
1006 ParseExpression(true, CHECK_OK);
1007 Expect(i::Token::RBRACK, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001008 if (result.IsThis()) {
1009 result = Expression::ThisProperty();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001010 } else {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001011 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001012 }
1013 break;
1014 }
1015
1016 case i::Token::LPAREN: {
1017 ParseArguments(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001018 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001019 break;
1020 }
1021
1022 case i::Token::PERIOD: {
1023 Consume(i::Token::PERIOD);
1024 ParseIdentifierName(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001025 if (result.IsThis()) {
1026 result = Expression::ThisProperty();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001027 } else {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001028 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001029 }
1030 break;
1031 }
1032
1033 default:
1034 return result;
1035 }
1036 }
1037}
1038
1039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001040PreParser::Expression PreParser::ParseNewExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001041 // NewExpression ::
1042 // ('new')+ MemberExpression
1043
1044 // The grammar for new expressions is pretty warped. The keyword
1045 // 'new' can either be a part of the new expression (where it isn't
1046 // followed by an argument list) or a part of the member expression,
1047 // where it must be followed by an argument list. To accommodate
1048 // this, we parse the 'new' keywords greedily and keep track of how
1049 // many we have parsed. This information is then passed on to the
1050 // member expression parser, which is only allowed to match argument
1051 // lists as long as it has 'new' prefixes left
1052 unsigned new_count = 0;
1053 do {
1054 Consume(i::Token::NEW);
1055 new_count++;
1056 } while (peek() == i::Token::NEW);
1057
1058 return ParseMemberWithNewPrefixesExpression(new_count, ok);
1059}
1060
1061
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062PreParser::Expression PreParser::ParseMemberExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001063 return ParseMemberWithNewPrefixesExpression(0, ok);
1064}
1065
1066
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001067PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001068 unsigned new_count, bool* ok) {
1069 // MemberExpression ::
1070 // (PrimaryExpression | FunctionLiteral)
1071 // ('[' Expression ']' | '.' Identifier | Arguments)*
1072
1073 // Parse the initial primary or function expression.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001074 Expression result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001075 if (peek() == i::Token::FUNCTION) {
1076 Consume(i::Token::FUNCTION);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001077
1078 bool is_generator = allow_generators_ && Check(i::Token::MUL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001079 Identifier identifier = Identifier::Default();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001080 if (peek_any_identifier()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001081 identifier = ParseIdentifier(CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001082 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001083 result = ParseFunctionLiteral(is_generator, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001084 if (result.IsStrictFunction() && !identifier.IsValidStrictVariable()) {
1085 StrictModeIdentifierViolation(scanner_->location(),
1086 "strict_function_name",
1087 identifier,
1088 ok);
1089 return Expression::Default();
1090 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001091 } else {
1092 result = ParsePrimaryExpression(CHECK_OK);
1093 }
1094
1095 while (true) {
1096 switch (peek()) {
1097 case i::Token::LBRACK: {
1098 Consume(i::Token::LBRACK);
1099 ParseExpression(true, CHECK_OK);
1100 Expect(i::Token::RBRACK, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001101 if (result.IsThis()) {
1102 result = Expression::ThisProperty();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001103 } else {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001104 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001105 }
1106 break;
1107 }
1108 case i::Token::PERIOD: {
1109 Consume(i::Token::PERIOD);
1110 ParseIdentifierName(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001111 if (result.IsThis()) {
1112 result = Expression::ThisProperty();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001113 } else {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001114 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001115 }
1116 break;
1117 }
1118 case i::Token::LPAREN: {
1119 if (new_count == 0) return result;
1120 // Consume one of the new prefixes (already parsed).
1121 ParseArguments(CHECK_OK);
1122 new_count--;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001123 result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001124 break;
1125 }
1126 default:
1127 return result;
1128 }
1129 }
1130}
1131
1132
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001133PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001134 // PrimaryExpression ::
1135 // 'this'
1136 // 'null'
1137 // 'true'
1138 // 'false'
1139 // Identifier
1140 // Number
1141 // String
1142 // ArrayLiteral
1143 // ObjectLiteral
1144 // RegExpLiteral
1145 // '(' Expression ')'
1146
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001147 Expression result = Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001148 switch (peek()) {
1149 case i::Token::THIS: {
1150 Next();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001151 result = Expression::This();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001152 break;
1153 }
1154
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00001155 case i::Token::FUTURE_RESERVED_WORD:
ager@chromium.org04921a82011-06-27 13:21:41 +00001156 case i::Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001157 case i::Token::YIELD:
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001158 case i::Token::IDENTIFIER: {
1159 Identifier id = ParseIdentifier(CHECK_OK);
1160 result = Expression::FromIdentifier(id);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001161 break;
1162 }
1163
1164 case i::Token::NULL_LITERAL:
1165 case i::Token::TRUE_LITERAL:
1166 case i::Token::FALSE_LITERAL:
1167 case i::Token::NUMBER: {
1168 Next();
1169 break;
1170 }
1171 case i::Token::STRING: {
1172 Next();
1173 result = GetStringSymbol();
1174 break;
1175 }
1176
1177 case i::Token::ASSIGN_DIV:
1178 result = ParseRegExpLiteral(true, CHECK_OK);
1179 break;
1180
1181 case i::Token::DIV:
1182 result = ParseRegExpLiteral(false, CHECK_OK);
1183 break;
1184
1185 case i::Token::LBRACK:
1186 result = ParseArrayLiteral(CHECK_OK);
1187 break;
1188
1189 case i::Token::LBRACE:
1190 result = ParseObjectLiteral(CHECK_OK);
1191 break;
1192
1193 case i::Token::LPAREN:
1194 Consume(i::Token::LPAREN);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001195 parenthesized_function_ = (peek() == i::Token::FUNCTION);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001196 result = ParseExpression(true, CHECK_OK);
1197 Expect(i::Token::RPAREN, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001198 result = result.Parenthesize();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001199 break;
1200
1201 case i::Token::MOD:
1202 result = ParseV8Intrinsic(CHECK_OK);
1203 break;
1204
1205 default: {
1206 Next();
1207 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001208 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001209 }
1210 }
1211
1212 return result;
1213}
1214
1215
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001216PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001217 // ArrayLiteral ::
1218 // '[' Expression? (',' Expression?)* ']'
1219 Expect(i::Token::LBRACK, CHECK_OK);
1220 while (peek() != i::Token::RBRACK) {
1221 if (peek() != i::Token::COMMA) {
1222 ParseAssignmentExpression(true, CHECK_OK);
1223 }
1224 if (peek() != i::Token::RBRACK) {
1225 Expect(i::Token::COMMA, CHECK_OK);
1226 }
1227 }
1228 Expect(i::Token::RBRACK, CHECK_OK);
1229
1230 scope_->NextMaterializedLiteralIndex();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001231 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001232}
1233
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001234void PreParser::CheckDuplicate(DuplicateFinder* finder,
1235 i::Token::Value property,
1236 int type,
1237 bool* ok) {
1238 int old_type;
1239 if (property == i::Token::NUMBER) {
1240 old_type = finder->AddNumber(scanner_->literal_ascii_string(), type);
1241 } else if (scanner_->is_literal_ascii()) {
1242 old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
1243 type);
1244 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001245 old_type = finder->AddUtf16Symbol(scanner_->literal_utf16_string(), type);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001246 }
1247 if (HasConflict(old_type, type)) {
1248 if (IsDataDataConflict(old_type, type)) {
1249 // Both are data properties.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001250 if (is_classic_mode()) return;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001251 ReportMessageAt(scanner_->location(),
1252 "strict_duplicate_property", NULL);
1253 } else if (IsDataAccessorConflict(old_type, type)) {
1254 // Both a data and an accessor property with the same name.
1255 ReportMessageAt(scanner_->location(),
1256 "accessor_data_property", NULL);
1257 } else {
1258 ASSERT(IsAccessorAccessorConflict(old_type, type));
1259 // Both accessors of the same type.
1260 ReportMessageAt(scanner_->location(),
1261 "accessor_get_set", NULL);
1262 }
1263 *ok = false;
1264 }
1265}
1266
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001267
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001269 // ObjectLiteral ::
1270 // '{' (
1271 // ((IdentifierName | String | Number) ':' AssignmentExpression)
1272 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
1273 // )*[','] '}'
1274
1275 Expect(i::Token::LBRACE, CHECK_OK);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001276 DuplicateFinder duplicate_finder(scanner_->unicode_cache());
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001277 while (peek() != i::Token::RBRACE) {
1278 i::Token::Value next = peek();
1279 switch (next) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001280 case i::Token::IDENTIFIER:
ager@chromium.org04921a82011-06-27 13:21:41 +00001281 case i::Token::FUTURE_RESERVED_WORD:
1282 case i::Token::FUTURE_STRICT_RESERVED_WORD: {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001283 bool is_getter = false;
1284 bool is_setter = false;
ager@chromium.org04921a82011-06-27 13:21:41 +00001285 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001286 if ((is_getter || is_setter) && peek() != i::Token::COLON) {
1287 i::Token::Value name = Next();
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001288 bool is_keyword = i::Token::IsKeyword(name);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001289 if (name != i::Token::IDENTIFIER &&
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001290 name != i::Token::FUTURE_RESERVED_WORD &&
ager@chromium.org04921a82011-06-27 13:21:41 +00001291 name != i::Token::FUTURE_STRICT_RESERVED_WORD &&
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001292 name != i::Token::NUMBER &&
1293 name != i::Token::STRING &&
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001294 !is_keyword) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001295 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001296 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001297 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001298 if (!is_keyword) {
1299 LogSymbol();
1300 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001301 PropertyType type = is_getter ? kGetterProperty : kSetterProperty;
1302 CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001303 ParseFunctionLiteral(false, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001304 if (peek() != i::Token::RBRACE) {
1305 Expect(i::Token::COMMA, CHECK_OK);
1306 }
1307 continue; // restart the while
1308 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001309 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001310 break;
1311 }
1312 case i::Token::STRING:
1313 Consume(next);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001314 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001315 GetStringSymbol();
1316 break;
1317 case i::Token::NUMBER:
1318 Consume(next);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001319 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001320 break;
1321 default:
1322 if (i::Token::IsKeyword(next)) {
1323 Consume(next);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001324 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001325 } else {
1326 // Unexpected token.
1327 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001328 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001329 }
1330 }
1331
1332 Expect(i::Token::COLON, CHECK_OK);
1333 ParseAssignmentExpression(true, CHECK_OK);
1334
1335 // TODO(1240767): Consider allowing trailing comma.
1336 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
1337 }
1338 Expect(i::Token::RBRACE, CHECK_OK);
1339
1340 scope_->NextMaterializedLiteralIndex();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001341 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001342}
1343
1344
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
1346 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001347 if (!scanner_->ScanRegExpPattern(seen_equal)) {
1348 Next();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001349 ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001350 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001351 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001352 }
1353
1354 scope_->NextMaterializedLiteralIndex();
1355
1356 if (!scanner_->ScanRegExpFlags()) {
1357 Next();
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001358 ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001359 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001360 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001361 }
1362 Next();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001363 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001364}
1365
1366
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001367PreParser::Arguments PreParser::ParseArguments(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001368 // Arguments ::
1369 // '(' (AssignmentExpression)*[','] ')'
1370
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001371 Expect(i::Token::LPAREN, ok);
1372 if (!*ok) return -1;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001373 bool done = (peek() == i::Token::RPAREN);
1374 int argc = 0;
1375 while (!done) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001376 ParseAssignmentExpression(true, ok);
1377 if (!*ok) return -1;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001378 argc++;
1379 done = (peek() == i::Token::RPAREN);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001380 if (!done) {
1381 Expect(i::Token::COMMA, ok);
1382 if (!*ok) return -1;
1383 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001384 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001385 Expect(i::Token::RPAREN, ok);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001386 return argc;
1387}
1388
1389
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001390PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
1391 bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001392 // Function ::
1393 // '(' FormalParameterList? ')' '{' FunctionBody '}'
1394
1395 // Parse function body.
1396 ScopeType outer_scope_type = scope_->type();
1397 bool inside_with = scope_->IsInsideWith();
1398 Scope function_scope(&scope_, kFunctionScope);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001399 function_scope.set_is_generator(is_generator);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001400 // FormalParameterList ::
1401 // '(' (Identifier)*[','] ')'
1402 Expect(i::Token::LPAREN, CHECK_OK);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001403 int start_position = scanner_->location().beg_pos;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001404 bool done = (peek() == i::Token::RPAREN);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001405 DuplicateFinder duplicate_finder(scanner_->unicode_cache());
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001406 while (!done) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001407 Identifier id = ParseIdentifier(CHECK_OK);
1408 if (!id.IsValidStrictVariable()) {
1409 StrictModeIdentifierViolation(scanner_->location(),
1410 "strict_param_name",
1411 id,
1412 CHECK_OK);
1413 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001414 int prev_value;
1415 if (scanner_->is_literal_ascii()) {
1416 prev_value =
1417 duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
1418 } else {
1419 prev_value =
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001420 duplicate_finder.AddUtf16Symbol(scanner_->literal_utf16_string(), 1);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001421 }
1422
1423 if (prev_value != 0) {
1424 SetStrictModeViolation(scanner_->location(),
1425 "strict_param_dupe",
1426 CHECK_OK);
1427 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001428 done = (peek() == i::Token::RPAREN);
1429 if (!done) {
1430 Expect(i::Token::COMMA, CHECK_OK);
1431 }
1432 }
1433 Expect(i::Token::RPAREN, CHECK_OK);
1434
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001435 // Determine if the function will be lazily compiled.
1436 // Currently only happens to top-level functions.
1437 // Optimistically assume that all top-level functions are lazily compiled.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001438 bool is_lazily_compiled = (outer_scope_type == kTopLevelScope &&
1439 !inside_with && allow_lazy_ &&
1440 !parenthesized_function_);
1441 parenthesized_function_ = false;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001442
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001443 Expect(i::Token::LBRACE, CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001444 if (is_lazily_compiled) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001445 ParseLazyFunctionLiteralBody(CHECK_OK);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001446 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001447 ParseSourceElements(i::Token::RBRACE, ok);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001448 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001449 Expect(i::Token::RBRACE, CHECK_OK);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001450
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001451 if (!is_classic_mode()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001452 int end_position = scanner_->location().end_pos;
1453 CheckOctalLiteral(start_position, end_position, CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001454 CheckDelayedStrictModeViolation(start_position, end_position, CHECK_OK);
1455 return Expression::StrictFunction();
lrn@chromium.org1c092762011-05-09 09:42:16 +00001456 }
1457
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001458 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001459}
1460
1461
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001462void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
1463 int body_start = scanner_->location().beg_pos;
1464 log_->PauseRecording();
1465 ParseSourceElements(i::Token::RBRACE, ok);
1466 log_->ResumeRecording();
1467 if (!*ok) return;
1468
1469 // Position right after terminal '}'.
1470 ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
1471 int body_end = scanner_->peek_location().end_pos;
1472 log_->LogFunction(body_start, body_end,
1473 scope_->materialized_literal_count(),
1474 scope_->expected_properties(),
1475 language_mode());
1476}
1477
1478
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001480 // CallRuntime ::
1481 // '%' Identifier Arguments
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001482 Expect(i::Token::MOD, CHECK_OK);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001483 if (!allow_natives_syntax_) {
1484 *ok = false;
1485 return Expression::Default();
1486 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001487 ParseIdentifier(CHECK_OK);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001488 ParseArguments(ok);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001489
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001490 return Expression::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001491}
1492
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001493#undef CHECK_OK
1494
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001495
1496void PreParser::ExpectSemicolon(bool* ok) {
1497 // Check for automatic semicolon insertion according to
1498 // the rules given in ECMA-262, section 7.9, page 21.
1499 i::Token::Value tok = peek();
1500 if (tok == i::Token::SEMICOLON) {
1501 Next();
1502 return;
1503 }
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00001504 if (scanner_->HasAnyLineTerminatorBeforeNext() ||
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001505 tok == i::Token::RBRACE ||
1506 tok == i::Token::EOS) {
1507 return;
1508 }
1509 Expect(i::Token::SEMICOLON, ok);
1510}
1511
1512
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001513void PreParser::LogSymbol() {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001514 int identifier_pos = scanner_->location().beg_pos;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001515 if (scanner_->is_literal_ascii()) {
1516 log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
1517 } else {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001518 log_->LogUtf16Symbol(identifier_pos, scanner_->literal_utf16_string());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001519 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001520}
1521
1522
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001523PreParser::Expression PreParser::GetStringSymbol() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001524 const int kUseStrictLength = 10;
1525 const char* kUseStrictChars = "use strict";
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001526 LogSymbol();
lrn@chromium.org1c092762011-05-09 09:42:16 +00001527 if (scanner_->is_literal_ascii() &&
1528 scanner_->literal_length() == kUseStrictLength &&
1529 !scanner_->literal_contains_escapes() &&
1530 !strncmp(scanner_->literal_ascii_string().start(), kUseStrictChars,
1531 kUseStrictLength)) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001532 return Expression::UseStrictStringLiteral();
lrn@chromium.org1c092762011-05-09 09:42:16 +00001533 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001534 return Expression::StringLiteral();
1535}
1536
1537
1538PreParser::Identifier PreParser::GetIdentifierSymbol() {
1539 LogSymbol();
1540 if (scanner_->current_token() == i::Token::FUTURE_RESERVED_WORD) {
1541 return Identifier::FutureReserved();
ager@chromium.org04921a82011-06-27 13:21:41 +00001542 } else if (scanner_->current_token() ==
1543 i::Token::FUTURE_STRICT_RESERVED_WORD) {
1544 return Identifier::FutureStrictReserved();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001545 } else if (scanner_->current_token() == i::Token::YIELD) {
1546 return Identifier::Yield();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001547 }
1548 if (scanner_->is_literal_ascii()) {
1549 // Detect strict-mode poison words.
1550 if (scanner_->literal_length() == 4 &&
1551 !strncmp(scanner_->literal_ascii_string().start(), "eval", 4)) {
1552 return Identifier::Eval();
1553 }
1554 if (scanner_->literal_length() == 9 &&
1555 !strncmp(scanner_->literal_ascii_string().start(), "arguments", 9)) {
1556 return Identifier::Arguments();
1557 }
1558 }
1559 return Identifier::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001560}
1561
1562
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001563PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001564 i::Token::Value next = Next();
1565 switch (next) {
1566 case i::Token::FUTURE_RESERVED_WORD: {
1567 i::Scanner::Location location = scanner_->location();
1568 ReportMessageAt(location.beg_pos, location.end_pos,
1569 "reserved_word", NULL);
1570 *ok = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 return GetIdentifierSymbol();
ager@chromium.org04921a82011-06-27 13:21:41 +00001572 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001573 case i::Token::YIELD:
1574 if (scope_->is_generator()) {
1575 // 'yield' in a generator is only valid as part of a YieldExpression.
1576 ReportMessageAt(scanner_->location(), "unexpected_token", "yield");
1577 *ok = false;
1578 return Identifier::Yield();
1579 }
1580 // FALLTHROUGH
ager@chromium.org04921a82011-06-27 13:21:41 +00001581 case i::Token::FUTURE_STRICT_RESERVED_WORD:
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001582 if (!is_classic_mode()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 i::Scanner::Location location = scanner_->location();
1584 ReportMessageAt(location.beg_pos, location.end_pos,
1585 "strict_reserved_word", NULL);
1586 *ok = false;
1587 }
1588 // FALLTHROUGH
ager@chromium.org04921a82011-06-27 13:21:41 +00001589 case i::Token::IDENTIFIER:
1590 return GetIdentifierSymbol();
1591 default:
1592 *ok = false;
1593 return Identifier::Default();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001594 }
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001595}
1596
1597
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001598void PreParser::SetStrictModeViolation(i::Scanner::Location location,
1599 const char* type,
1600 bool* ok) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001601 if (!is_classic_mode()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001602 ReportMessageAt(location, type, NULL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001603 *ok = false;
1604 return;
1605 }
1606 // Delay report in case this later turns out to be strict code
1607 // (i.e., for function names and parameters prior to a "use strict"
1608 // directive).
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001609 // It's safe to overwrite an existing violation.
1610 // It's either from a function that turned out to be non-strict,
1611 // or it's in the current function (and we just need to report
1612 // one error), or it's in a unclosed nesting function that wasn't
1613 // strict (otherwise we would already be in strict mode).
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001614 strict_mode_violation_location_ = location;
1615 strict_mode_violation_type_ = type;
1616}
1617
1618
1619void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
1620 int end_pos,
1621 bool* ok) {
1622 i::Scanner::Location location = strict_mode_violation_location_;
1623 if (location.IsValid() &&
1624 location.beg_pos > beg_pos && location.end_pos < end_pos) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001625 ReportMessageAt(location, strict_mode_violation_type_, NULL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001626 *ok = false;
1627 }
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001628}
1629
1630
1631void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
1632 const char* eval_args_type,
1633 Identifier identifier,
1634 bool* ok) {
1635 const char* type = eval_args_type;
1636 if (identifier.IsFutureReserved()) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001637 type = "reserved_word";
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001638 } else if (identifier.IsFutureStrictReserved() || identifier.IsYield()) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001639 type = "strict_reserved_word";
1640 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001641 if (!is_classic_mode()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001642 ReportMessageAt(location, type, NULL);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001643 *ok = false;
1644 return;
1645 }
1646 strict_mode_violation_location_ = location;
1647 strict_mode_violation_type_ = type;
1648}
1649
1650
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001651PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001652 i::Token::Value next = Next();
1653 if (i::Token::IsKeyword(next)) {
1654 int pos = scanner_->location().beg_pos;
1655 const char* keyword = i::Token::String(next);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001656 log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
1657 i::StrLength(keyword)));
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001658 return Identifier::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001659 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001660 if (next == i::Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00001661 next == i::Token::FUTURE_RESERVED_WORD ||
1662 next == i::Token::FUTURE_STRICT_RESERVED_WORD) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001663 return GetIdentifierSymbol();
1664 }
1665 *ok = false;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001666 return Identifier::Default();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001667}
1668
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001669#undef CHECK_OK
1670
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001671
1672// This function reads an identifier and determines whether or not it
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001673// is 'get' or 'set'.
ager@chromium.org04921a82011-06-27 13:21:41 +00001674PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
1675 bool* is_set,
1676 bool* ok) {
1677 Identifier result = ParseIdentifierName(ok);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001678 if (!*ok) return Identifier::Default();
1679 if (scanner_->is_literal_ascii() &&
1680 scanner_->literal_length() == 3) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00001681 const char* token = scanner_->literal_ascii_string().start();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001682 *is_get = strncmp(token, "get", 3) == 0;
1683 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
1684 }
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001685 return result;
1686}
1687
1688bool PreParser::peek_any_identifier() {
1689 i::Token::Value next = peek();
1690 return next == i::Token::IDENTIFIER ||
ager@chromium.org04921a82011-06-27 13:21:41 +00001691 next == i::Token::FUTURE_RESERVED_WORD ||
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001692 next == i::Token::FUTURE_STRICT_RESERVED_WORD ||
1693 next == i::Token::YIELD;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001694}
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001695
1696
1697int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) {
1698 return AddSymbol(i::Vector<const byte>::cast(key), true, value);
1699}
1700
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001701int DuplicateFinder::AddUtf16Symbol(i::Vector<const uint16_t> key, int value) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001702 return AddSymbol(i::Vector<const byte>::cast(key), false, value);
1703}
1704
1705int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
1706 bool is_ascii,
1707 int value) {
1708 uint32_t hash = Hash(key, is_ascii);
1709 byte* encoding = BackupKey(key, is_ascii);
1710 i::HashMap::Entry* entry = map_.Lookup(encoding, hash, true);
1711 int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
1712 entry->value =
1713 reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
1714 return old_value;
1715}
1716
1717
1718int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) {
1719 ASSERT(key.length() > 0);
1720 // Quick check for already being in canonical form.
1721 if (IsNumberCanonical(key)) {
1722 return AddAsciiSymbol(key, value);
1723 }
1724
1725 int flags = i::ALLOW_HEX | i::ALLOW_OCTALS;
1726 double double_value = StringToDouble(unicode_constants_, key, flags, 0.0);
1727 int length;
1728 const char* string;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001729 if (!std::isfinite(double_value)) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001730 string = "Infinity";
1731 length = 8; // strlen("Infinity");
1732 } else {
1733 string = DoubleToCString(double_value,
1734 i::Vector<char>(number_buffer_, kBufferSize));
1735 length = i::StrLength(string);
1736 }
1737 return AddSymbol(i::Vector<const byte>(reinterpret_cast<const byte*>(string),
1738 length), true, value);
1739}
1740
1741
1742bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
1743 // Test for a safe approximation of number literals that are already
1744 // in canonical form: max 15 digits, no leading zeroes, except an
1745 // integer part that is a single zero, and no trailing zeros below
1746 // the decimal point.
1747 int pos = 0;
1748 int length = number.length();
1749 if (number.length() > 15) return false;
1750 if (number[pos] == '0') {
1751 pos++;
1752 } else {
1753 while (pos < length &&
1754 static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
1755 }
1756 if (length == pos) return true;
1757 if (number[pos] != '.') return false;
1758 pos++;
1759 bool invalid_last_digit = true;
1760 while (pos < length) {
1761 byte digit = number[pos] - '0';
1762 if (digit > '9' - '0') return false;
1763 invalid_last_digit = (digit == 0);
1764 pos++;
1765 }
1766 return !invalid_last_digit;
1767}
1768
1769
1770uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
1771 // Primitive hash function, almost identical to the one used
1772 // for strings (except that it's seeded by the length and ASCII-ness).
1773 int length = key.length();
1774 uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
1775 for (int i = 0; i < length; i++) {
1776 uint32_t c = key[i];
1777 hash = (hash + c) * 1025;
1778 hash ^= (hash >> 6);
1779 }
1780 return hash;
1781}
1782
1783
1784bool DuplicateFinder::Match(void* first, void* second) {
1785 // Decode lengths.
1786 // Length + ASCII-bit is encoded as base 128, most significant heptet first,
1787 // with a 8th bit being non-zero while there are more heptets.
1788 // The value encodes the number of bytes following, and whether the original
1789 // was ASCII.
1790 byte* s1 = reinterpret_cast<byte*>(first);
1791 byte* s2 = reinterpret_cast<byte*>(second);
1792 uint32_t length_ascii_field = 0;
1793 byte c1;
1794 do {
1795 c1 = *s1;
1796 if (c1 != *s2) return false;
1797 length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
1798 s1++;
1799 s2++;
1800 } while ((c1 & 0x80) != 0);
1801 int length = static_cast<int>(length_ascii_field >> 1);
1802 return memcmp(s1, s2, length) == 0;
1803}
1804
1805
1806byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
1807 bool is_ascii) {
1808 uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
1809 backing_store_.StartSequence();
1810 // Emit ascii_length as base-128 encoded number, with the 7th bit set
1811 // on the byte of every heptet except the last, least significant, one.
1812 if (ascii_length >= (1 << 7)) {
1813 if (ascii_length >= (1 << 14)) {
1814 if (ascii_length >= (1 << 21)) {
1815 if (ascii_length >= (1 << 28)) {
1816 backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
1817 }
1818 backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
1819 }
1820 backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
1821 }
1822 backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
1823 }
1824 backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
1825
1826 backing_store_.AddBlock(bytes);
1827 return backing_store_.EndSequence().start();
1828}
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001829} } // v8::preparser