OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
| 28 #include <math.h> |
| 29 |
28 #include "../include/v8stdint.h" | 30 #include "../include/v8stdint.h" |
29 #include "unicode.h" | 31 #include "unicode.h" |
30 #include "globals.h" | 32 #include "globals.h" |
31 #include "checks.h" | 33 #include "checks.h" |
32 #include "allocation.h" | 34 #include "allocation.h" |
33 #include "utils.h" | 35 #include "utils.h" |
34 #include "list.h" | 36 #include "list.h" |
| 37 #include "conversions.h" |
| 38 #include "hashmap.h" |
35 | 39 |
36 #include "scanner-base.h" | 40 #include "scanner-base.h" |
37 #include "preparse-data-format.h" | 41 #include "preparse-data-format.h" |
38 #include "preparse-data.h" | 42 #include "preparse-data.h" |
39 #include "preparser.h" | 43 #include "preparser.h" |
40 | 44 |
41 #include "conversions-inl.h" | 45 #include "conversions-inl.h" |
42 | 46 |
43 namespace v8 { | 47 namespace v8 { |
| 48 |
| 49 #ifdef _MSC_VER |
| 50 // Usually defined in math.h, but not in MSVC. |
| 51 // Abstracted to work |
| 52 int isfinite(double value); |
| 53 #endif |
| 54 |
44 namespace preparser { | 55 namespace preparser { |
45 | 56 |
46 // Preparsing checks a JavaScript program and emits preparse-data that helps | 57 // Preparsing checks a JavaScript program and emits preparse-data that helps |
47 // a later parsing to be faster. | 58 // a later parsing to be faster. |
48 // See preparser-data.h for the data. | 59 // See preparser-data.h for the data. |
49 | 60 |
50 // The PreParser checks that the syntax follows the grammar for JavaScript, | 61 // The PreParser checks that the syntax follows the grammar for JavaScript, |
51 // and collects some information about the program along the way. | 62 // and collects some information about the program along the way. |
52 // The grammar check is only performed in order to understand the program | 63 // The grammar check is only performed in order to understand the program |
53 // sufficiently to deduce some information about it, that can be used | 64 // sufficiently to deduce some information about it, that can be used |
54 // to speed up later parsing. Finding errors is not the goal of pre-parsing, | 65 // to speed up later parsing. Finding errors is not the goal of pre-parsing, |
55 // rather it is to speed up properly written and correct programs. | 66 // rather it is to speed up properly written and correct programs. |
56 // That means that contextual checks (like a label being declared where | 67 // That means that contextual checks (like a label being declared where |
57 // it is used) are generally omitted. | 68 // it is used) are generally omitted. |
58 | 69 |
59 void PreParser::ReportUnexpectedToken(i::Token::Value token) { | 70 void PreParser::ReportUnexpectedToken(i::Token::Value token) { |
60 // We don't report stack overflows here, to avoid increasing the | 71 // We don't report stack overflows here, to avoid increasing the |
61 // stack depth even further. Instead we report it after parsing is | 72 // stack depth even further. Instead we report it after parsing is |
62 // over, in ParseProgram. | 73 // over, in ParseProgram. |
63 if (token == i::Token::ILLEGAL && stack_overflow_) { | 74 if (token == i::Token::ILLEGAL && stack_overflow_) { |
64 return; | 75 return; |
65 } | 76 } |
66 i::JavaScriptScanner::Location source_location = scanner_->location(); | 77 i::JavaScriptScanner::Location source_location = scanner_->location(); |
67 | 78 |
68 // Four of the tokens are treated specially | 79 // Four of the tokens are treated specially |
69 switch (token) { | 80 switch (token) { |
70 case i::Token::EOS: | 81 case i::Token::EOS: |
71 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 82 return ReportMessageAt(source_location, "unexpected_eos", NULL); |
72 "unexpected_eos", NULL); | |
73 case i::Token::NUMBER: | 83 case i::Token::NUMBER: |
74 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 84 return ReportMessageAt(source_location, "unexpected_token_number", NULL); |
75 "unexpected_token_number", NULL); | |
76 case i::Token::STRING: | 85 case i::Token::STRING: |
77 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 86 return ReportMessageAt(source_location, "unexpected_token_string", NULL); |
78 "unexpected_token_string", NULL); | |
79 case i::Token::IDENTIFIER: | 87 case i::Token::IDENTIFIER: |
80 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 88 return ReportMessageAt(source_location, |
81 "unexpected_token_identifier", NULL); | 89 "unexpected_token_identifier", NULL); |
82 case i::Token::FUTURE_RESERVED_WORD: | 90 case i::Token::FUTURE_RESERVED_WORD: |
83 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 91 return ReportMessageAt(source_location, "unexpected_reserved", NULL); |
84 "unexpected_reserved", NULL); | |
85 case i::Token::FUTURE_STRICT_RESERVED_WORD: | 92 case i::Token::FUTURE_STRICT_RESERVED_WORD: |
86 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 93 return ReportMessageAt(source_location, |
87 "unexpected_strict_reserved", NULL); | 94 "unexpected_strict_reserved", NULL); |
88 default: | 95 default: |
89 const char* name = i::Token::String(token); | 96 const char* name = i::Token::String(token); |
90 ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 97 ReportMessageAt(source_location, "unexpected_token", name); |
91 "unexpected_token", name); | |
92 } | 98 } |
93 } | 99 } |
94 | 100 |
95 | 101 |
96 // Checks whether octal literal last seen is between beg_pos and end_pos. | 102 // Checks whether octal literal last seen is between beg_pos and end_pos. |
97 // If so, reports an error. | 103 // If so, reports an error. |
98 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { | 104 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { |
99 i::Scanner::Location octal = scanner_->octal_position(); | 105 i::Scanner::Location octal = scanner_->octal_position(); |
100 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { | 106 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { |
101 ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL); | 107 ReportMessageAt(octal, "strict_octal_literal", NULL); |
102 scanner_->clear_octal_position(); | 108 scanner_->clear_octal_position(); |
103 *ok = false; | 109 *ok = false; |
104 } | 110 } |
105 } | 111 } |
106 | 112 |
107 | 113 |
108 #define CHECK_OK ok); \ | 114 #define CHECK_OK ok); \ |
109 if (!*ok) return kUnknownSourceElements; \ | 115 if (!*ok) return kUnknownSourceElements; \ |
110 ((void)0 | 116 ((void)0 |
111 #define DUMMY ) // to make indentation work | 117 #define DUMMY ) // to make indentation work |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 Expression function_value = ParseFunctionLiteral(CHECK_OK); | 250 Expression function_value = ParseFunctionLiteral(CHECK_OK); |
245 | 251 |
246 if (function_value.IsStrictFunction() && | 252 if (function_value.IsStrictFunction() && |
247 !identifier.IsValidStrictVariable()) { | 253 !identifier.IsValidStrictVariable()) { |
248 // Strict mode violation, using either reserved word or eval/arguments | 254 // Strict mode violation, using either reserved word or eval/arguments |
249 // as name of strict function. | 255 // as name of strict function. |
250 const char* type = "strict_function_name"; | 256 const char* type = "strict_function_name"; |
251 if (identifier.IsFutureStrictReserved()) { | 257 if (identifier.IsFutureStrictReserved()) { |
252 type = "strict_reserved_word"; | 258 type = "strict_reserved_word"; |
253 } | 259 } |
254 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 260 ReportMessageAt(location, type, NULL); |
255 *ok = false; | 261 *ok = false; |
256 } | 262 } |
257 return Statement::FunctionDeclaration(); | 263 return Statement::FunctionDeclaration(); |
258 } | 264 } |
259 | 265 |
260 | 266 |
261 PreParser::Statement PreParser::ParseBlock(bool* ok) { | 267 PreParser::Statement PreParser::ParseBlock(bool* ok) { |
262 // Block :: | 268 // Block :: |
263 // '{' Statement* '}' | 269 // '{' Statement* '}' |
264 | 270 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 int* num_decl, | 312 int* num_decl, |
307 bool* ok) { | 313 bool* ok) { |
308 // VariableDeclarations :: | 314 // VariableDeclarations :: |
309 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | 315 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] |
310 | 316 |
311 if (peek() == i::Token::VAR) { | 317 if (peek() == i::Token::VAR) { |
312 Consume(i::Token::VAR); | 318 Consume(i::Token::VAR); |
313 } else if (peek() == i::Token::CONST) { | 319 } else if (peek() == i::Token::CONST) { |
314 if (strict_mode()) { | 320 if (strict_mode()) { |
315 i::Scanner::Location location = scanner_->peek_location(); | 321 i::Scanner::Location location = scanner_->peek_location(); |
316 ReportMessageAt(location.beg_pos, location.end_pos, | 322 ReportMessageAt(location, "strict_const", NULL); |
317 "strict_const", NULL); | |
318 *ok = false; | 323 *ok = false; |
319 return Statement::Default(); | 324 return Statement::Default(); |
320 } | 325 } |
321 Consume(i::Token::CONST); | 326 Consume(i::Token::CONST); |
322 } else if (peek() == i::Token::LET) { | 327 } else if (peek() == i::Token::LET) { |
323 if (var_context != kSourceElement && | 328 if (var_context != kSourceElement && |
324 var_context != kForStatement) { | 329 var_context != kForStatement) { |
325 i::Scanner::Location location = scanner_->peek_location(); | 330 i::Scanner::Location location = scanner_->peek_location(); |
326 ReportMessageAt(location.beg_pos, location.end_pos, | 331 ReportMessageAt(location.beg_pos, location.end_pos, |
327 "unprotected_let", NULL); | 332 "unprotected_let", NULL); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
468 return Statement::Default(); | 473 return Statement::Default(); |
469 } | 474 } |
470 | 475 |
471 | 476 |
472 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { | 477 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { |
473 // WithStatement :: | 478 // WithStatement :: |
474 // 'with' '(' Expression ')' Statement | 479 // 'with' '(' Expression ')' Statement |
475 Expect(i::Token::WITH, CHECK_OK); | 480 Expect(i::Token::WITH, CHECK_OK); |
476 if (strict_mode()) { | 481 if (strict_mode()) { |
477 i::Scanner::Location location = scanner_->location(); | 482 i::Scanner::Location location = scanner_->location(); |
478 ReportMessageAt(location.beg_pos, location.end_pos, | 483 ReportMessageAt(location, "strict_mode_with", NULL); |
479 "strict_mode_with", NULL); | |
480 *ok = false; | 484 *ok = false; |
481 return Statement::Default(); | 485 return Statement::Default(); |
482 } | 486 } |
483 Expect(i::Token::LPAREN, CHECK_OK); | 487 Expect(i::Token::LPAREN, CHECK_OK); |
484 ParseExpression(true, CHECK_OK); | 488 ParseExpression(true, CHECK_OK); |
485 Expect(i::Token::RPAREN, CHECK_OK); | 489 Expect(i::Token::RPAREN, CHECK_OK); |
486 | 490 |
487 scope_->EnterWith(); | 491 scope_->EnterWith(); |
488 ParseStatement(CHECK_OK); | 492 ParseStatement(CHECK_OK); |
489 scope_->LeaveWith(); | 493 scope_->LeaveWith(); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 } | 609 } |
606 | 610 |
607 | 611 |
608 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { | 612 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { |
609 // ThrowStatement :: | 613 // ThrowStatement :: |
610 // 'throw' [no line terminator] Expression ';' | 614 // 'throw' [no line terminator] Expression ';' |
611 | 615 |
612 Expect(i::Token::THROW, CHECK_OK); | 616 Expect(i::Token::THROW, CHECK_OK); |
613 if (scanner_->HasAnyLineTerminatorBeforeNext()) { | 617 if (scanner_->HasAnyLineTerminatorBeforeNext()) { |
614 i::JavaScriptScanner::Location pos = scanner_->location(); | 618 i::JavaScriptScanner::Location pos = scanner_->location(); |
615 ReportMessageAt(pos.beg_pos, pos.end_pos, | 619 ReportMessageAt(pos, "newline_after_throw", NULL); |
616 "newline_after_throw", NULL); | |
617 *ok = false; | 620 *ok = false; |
618 return Statement::Default(); | 621 return Statement::Default(); |
619 } | 622 } |
620 ParseExpression(true, CHECK_OK); | 623 ParseExpression(true, CHECK_OK); |
621 ExpectSemicolon(ok); | 624 ExpectSemicolon(ok); |
622 return Statement::Default(); | 625 return Statement::Default(); |
623 } | 626 } |
624 | 627 |
625 | 628 |
626 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { | 629 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 ReportMessageAt(location.beg_pos, location.end_pos, | 1021 ReportMessageAt(location.beg_pos, location.end_pos, |
1019 "reserved_word", NULL); | 1022 "reserved_word", NULL); |
1020 *ok = false; | 1023 *ok = false; |
1021 return Expression::Default(); | 1024 return Expression::Default(); |
1022 } | 1025 } |
1023 | 1026 |
1024 case i::Token::FUTURE_STRICT_RESERVED_WORD: | 1027 case i::Token::FUTURE_STRICT_RESERVED_WORD: |
1025 if (strict_mode()) { | 1028 if (strict_mode()) { |
1026 Next(); | 1029 Next(); |
1027 i::Scanner::Location location = scanner_->location(); | 1030 i::Scanner::Location location = scanner_->location(); |
1028 ReportMessageAt(location.beg_pos, location.end_pos, | 1031 ReportMessageAt(location, "strict_reserved_word", NULL); |
1029 "strict_reserved_word", NULL); | |
1030 *ok = false; | 1032 *ok = false; |
1031 return Expression::Default(); | 1033 return Expression::Default(); |
1032 } | 1034 } |
1033 // FALLTHROUGH | 1035 // FALLTHROUGH |
1034 case i::Token::IDENTIFIER: { | 1036 case i::Token::IDENTIFIER: { |
1035 Identifier id = ParseIdentifier(CHECK_OK); | 1037 Identifier id = ParseIdentifier(CHECK_OK); |
1036 result = Expression::FromIdentifier(id); | 1038 result = Expression::FromIdentifier(id); |
1037 break; | 1039 break; |
1038 } | 1040 } |
1039 | 1041 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1100 if (peek() != i::Token::RBRACK) { | 1102 if (peek() != i::Token::RBRACK) { |
1101 Expect(i::Token::COMMA, CHECK_OK); | 1103 Expect(i::Token::COMMA, CHECK_OK); |
1102 } | 1104 } |
1103 } | 1105 } |
1104 Expect(i::Token::RBRACK, CHECK_OK); | 1106 Expect(i::Token::RBRACK, CHECK_OK); |
1105 | 1107 |
1106 scope_->NextMaterializedLiteralIndex(); | 1108 scope_->NextMaterializedLiteralIndex(); |
1107 return Expression::Default(); | 1109 return Expression::Default(); |
1108 } | 1110 } |
1109 | 1111 |
| 1112 void PreParser::CheckDuplicate(DuplicateFinder* finder, |
| 1113 i::Token::Value property, |
| 1114 int type, |
| 1115 bool* ok) { |
| 1116 int old_type; |
| 1117 if (property == i::Token::NUMBER) { |
| 1118 old_type = finder->AddNumber(scanner_->literal_ascii_string(), type); |
| 1119 } else if (scanner_->is_literal_ascii()) { |
| 1120 old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(), |
| 1121 type); |
| 1122 } else { |
| 1123 old_type = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type); |
| 1124 } |
| 1125 if (HasConflict(old_type, type)) { |
| 1126 if (IsDataDataConflict(old_type, type)) { |
| 1127 // Both are data properties. |
| 1128 if (!strict_mode()) return; |
| 1129 ReportMessageAt(scanner_->location(), |
| 1130 "strict_duplicate_property", NULL); |
| 1131 } else if (IsDataAccessorConflict(old_type, type)) { |
| 1132 // Both a data and an accessor property with the same name. |
| 1133 ReportMessageAt(scanner_->location(), |
| 1134 "accessor_data_property", NULL); |
| 1135 } else { |
| 1136 ASSERT(IsAccessorAccessorConflict(old_type, type)); |
| 1137 // Both accessors of the same type. |
| 1138 ReportMessageAt(scanner_->location(), |
| 1139 "accessor_get_set", NULL); |
| 1140 } |
| 1141 *ok = false; |
| 1142 } |
| 1143 } |
| 1144 |
1110 | 1145 |
1111 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { | 1146 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { |
1112 // ObjectLiteral :: | 1147 // ObjectLiteral :: |
1113 // '{' ( | 1148 // '{' ( |
1114 // ((IdentifierName | String | Number) ':' AssignmentExpression) | 1149 // ((IdentifierName | String | Number) ':' AssignmentExpression) |
1115 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) | 1150 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) |
1116 // )*[','] '}' | 1151 // )*[','] '}' |
1117 | 1152 |
1118 Expect(i::Token::LBRACE, CHECK_OK); | 1153 Expect(i::Token::LBRACE, CHECK_OK); |
| 1154 DuplicateFinder duplicate_finder(scanner_->unicode_cache()); |
1119 while (peek() != i::Token::RBRACE) { | 1155 while (peek() != i::Token::RBRACE) { |
1120 i::Token::Value next = peek(); | 1156 i::Token::Value next = peek(); |
1121 switch (next) { | 1157 switch (next) { |
1122 case i::Token::IDENTIFIER: | 1158 case i::Token::IDENTIFIER: |
1123 case i::Token::FUTURE_RESERVED_WORD: | 1159 case i::Token::FUTURE_RESERVED_WORD: |
1124 case i::Token::FUTURE_STRICT_RESERVED_WORD: { | 1160 case i::Token::FUTURE_STRICT_RESERVED_WORD: { |
1125 bool is_getter = false; | 1161 bool is_getter = false; |
1126 bool is_setter = false; | 1162 bool is_setter = false; |
1127 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); | 1163 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); |
1128 if ((is_getter || is_setter) && peek() != i::Token::COLON) { | 1164 if ((is_getter || is_setter) && peek() != i::Token::COLON) { |
1129 i::Token::Value name = Next(); | 1165 i::Token::Value name = Next(); |
1130 bool is_keyword = i::Token::IsKeyword(name); | 1166 bool is_keyword = i::Token::IsKeyword(name); |
1131 if (name != i::Token::IDENTIFIER && | 1167 if (name != i::Token::IDENTIFIER && |
1132 name != i::Token::FUTURE_RESERVED_WORD && | 1168 name != i::Token::FUTURE_RESERVED_WORD && |
1133 name != i::Token::FUTURE_STRICT_RESERVED_WORD && | 1169 name != i::Token::FUTURE_STRICT_RESERVED_WORD && |
1134 name != i::Token::NUMBER && | 1170 name != i::Token::NUMBER && |
1135 name != i::Token::STRING && | 1171 name != i::Token::STRING && |
1136 !is_keyword) { | 1172 !is_keyword) { |
1137 *ok = false; | 1173 *ok = false; |
1138 return Expression::Default(); | 1174 return Expression::Default(); |
1139 } | 1175 } |
1140 if (!is_keyword) { | 1176 if (!is_keyword) { |
1141 LogSymbol(); | 1177 LogSymbol(); |
1142 } | 1178 } |
| 1179 PropertyType type = is_getter ? kGetterProperty : kSetterProperty; |
| 1180 CheckDuplicate(&duplicate_finder, name, type, CHECK_OK); |
1143 ParseFunctionLiteral(CHECK_OK); | 1181 ParseFunctionLiteral(CHECK_OK); |
1144 if (peek() != i::Token::RBRACE) { | 1182 if (peek() != i::Token::RBRACE) { |
1145 Expect(i::Token::COMMA, CHECK_OK); | 1183 Expect(i::Token::COMMA, CHECK_OK); |
1146 } | 1184 } |
1147 continue; // restart the while | 1185 continue; // restart the while |
1148 } | 1186 } |
| 1187 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1149 break; | 1188 break; |
1150 } | 1189 } |
1151 case i::Token::STRING: | 1190 case i::Token::STRING: |
1152 Consume(next); | 1191 Consume(next); |
| 1192 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1153 GetStringSymbol(); | 1193 GetStringSymbol(); |
1154 break; | 1194 break; |
1155 case i::Token::NUMBER: | 1195 case i::Token::NUMBER: |
1156 Consume(next); | 1196 Consume(next); |
| 1197 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1157 break; | 1198 break; |
1158 default: | 1199 default: |
1159 if (i::Token::IsKeyword(next)) { | 1200 if (i::Token::IsKeyword(next)) { |
1160 Consume(next); | 1201 Consume(next); |
| 1202 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1161 } else { | 1203 } else { |
1162 // Unexpected token. | 1204 // Unexpected token. |
1163 *ok = false; | 1205 *ok = false; |
1164 return Expression::Default(); | 1206 return Expression::Default(); |
1165 } | 1207 } |
1166 } | 1208 } |
1167 | 1209 |
1168 Expect(i::Token::COLON, CHECK_OK); | 1210 Expect(i::Token::COLON, CHECK_OK); |
1169 ParseAssignmentExpression(true, CHECK_OK); | 1211 ParseAssignmentExpression(true, CHECK_OK); |
1170 | 1212 |
1171 // TODO(1240767): Consider allowing trailing comma. | 1213 // TODO(1240767): Consider allowing trailing comma. |
1172 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); | 1214 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); |
1173 } | 1215 } |
1174 Expect(i::Token::RBRACE, CHECK_OK); | 1216 Expect(i::Token::RBRACE, CHECK_OK); |
1175 | 1217 |
1176 scope_->NextMaterializedLiteralIndex(); | 1218 scope_->NextMaterializedLiteralIndex(); |
1177 return Expression::Default(); | 1219 return Expression::Default(); |
1178 } | 1220 } |
1179 | 1221 |
1180 | 1222 |
1181 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, | 1223 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, |
1182 bool* ok) { | 1224 bool* ok) { |
1183 if (!scanner_->ScanRegExpPattern(seen_equal)) { | 1225 if (!scanner_->ScanRegExpPattern(seen_equal)) { |
1184 Next(); | 1226 Next(); |
1185 i::JavaScriptScanner::Location location = scanner_->location(); | 1227 ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL); |
1186 ReportMessageAt(location.beg_pos, location.end_pos, | |
1187 "unterminated_regexp", NULL); | |
1188 *ok = false; | 1228 *ok = false; |
1189 return Expression::Default(); | 1229 return Expression::Default(); |
1190 } | 1230 } |
1191 | 1231 |
1192 scope_->NextMaterializedLiteralIndex(); | 1232 scope_->NextMaterializedLiteralIndex(); |
1193 | 1233 |
1194 if (!scanner_->ScanRegExpFlags()) { | 1234 if (!scanner_->ScanRegExpFlags()) { |
1195 Next(); | 1235 Next(); |
1196 i::JavaScriptScanner::Location location = scanner_->location(); | 1236 ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL); |
1197 ReportMessageAt(location.beg_pos, location.end_pos, | |
1198 "invalid_regexp_flags", NULL); | |
1199 *ok = false; | 1237 *ok = false; |
1200 return Expression::Default(); | 1238 return Expression::Default(); |
1201 } | 1239 } |
1202 Next(); | 1240 Next(); |
1203 return Expression::Default(); | 1241 return Expression::Default(); |
1204 } | 1242 } |
1205 | 1243 |
1206 | 1244 |
1207 PreParser::Arguments PreParser::ParseArguments(bool* ok) { | 1245 PreParser::Arguments PreParser::ParseArguments(bool* ok) { |
1208 // Arguments :: | 1246 // Arguments :: |
(...skipping 24 matching lines...) Expand all Loading... |
1233 | 1271 |
1234 // Parse function body. | 1272 // Parse function body. |
1235 ScopeType outer_scope_type = scope_->type(); | 1273 ScopeType outer_scope_type = scope_->type(); |
1236 bool inside_with = scope_->IsInsideWith(); | 1274 bool inside_with = scope_->IsInsideWith(); |
1237 Scope function_scope(&scope_, kFunctionScope); | 1275 Scope function_scope(&scope_, kFunctionScope); |
1238 // FormalParameterList :: | 1276 // FormalParameterList :: |
1239 // '(' (Identifier)*[','] ')' | 1277 // '(' (Identifier)*[','] ')' |
1240 Expect(i::Token::LPAREN, CHECK_OK); | 1278 Expect(i::Token::LPAREN, CHECK_OK); |
1241 int start_position = scanner_->location().beg_pos; | 1279 int start_position = scanner_->location().beg_pos; |
1242 bool done = (peek() == i::Token::RPAREN); | 1280 bool done = (peek() == i::Token::RPAREN); |
| 1281 DuplicateFinder duplicate_finder(scanner_->unicode_cache()); |
1243 while (!done) { | 1282 while (!done) { |
1244 Identifier id = ParseIdentifier(CHECK_OK); | 1283 Identifier id = ParseIdentifier(CHECK_OK); |
1245 if (!id.IsValidStrictVariable()) { | 1284 if (!id.IsValidStrictVariable()) { |
1246 StrictModeIdentifierViolation(scanner_->location(), | 1285 StrictModeIdentifierViolation(scanner_->location(), |
1247 "strict_param_name", | 1286 "strict_param_name", |
1248 id, | 1287 id, |
1249 CHECK_OK); | 1288 CHECK_OK); |
1250 } | 1289 } |
| 1290 int prev_value; |
| 1291 if (scanner_->is_literal_ascii()) { |
| 1292 prev_value = |
| 1293 duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1); |
| 1294 } else { |
| 1295 prev_value = |
| 1296 duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1); |
| 1297 } |
| 1298 |
| 1299 if (prev_value != 0) { |
| 1300 SetStrictModeViolation(scanner_->location(), |
| 1301 "strict_param_dupe", |
| 1302 CHECK_OK); |
| 1303 } |
1251 done = (peek() == i::Token::RPAREN); | 1304 done = (peek() == i::Token::RPAREN); |
1252 if (!done) { | 1305 if (!done) { |
1253 Expect(i::Token::COMMA, CHECK_OK); | 1306 Expect(i::Token::COMMA, CHECK_OK); |
1254 } | 1307 } |
1255 } | 1308 } |
1256 Expect(i::Token::RPAREN, CHECK_OK); | 1309 Expect(i::Token::RPAREN, CHECK_OK); |
1257 | 1310 |
1258 Expect(i::Token::LBRACE, CHECK_OK); | 1311 Expect(i::Token::LBRACE, CHECK_OK); |
1259 int function_block_pos = scanner_->location().beg_pos; | 1312 int function_block_pos = scanner_->location().beg_pos; |
1260 | 1313 |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1392 *ok = false; | 1445 *ok = false; |
1393 return Identifier::Default(); | 1446 return Identifier::Default(); |
1394 } | 1447 } |
1395 } | 1448 } |
1396 | 1449 |
1397 | 1450 |
1398 void PreParser::SetStrictModeViolation(i::Scanner::Location location, | 1451 void PreParser::SetStrictModeViolation(i::Scanner::Location location, |
1399 const char* type, | 1452 const char* type, |
1400 bool* ok) { | 1453 bool* ok) { |
1401 if (strict_mode()) { | 1454 if (strict_mode()) { |
1402 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 1455 ReportMessageAt(location, type, NULL); |
1403 *ok = false; | 1456 *ok = false; |
1404 return; | 1457 return; |
1405 } | 1458 } |
1406 // Delay report in case this later turns out to be strict code | 1459 // Delay report in case this later turns out to be strict code |
1407 // (i.e., for function names and parameters prior to a "use strict" | 1460 // (i.e., for function names and parameters prior to a "use strict" |
1408 // directive). | 1461 // directive). |
| 1462 // It's safe to overwrite an existing violation. |
| 1463 // It's either from a function that turned out to be non-strict, |
| 1464 // or it's in the current function (and we just need to report |
| 1465 // one error), or it's in a unclosed nesting function that wasn't |
| 1466 // strict (otherwise we would already be in strict mode). |
1409 strict_mode_violation_location_ = location; | 1467 strict_mode_violation_location_ = location; |
1410 strict_mode_violation_type_ = type; | 1468 strict_mode_violation_type_ = type; |
1411 } | 1469 } |
1412 | 1470 |
1413 | 1471 |
1414 void PreParser::CheckDelayedStrictModeViolation(int beg_pos, | 1472 void PreParser::CheckDelayedStrictModeViolation(int beg_pos, |
1415 int end_pos, | 1473 int end_pos, |
1416 bool* ok) { | 1474 bool* ok) { |
1417 i::Scanner::Location location = strict_mode_violation_location_; | 1475 i::Scanner::Location location = strict_mode_violation_location_; |
1418 if (location.IsValid() && | 1476 if (location.IsValid() && |
1419 location.beg_pos > beg_pos && location.end_pos < end_pos) { | 1477 location.beg_pos > beg_pos && location.end_pos < end_pos) { |
1420 ReportMessageAt(location.beg_pos, location.end_pos, | 1478 ReportMessageAt(location, strict_mode_violation_type_, NULL); |
1421 strict_mode_violation_type_, NULL); | |
1422 *ok = false; | 1479 *ok = false; |
1423 } | 1480 } |
1424 strict_mode_violation_location_ = i::Scanner::Location::invalid(); | |
1425 } | 1481 } |
1426 | 1482 |
1427 | 1483 |
1428 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, | 1484 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, |
1429 const char* eval_args_type, | 1485 const char* eval_args_type, |
1430 Identifier identifier, | 1486 Identifier identifier, |
1431 bool* ok) { | 1487 bool* ok) { |
1432 const char* type = eval_args_type; | 1488 const char* type = eval_args_type; |
1433 if (identifier.IsFutureReserved()) { | 1489 if (identifier.IsFutureReserved()) { |
1434 type = "reserved_word"; | 1490 type = "reserved_word"; |
1435 } else if (identifier.IsFutureStrictReserved()) { | 1491 } else if (identifier.IsFutureStrictReserved()) { |
1436 type = "strict_reserved_word"; | 1492 type = "strict_reserved_word"; |
1437 } | 1493 } |
1438 if (strict_mode()) { | 1494 if (strict_mode()) { |
1439 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 1495 ReportMessageAt(location, type, NULL); |
1440 *ok = false; | 1496 *ok = false; |
1441 return; | 1497 return; |
1442 } | 1498 } |
1443 strict_mode_violation_location_ = location; | 1499 strict_mode_violation_location_ = location; |
1444 strict_mode_violation_type_ = type; | 1500 strict_mode_violation_type_ = type; |
1445 } | 1501 } |
1446 | 1502 |
1447 | 1503 |
1448 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { | 1504 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { |
1449 i::Token::Value next = Next(); | 1505 i::Token::Value next = Next(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1481 } | 1537 } |
1482 return result; | 1538 return result; |
1483 } | 1539 } |
1484 | 1540 |
1485 bool PreParser::peek_any_identifier() { | 1541 bool PreParser::peek_any_identifier() { |
1486 i::Token::Value next = peek(); | 1542 i::Token::Value next = peek(); |
1487 return next == i::Token::IDENTIFIER || | 1543 return next == i::Token::IDENTIFIER || |
1488 next == i::Token::FUTURE_RESERVED_WORD || | 1544 next == i::Token::FUTURE_RESERVED_WORD || |
1489 next == i::Token::FUTURE_STRICT_RESERVED_WORD; | 1545 next == i::Token::FUTURE_STRICT_RESERVED_WORD; |
1490 } | 1546 } |
| 1547 |
| 1548 |
| 1549 int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) { |
| 1550 return AddSymbol(i::Vector<const byte>::cast(key), true, value); |
| 1551 } |
| 1552 |
| 1553 int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) { |
| 1554 return AddSymbol(i::Vector<const byte>::cast(key), false, value); |
| 1555 } |
| 1556 |
| 1557 int DuplicateFinder::AddSymbol(i::Vector<const byte> key, |
| 1558 bool is_ascii, |
| 1559 int value) { |
| 1560 uint32_t hash = Hash(key, is_ascii); |
| 1561 byte* encoding = BackupKey(key, is_ascii); |
| 1562 i::HashMap::Entry* entry = map_->Lookup(encoding, hash, true); |
| 1563 int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); |
| 1564 entry->value = |
| 1565 reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value)); |
| 1566 return old_value; |
| 1567 } |
| 1568 |
| 1569 |
| 1570 int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) { |
| 1571 ASSERT(key.length() > 0); |
| 1572 // Quick check for already being in canonical form. |
| 1573 if (IsNumberCanonical(key)) { |
| 1574 return AddAsciiSymbol(key, value); |
| 1575 } |
| 1576 |
| 1577 int flags = i::ALLOW_HEX | i::ALLOW_OCTALS; |
| 1578 double double_value = StringToDouble(unicode_constants_, key, flags, 0.0); |
| 1579 int length; |
| 1580 const char* string; |
| 1581 if (!isfinite(double_value)) { |
| 1582 string = "Infinity"; |
| 1583 length = 8; // strlen("Infinity"); |
| 1584 } else { |
| 1585 string = DoubleToCString(double_value, |
| 1586 i::Vector<char>(number_buffer_, kBufferSize)); |
| 1587 length = i::StrLength(string); |
| 1588 } |
| 1589 return AddAsciiSymbol(i::Vector<const char>(string, length), value); |
| 1590 } |
| 1591 |
| 1592 |
| 1593 bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) { |
| 1594 // Test for a safe approximation of number literals that are already |
| 1595 // in canonical form: max 15 digits, no leading zeroes, except an |
| 1596 // integer part that is a single zero, and no trailing zeros below |
| 1597 // the decimal point. |
| 1598 int pos = 0; |
| 1599 int length = number.length(); |
| 1600 if (number.length() > 15) return false; |
| 1601 if (number[pos] == '0') { |
| 1602 pos++; |
| 1603 } else { |
| 1604 while (pos < length && |
| 1605 static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++; |
| 1606 } |
| 1607 if (length == pos) return true; |
| 1608 if (number[pos] != '.') return false; |
| 1609 pos++; |
| 1610 bool invalid_last_digit = true; |
| 1611 while (pos < length) { |
| 1612 byte digit = number[pos] - '0'; |
| 1613 if (digit > '9' - '0') return false; |
| 1614 invalid_last_digit = (digit == 0); |
| 1615 pos++; |
| 1616 } |
| 1617 return !invalid_last_digit; |
| 1618 } |
| 1619 |
| 1620 |
| 1621 uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) { |
| 1622 // Primitive hash function, almost identical to the one used |
| 1623 // for strings (except that it's seeded by the length and ASCII-ness). |
| 1624 int length = key.length(); |
| 1625 uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ; |
| 1626 for (int i = 0; i < length; i++) { |
| 1627 uint32_t c = key[i]; |
| 1628 hash = (hash + c) * 1025; |
| 1629 hash ^= (hash >> 6); |
| 1630 } |
| 1631 return hash; |
| 1632 } |
| 1633 |
| 1634 |
| 1635 bool DuplicateFinder::Match(void* first, void* second) { |
| 1636 // Decode lengths. |
| 1637 // Length + ASCII-bit is encoded as base 128, most significant heptet first, |
| 1638 // with a 8th bit being non-zero while there are more heptets. |
| 1639 // The value encodes the number of bytes following, and whether the original |
| 1640 // was ASCII. |
| 1641 byte* s1 = reinterpret_cast<byte*>(first); |
| 1642 byte* s2 = reinterpret_cast<byte*>(second); |
| 1643 uint32_t length_ascii_field = 0; |
| 1644 byte c1; |
| 1645 do { |
| 1646 c1 = *s1; |
| 1647 if (c1 != *s2) return false; |
| 1648 length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f); |
| 1649 s1++; |
| 1650 s2++; |
| 1651 } while ((c1 & 0x80) != 0); |
| 1652 int length = static_cast<int>(length_ascii_field >> 1); |
| 1653 return memcmp(s1, s2, length) == 0; |
| 1654 } |
| 1655 |
| 1656 |
| 1657 byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes, |
| 1658 bool is_ascii) { |
| 1659 uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0); |
| 1660 backing_store_.StartSequence(); |
| 1661 // Emit ascii_length as base-128 encoded number, with the 7th bit set |
| 1662 // on the byte of every heptet except the last, least significant, one. |
| 1663 if (ascii_length >= (1 << 7)) { |
| 1664 if (ascii_length >= (1 << 14)) { |
| 1665 if (ascii_length >= (1 << 21)) { |
| 1666 if (ascii_length >= (1 << 28)) { |
| 1667 backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80)); |
| 1668 } |
| 1669 backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u)); |
| 1670 } |
| 1671 backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u)); |
| 1672 } |
| 1673 backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u)); |
| 1674 } |
| 1675 backing_store_.Add(static_cast<byte>(ascii_length & 0x7f)); |
| 1676 |
| 1677 backing_store_.AddBlock(bytes); |
| 1678 return backing_store_.EndSequence().start(); |
| 1679 } |
1491 } } // v8::preparser | 1680 } } // v8::preparser |
OLD | NEW |