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 <errno.h> |
| 29 #include <math.h> |
| 30 |
28 #include "../include/v8stdint.h" | 31 #include "../include/v8stdint.h" |
29 #include "unicode.h" | 32 #include "unicode.h" |
30 #include "globals.h" | 33 #include "globals.h" |
31 #include "checks.h" | 34 #include "checks.h" |
32 #include "allocation.h" | 35 #include "allocation.h" |
33 #include "utils.h" | 36 #include "utils.h" |
34 #include "list.h" | 37 #include "list.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 namespace v8 { | 45 namespace v8 { |
42 namespace preparser { | 46 namespace preparser { |
43 | 47 |
44 // Preparsing checks a JavaScript program and emits preparse-data that helps | 48 // Preparsing checks a JavaScript program and emits preparse-data that helps |
(...skipping 16 matching lines...) Expand all Loading... |
61 // stack depth even further. Instead we report it after parsing is | 65 // stack depth even further. Instead we report it after parsing is |
62 // over, in ParseProgram. | 66 // over, in ParseProgram. |
63 if (token == i::Token::ILLEGAL && stack_overflow_) { | 67 if (token == i::Token::ILLEGAL && stack_overflow_) { |
64 return; | 68 return; |
65 } | 69 } |
66 i::JavaScriptScanner::Location source_location = scanner_->location(); | 70 i::JavaScriptScanner::Location source_location = scanner_->location(); |
67 | 71 |
68 // Four of the tokens are treated specially | 72 // Four of the tokens are treated specially |
69 switch (token) { | 73 switch (token) { |
70 case i::Token::EOS: | 74 case i::Token::EOS: |
71 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 75 return ReportMessageAt(source_location, "unexpected_eos", NULL); |
72 "unexpected_eos", NULL); | |
73 case i::Token::NUMBER: | 76 case i::Token::NUMBER: |
74 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 77 return ReportMessageAt(source_location, "unexpected_token_number", NULL); |
75 "unexpected_token_number", NULL); | |
76 case i::Token::STRING: | 78 case i::Token::STRING: |
77 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 79 return ReportMessageAt(source_location, "unexpected_token_string", NULL); |
78 "unexpected_token_string", NULL); | |
79 case i::Token::IDENTIFIER: | 80 case i::Token::IDENTIFIER: |
80 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 81 return ReportMessageAt(source_location, |
81 "unexpected_token_identifier", NULL); | 82 "unexpected_token_identifier", NULL); |
82 case i::Token::FUTURE_RESERVED_WORD: | 83 case i::Token::FUTURE_RESERVED_WORD: |
83 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 84 return ReportMessageAt(source_location, "unexpected_reserved", NULL); |
84 "unexpected_reserved", NULL); | |
85 case i::Token::FUTURE_STRICT_RESERVED_WORD: | 85 case i::Token::FUTURE_STRICT_RESERVED_WORD: |
86 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 86 return ReportMessageAt(source_location, |
87 "unexpected_strict_reserved", NULL); | 87 "unexpected_strict_reserved", NULL); |
88 default: | 88 default: |
89 const char* name = i::Token::String(token); | 89 const char* name = i::Token::String(token); |
90 ReportMessageAt(source_location.beg_pos, source_location.end_pos, | 90 ReportMessageAt(source_location, "unexpected_token", name); |
91 "unexpected_token", name); | |
92 } | 91 } |
93 } | 92 } |
94 | 93 |
95 | 94 |
96 // Checks whether octal literal last seen is between beg_pos and end_pos. | 95 // Checks whether octal literal last seen is between beg_pos and end_pos. |
97 // If so, reports an error. | 96 // If so, reports an error. |
98 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { | 97 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { |
99 i::Scanner::Location octal = scanner_->octal_position(); | 98 i::Scanner::Location octal = scanner_->octal_position(); |
100 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { | 99 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { |
101 ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL); | 100 ReportMessageAt(octal, "strict_octal_literal", NULL); |
102 scanner_->clear_octal_position(); | 101 scanner_->clear_octal_position(); |
103 *ok = false; | 102 *ok = false; |
104 } | 103 } |
105 } | 104 } |
106 | 105 |
107 | 106 |
108 #define CHECK_OK ok); \ | 107 #define CHECK_OK ok); \ |
109 if (!*ok) return kUnknownSourceElements; \ | 108 if (!*ok) return kUnknownSourceElements; \ |
110 ((void)0 | 109 ((void)0 |
111 #define DUMMY ) // to make indentation work | 110 #define DUMMY ) // to make indentation work |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 Expression function_value = ParseFunctionLiteral(CHECK_OK); | 233 Expression function_value = ParseFunctionLiteral(CHECK_OK); |
235 | 234 |
236 if (function_value.IsStrictFunction() && | 235 if (function_value.IsStrictFunction() && |
237 !identifier.IsValidStrictVariable()) { | 236 !identifier.IsValidStrictVariable()) { |
238 // Strict mode violation, using either reserved word or eval/arguments | 237 // Strict mode violation, using either reserved word or eval/arguments |
239 // as name of strict function. | 238 // as name of strict function. |
240 const char* type = "strict_function_name"; | 239 const char* type = "strict_function_name"; |
241 if (identifier.IsFutureStrictReserved()) { | 240 if (identifier.IsFutureStrictReserved()) { |
242 type = "strict_reserved_word"; | 241 type = "strict_reserved_word"; |
243 } | 242 } |
244 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 243 ReportMessageAt(location, type, NULL); |
245 *ok = false; | 244 *ok = false; |
246 } | 245 } |
247 return Statement::FunctionDeclaration(); | 246 return Statement::FunctionDeclaration(); |
248 } | 247 } |
249 | 248 |
250 | 249 |
251 PreParser::Statement PreParser::ParseBlock(bool* ok) { | 250 PreParser::Statement PreParser::ParseBlock(bool* ok) { |
252 // Block :: | 251 // Block :: |
253 // '{' Statement* '}' | 252 // '{' Statement* '}' |
254 | 253 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 int* num_decl, | 290 int* num_decl, |
292 bool* ok) { | 291 bool* ok) { |
293 // VariableDeclarations :: | 292 // VariableDeclarations :: |
294 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] | 293 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] |
295 | 294 |
296 if (peek() == i::Token::VAR) { | 295 if (peek() == i::Token::VAR) { |
297 Consume(i::Token::VAR); | 296 Consume(i::Token::VAR); |
298 } else if (peek() == i::Token::CONST) { | 297 } else if (peek() == i::Token::CONST) { |
299 if (strict_mode()) { | 298 if (strict_mode()) { |
300 i::Scanner::Location location = scanner_->peek_location(); | 299 i::Scanner::Location location = scanner_->peek_location(); |
301 ReportMessageAt(location.beg_pos, location.end_pos, | 300 ReportMessageAt(location, "strict_const", NULL); |
302 "strict_const", NULL); | |
303 *ok = false; | 301 *ok = false; |
304 return Statement::Default(); | 302 return Statement::Default(); |
305 } | 303 } |
306 Consume(i::Token::CONST); | 304 Consume(i::Token::CONST); |
307 } else { | 305 } else { |
308 *ok = false; | 306 *ok = false; |
309 return Statement::Default(); | 307 return Statement::Default(); |
310 } | 308 } |
311 | 309 |
312 // The scope of a variable/const declared anywhere inside a function | 310 // The scope of a variable/const declared anywhere inside a function |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
441 return Statement::Default(); | 439 return Statement::Default(); |
442 } | 440 } |
443 | 441 |
444 | 442 |
445 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { | 443 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { |
446 // WithStatement :: | 444 // WithStatement :: |
447 // 'with' '(' Expression ')' Statement | 445 // 'with' '(' Expression ')' Statement |
448 Expect(i::Token::WITH, CHECK_OK); | 446 Expect(i::Token::WITH, CHECK_OK); |
449 if (strict_mode()) { | 447 if (strict_mode()) { |
450 i::Scanner::Location location = scanner_->location(); | 448 i::Scanner::Location location = scanner_->location(); |
451 ReportMessageAt(location.beg_pos, location.end_pos, | 449 ReportMessageAt(location, "strict_mode_with", NULL); |
452 "strict_mode_with", NULL); | |
453 *ok = false; | 450 *ok = false; |
454 return Statement::Default(); | 451 return Statement::Default(); |
455 } | 452 } |
456 Expect(i::Token::LPAREN, CHECK_OK); | 453 Expect(i::Token::LPAREN, CHECK_OK); |
457 ParseExpression(true, CHECK_OK); | 454 ParseExpression(true, CHECK_OK); |
458 Expect(i::Token::RPAREN, CHECK_OK); | 455 Expect(i::Token::RPAREN, CHECK_OK); |
459 | 456 |
460 scope_->EnterWith(); | 457 scope_->EnterWith(); |
461 ParseStatement(CHECK_OK); | 458 ParseStatement(CHECK_OK); |
462 scope_->LeaveWith(); | 459 scope_->LeaveWith(); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 } | 574 } |
578 | 575 |
579 | 576 |
580 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { | 577 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { |
581 // ThrowStatement :: | 578 // ThrowStatement :: |
582 // 'throw' [no line terminator] Expression ';' | 579 // 'throw' [no line terminator] Expression ';' |
583 | 580 |
584 Expect(i::Token::THROW, CHECK_OK); | 581 Expect(i::Token::THROW, CHECK_OK); |
585 if (scanner_->HasAnyLineTerminatorBeforeNext()) { | 582 if (scanner_->HasAnyLineTerminatorBeforeNext()) { |
586 i::JavaScriptScanner::Location pos = scanner_->location(); | 583 i::JavaScriptScanner::Location pos = scanner_->location(); |
587 ReportMessageAt(pos.beg_pos, pos.end_pos, | 584 ReportMessageAt(pos, "newline_after_throw", NULL); |
588 "newline_after_throw", NULL); | |
589 *ok = false; | 585 *ok = false; |
590 return Statement::Default(); | 586 return Statement::Default(); |
591 } | 587 } |
592 ParseExpression(true, CHECK_OK); | 588 ParseExpression(true, CHECK_OK); |
593 ExpectSemicolon(ok); | 589 ExpectSemicolon(ok); |
594 return Statement::Default(); | 590 return Statement::Default(); |
595 } | 591 } |
596 | 592 |
597 | 593 |
598 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { | 594 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { |
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
990 ReportMessageAt(location.beg_pos, location.end_pos, | 986 ReportMessageAt(location.beg_pos, location.end_pos, |
991 "reserved_word", NULL); | 987 "reserved_word", NULL); |
992 *ok = false; | 988 *ok = false; |
993 return Expression::Default(); | 989 return Expression::Default(); |
994 } | 990 } |
995 | 991 |
996 case i::Token::FUTURE_STRICT_RESERVED_WORD: | 992 case i::Token::FUTURE_STRICT_RESERVED_WORD: |
997 if (strict_mode()) { | 993 if (strict_mode()) { |
998 Next(); | 994 Next(); |
999 i::Scanner::Location location = scanner_->location(); | 995 i::Scanner::Location location = scanner_->location(); |
1000 ReportMessageAt(location.beg_pos, location.end_pos, | 996 ReportMessageAt(location, "strict_reserved_word", NULL); |
1001 "strict_reserved_word", NULL); | |
1002 *ok = false; | 997 *ok = false; |
1003 return Expression::Default(); | 998 return Expression::Default(); |
1004 } | 999 } |
1005 // FALLTHROUGH | 1000 // FALLTHROUGH |
1006 case i::Token::IDENTIFIER: { | 1001 case i::Token::IDENTIFIER: { |
1007 Identifier id = ParseIdentifier(CHECK_OK); | 1002 Identifier id = ParseIdentifier(CHECK_OK); |
1008 result = Expression::FromIdentifier(id); | 1003 result = Expression::FromIdentifier(id); |
1009 break; | 1004 break; |
1010 } | 1005 } |
1011 | 1006 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1072 if (peek() != i::Token::RBRACK) { | 1067 if (peek() != i::Token::RBRACK) { |
1073 Expect(i::Token::COMMA, CHECK_OK); | 1068 Expect(i::Token::COMMA, CHECK_OK); |
1074 } | 1069 } |
1075 } | 1070 } |
1076 Expect(i::Token::RBRACK, CHECK_OK); | 1071 Expect(i::Token::RBRACK, CHECK_OK); |
1077 | 1072 |
1078 scope_->NextMaterializedLiteralIndex(); | 1073 scope_->NextMaterializedLiteralIndex(); |
1079 return Expression::Default(); | 1074 return Expression::Default(); |
1080 } | 1075 } |
1081 | 1076 |
| 1077 void PreParser::CheckDuplicate(DuplicateFinder* finder, |
| 1078 i::Token::Value property, |
| 1079 int type, |
| 1080 bool* ok) { |
| 1081 int old_value; |
| 1082 if (property == i::Token::NUMBER) { |
| 1083 old_value = finder->AddNumber(scanner_->literal_ascii_string(), type); |
| 1084 } else if (scanner_->is_literal_ascii()) { |
| 1085 old_value = finder->AddAsciiSymbol(scanner_->literal_ascii_string(), |
| 1086 type); |
| 1087 } else { |
| 1088 old_value = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type); |
| 1089 } |
| 1090 int intersect = old_value & type; |
| 1091 if (intersect != 0) { |
| 1092 if ((intersect & kValueFlag) != 0) { |
| 1093 // Both are data properties. |
| 1094 if (!strict_mode()) return; |
| 1095 ReportMessageAt(scanner_->location(), |
| 1096 "strict_duplicate_property", NULL); |
| 1097 } else if (((old_value ^ type) & kValueFlag) != 0) { |
| 1098 // Both a data and an accessor property with the same name. |
| 1099 ReportMessageAt(scanner_->location(), |
| 1100 "accessor_data_property", NULL); |
| 1101 } else { |
| 1102 // Both accessors of the same type. |
| 1103 ReportMessageAt(scanner_->location(), |
| 1104 "accessor_get_set", NULL); |
| 1105 } |
| 1106 *ok = false; |
| 1107 } |
| 1108 } |
| 1109 |
1082 | 1110 |
1083 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { | 1111 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { |
1084 // ObjectLiteral :: | 1112 // ObjectLiteral :: |
1085 // '{' ( | 1113 // '{' ( |
1086 // ((IdentifierName | String | Number) ':' AssignmentExpression) | 1114 // ((IdentifierName | String | Number) ':' AssignmentExpression) |
1087 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) | 1115 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) |
1088 // )*[','] '}' | 1116 // )*[','] '}' |
1089 | 1117 |
1090 Expect(i::Token::LBRACE, CHECK_OK); | 1118 Expect(i::Token::LBRACE, CHECK_OK); |
| 1119 DuplicateFinder duplicate_finder; |
1091 while (peek() != i::Token::RBRACE) { | 1120 while (peek() != i::Token::RBRACE) { |
1092 i::Token::Value next = peek(); | 1121 i::Token::Value next = peek(); |
1093 switch (next) { | 1122 switch (next) { |
1094 case i::Token::IDENTIFIER: | 1123 case i::Token::IDENTIFIER: |
1095 case i::Token::FUTURE_RESERVED_WORD: | 1124 case i::Token::FUTURE_RESERVED_WORD: |
1096 case i::Token::FUTURE_STRICT_RESERVED_WORD: { | 1125 case i::Token::FUTURE_STRICT_RESERVED_WORD: { |
1097 bool is_getter = false; | 1126 bool is_getter = false; |
1098 bool is_setter = false; | 1127 bool is_setter = false; |
1099 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); | 1128 ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK); |
1100 if ((is_getter || is_setter) && peek() != i::Token::COLON) { | 1129 if ((is_getter || is_setter) && peek() != i::Token::COLON) { |
1101 i::Token::Value name = Next(); | 1130 i::Token::Value name = Next(); |
1102 bool is_keyword = i::Token::IsKeyword(name); | 1131 bool is_keyword = i::Token::IsKeyword(name); |
1103 if (name != i::Token::IDENTIFIER && | 1132 if (name != i::Token::IDENTIFIER && |
1104 name != i::Token::FUTURE_RESERVED_WORD && | 1133 name != i::Token::FUTURE_RESERVED_WORD && |
1105 name != i::Token::FUTURE_STRICT_RESERVED_WORD && | 1134 name != i::Token::FUTURE_STRICT_RESERVED_WORD && |
1106 name != i::Token::NUMBER && | 1135 name != i::Token::NUMBER && |
1107 name != i::Token::STRING && | 1136 name != i::Token::STRING && |
1108 !is_keyword) { | 1137 !is_keyword) { |
1109 *ok = false; | 1138 *ok = false; |
1110 return Expression::Default(); | 1139 return Expression::Default(); |
1111 } | 1140 } |
1112 if (!is_keyword) { | 1141 if (!is_keyword) { |
1113 LogSymbol(); | 1142 LogSymbol(); |
1114 } | 1143 } |
| 1144 int type = is_getter ? kGetterProperty : kSetterProperty; |
| 1145 CheckDuplicate(&duplicate_finder, name, type, CHECK_OK); |
1115 ParseFunctionLiteral(CHECK_OK); | 1146 ParseFunctionLiteral(CHECK_OK); |
1116 if (peek() != i::Token::RBRACE) { | 1147 if (peek() != i::Token::RBRACE) { |
1117 Expect(i::Token::COMMA, CHECK_OK); | 1148 Expect(i::Token::COMMA, CHECK_OK); |
1118 } | 1149 } |
1119 continue; // restart the while | 1150 continue; // restart the while |
1120 } | 1151 } |
| 1152 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1121 break; | 1153 break; |
1122 } | 1154 } |
1123 case i::Token::STRING: | 1155 case i::Token::STRING: |
1124 Consume(next); | 1156 Consume(next); |
| 1157 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1125 GetStringSymbol(); | 1158 GetStringSymbol(); |
1126 break; | 1159 break; |
1127 case i::Token::NUMBER: | 1160 case i::Token::NUMBER: |
1128 Consume(next); | 1161 Consume(next); |
| 1162 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1129 break; | 1163 break; |
1130 default: | 1164 default: |
1131 if (i::Token::IsKeyword(next)) { | 1165 if (i::Token::IsKeyword(next)) { |
1132 Consume(next); | 1166 Consume(next); |
| 1167 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK); |
1133 } else { | 1168 } else { |
1134 // Unexpected token. | 1169 // Unexpected token. |
1135 *ok = false; | 1170 *ok = false; |
1136 return Expression::Default(); | 1171 return Expression::Default(); |
1137 } | 1172 } |
1138 } | 1173 } |
1139 | 1174 |
1140 Expect(i::Token::COLON, CHECK_OK); | 1175 Expect(i::Token::COLON, CHECK_OK); |
1141 ParseAssignmentExpression(true, CHECK_OK); | 1176 ParseAssignmentExpression(true, CHECK_OK); |
1142 | 1177 |
1143 // TODO(1240767): Consider allowing trailing comma. | 1178 // TODO(1240767): Consider allowing trailing comma. |
1144 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); | 1179 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); |
1145 } | 1180 } |
1146 Expect(i::Token::RBRACE, CHECK_OK); | 1181 Expect(i::Token::RBRACE, CHECK_OK); |
1147 | 1182 |
1148 scope_->NextMaterializedLiteralIndex(); | 1183 scope_->NextMaterializedLiteralIndex(); |
1149 return Expression::Default(); | 1184 return Expression::Default(); |
1150 } | 1185 } |
1151 | 1186 |
1152 | 1187 |
1153 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, | 1188 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, |
1154 bool* ok) { | 1189 bool* ok) { |
1155 if (!scanner_->ScanRegExpPattern(seen_equal)) { | 1190 if (!scanner_->ScanRegExpPattern(seen_equal)) { |
1156 Next(); | 1191 Next(); |
1157 i::JavaScriptScanner::Location location = scanner_->location(); | 1192 ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL); |
1158 ReportMessageAt(location.beg_pos, location.end_pos, | |
1159 "unterminated_regexp", NULL); | |
1160 *ok = false; | 1193 *ok = false; |
1161 return Expression::Default(); | 1194 return Expression::Default(); |
1162 } | 1195 } |
1163 | 1196 |
1164 scope_->NextMaterializedLiteralIndex(); | 1197 scope_->NextMaterializedLiteralIndex(); |
1165 | 1198 |
1166 if (!scanner_->ScanRegExpFlags()) { | 1199 if (!scanner_->ScanRegExpFlags()) { |
1167 Next(); | 1200 Next(); |
1168 i::JavaScriptScanner::Location location = scanner_->location(); | 1201 ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL); |
1169 ReportMessageAt(location.beg_pos, location.end_pos, | |
1170 "invalid_regexp_flags", NULL); | |
1171 *ok = false; | 1202 *ok = false; |
1172 return Expression::Default(); | 1203 return Expression::Default(); |
1173 } | 1204 } |
1174 Next(); | 1205 Next(); |
1175 return Expression::Default(); | 1206 return Expression::Default(); |
1176 } | 1207 } |
1177 | 1208 |
1178 | 1209 |
1179 PreParser::Arguments PreParser::ParseArguments(bool* ok) { | 1210 PreParser::Arguments PreParser::ParseArguments(bool* ok) { |
1180 // Arguments :: | 1211 // Arguments :: |
(...skipping 24 matching lines...) Expand all Loading... |
1205 | 1236 |
1206 // Parse function body. | 1237 // Parse function body. |
1207 ScopeType outer_scope_type = scope_->type(); | 1238 ScopeType outer_scope_type = scope_->type(); |
1208 bool inside_with = scope_->IsInsideWith(); | 1239 bool inside_with = scope_->IsInsideWith(); |
1209 Scope function_scope(&scope_, kFunctionScope); | 1240 Scope function_scope(&scope_, kFunctionScope); |
1210 // FormalParameterList :: | 1241 // FormalParameterList :: |
1211 // '(' (Identifier)*[','] ')' | 1242 // '(' (Identifier)*[','] ')' |
1212 Expect(i::Token::LPAREN, CHECK_OK); | 1243 Expect(i::Token::LPAREN, CHECK_OK); |
1213 int start_position = scanner_->location().beg_pos; | 1244 int start_position = scanner_->location().beg_pos; |
1214 bool done = (peek() == i::Token::RPAREN); | 1245 bool done = (peek() == i::Token::RPAREN); |
| 1246 DuplicateFinder duplicate_finder; |
1215 while (!done) { | 1247 while (!done) { |
1216 Identifier id = ParseIdentifier(CHECK_OK); | 1248 Identifier id = ParseIdentifier(CHECK_OK); |
1217 if (!id.IsValidStrictVariable()) { | 1249 if (!id.IsValidStrictVariable()) { |
1218 StrictModeIdentifierViolation(scanner_->location(), | 1250 StrictModeIdentifierViolation(scanner_->location(), |
1219 "strict_param_name", | 1251 "strict_param_name", |
1220 id, | 1252 id, |
1221 CHECK_OK); | 1253 CHECK_OK); |
1222 } | 1254 } |
| 1255 int prev_value; |
| 1256 if (scanner_->is_literal_ascii()) { |
| 1257 prev_value = |
| 1258 duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1); |
| 1259 } else { |
| 1260 prev_value = |
| 1261 duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1); |
| 1262 } |
| 1263 |
| 1264 if (prev_value != 0) { |
| 1265 SetStrictModeViolation(scanner_->location(), |
| 1266 "strict_param_dupe", |
| 1267 CHECK_OK); |
| 1268 } |
1223 done = (peek() == i::Token::RPAREN); | 1269 done = (peek() == i::Token::RPAREN); |
1224 if (!done) { | 1270 if (!done) { |
1225 Expect(i::Token::COMMA, CHECK_OK); | 1271 Expect(i::Token::COMMA, CHECK_OK); |
1226 } | 1272 } |
1227 } | 1273 } |
1228 Expect(i::Token::RPAREN, CHECK_OK); | 1274 Expect(i::Token::RPAREN, CHECK_OK); |
1229 | 1275 |
1230 Expect(i::Token::LBRACE, CHECK_OK); | 1276 Expect(i::Token::LBRACE, CHECK_OK); |
1231 int function_block_pos = scanner_->location().beg_pos; | 1277 int function_block_pos = scanner_->location().beg_pos; |
1232 | 1278 |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 *ok = false; | 1410 *ok = false; |
1365 return Identifier::Default(); | 1411 return Identifier::Default(); |
1366 } | 1412 } |
1367 } | 1413 } |
1368 | 1414 |
1369 | 1415 |
1370 void PreParser::SetStrictModeViolation(i::Scanner::Location location, | 1416 void PreParser::SetStrictModeViolation(i::Scanner::Location location, |
1371 const char* type, | 1417 const char* type, |
1372 bool* ok) { | 1418 bool* ok) { |
1373 if (strict_mode()) { | 1419 if (strict_mode()) { |
1374 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 1420 ReportMessageAt(location, type, NULL); |
1375 *ok = false; | 1421 *ok = false; |
1376 return; | 1422 return; |
1377 } | 1423 } |
1378 // Delay report in case this later turns out to be strict code | 1424 // Delay report in case this later turns out to be strict code |
1379 // (i.e., for function names and parameters prior to a "use strict" | 1425 // (i.e., for function names and parameters prior to a "use strict" |
1380 // directive). | 1426 // directive). |
| 1427 // It's safe to overwrite an existing violation. |
| 1428 // It's either from a function that turned out to be non-strict, |
| 1429 // or it's in the current function (and we just need to report |
| 1430 // one error), or it's in a unclosed nesting function that wasn't |
| 1431 // strict (otherwise we would already be in strict mode). |
1381 strict_mode_violation_location_ = location; | 1432 strict_mode_violation_location_ = location; |
1382 strict_mode_violation_type_ = type; | 1433 strict_mode_violation_type_ = type; |
1383 } | 1434 } |
1384 | 1435 |
1385 | 1436 |
1386 void PreParser::CheckDelayedStrictModeViolation(int beg_pos, | 1437 void PreParser::CheckDelayedStrictModeViolation(int beg_pos, |
1387 int end_pos, | 1438 int end_pos, |
1388 bool* ok) { | 1439 bool* ok) { |
1389 i::Scanner::Location location = strict_mode_violation_location_; | 1440 i::Scanner::Location location = strict_mode_violation_location_; |
1390 if (location.IsValid() && | 1441 if (location.IsValid() && |
1391 location.beg_pos > beg_pos && location.end_pos < end_pos) { | 1442 location.beg_pos > beg_pos && location.end_pos < end_pos) { |
1392 ReportMessageAt(location.beg_pos, location.end_pos, | 1443 ReportMessageAt(location, strict_mode_violation_type_, NULL); |
1393 strict_mode_violation_type_, NULL); | |
1394 *ok = false; | 1444 *ok = false; |
1395 } | 1445 } |
1396 strict_mode_violation_location_ = i::Scanner::Location::invalid(); | |
1397 } | 1446 } |
1398 | 1447 |
1399 | 1448 |
1400 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, | 1449 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, |
1401 const char* eval_args_type, | 1450 const char* eval_args_type, |
1402 Identifier identifier, | 1451 Identifier identifier, |
1403 bool* ok) { | 1452 bool* ok) { |
1404 const char* type = eval_args_type; | 1453 const char* type = eval_args_type; |
1405 if (identifier.IsFutureReserved()) { | 1454 if (identifier.IsFutureReserved()) { |
1406 type = "reserved_word"; | 1455 type = "reserved_word"; |
1407 } else if (identifier.IsFutureStrictReserved()) { | 1456 } else if (identifier.IsFutureStrictReserved()) { |
1408 type = "strict_reserved_word"; | 1457 type = "strict_reserved_word"; |
1409 } | 1458 } |
1410 if (strict_mode()) { | 1459 if (strict_mode()) { |
1411 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); | 1460 ReportMessageAt(location, type, NULL); |
1412 *ok = false; | 1461 *ok = false; |
1413 return; | 1462 return; |
1414 } | 1463 } |
1415 strict_mode_violation_location_ = location; | 1464 strict_mode_violation_location_ = location; |
1416 strict_mode_violation_type_ = type; | 1465 strict_mode_violation_type_ = type; |
1417 } | 1466 } |
1418 | 1467 |
1419 | 1468 |
1420 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { | 1469 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { |
1421 i::Token::Value next = Next(); | 1470 i::Token::Value next = Next(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1453 } | 1502 } |
1454 return result; | 1503 return result; |
1455 } | 1504 } |
1456 | 1505 |
1457 bool PreParser::peek_any_identifier() { | 1506 bool PreParser::peek_any_identifier() { |
1458 i::Token::Value next = peek(); | 1507 i::Token::Value next = peek(); |
1459 return next == i::Token::IDENTIFIER || | 1508 return next == i::Token::IDENTIFIER || |
1460 next == i::Token::FUTURE_RESERVED_WORD || | 1509 next == i::Token::FUTURE_RESERVED_WORD || |
1461 next == i::Token::FUTURE_STRICT_RESERVED_WORD; | 1510 next == i::Token::FUTURE_STRICT_RESERVED_WORD; |
1462 } | 1511 } |
| 1512 |
| 1513 |
| 1514 int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) { |
| 1515 return AddSymbol(i::Vector<const byte>::cast(key), true, value); |
| 1516 } |
| 1517 |
| 1518 int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) { |
| 1519 return AddSymbol(i::Vector<const byte>::cast(key), false, value); |
| 1520 } |
| 1521 |
| 1522 int DuplicateFinder::AddSymbol(i::Vector<const byte> key, |
| 1523 bool is_ascii, |
| 1524 int value) { |
| 1525 uint32_t hash = Hash(key, is_ascii); |
| 1526 byte* encoding = BackupKey(key, is_ascii); |
| 1527 i::HashMap::Entry* entry = map_->Lookup(encoding, hash, true); |
| 1528 int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); |
| 1529 entry->value = |
| 1530 reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value)); |
| 1531 return old_value; |
| 1532 } |
| 1533 |
| 1534 |
| 1535 int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) { |
| 1536 // Quick check for already being in canonical form. |
| 1537 if (IsNumberCanonical(key)) { |
| 1538 return AddAsciiSymbol(key, value); |
| 1539 } |
| 1540 |
| 1541 // TODO(lrn): Use correct string->number->string conversions that |
| 1542 // generate the same string as v8's ToString(ToNumber(literal)). |
| 1543 // Current solution doesn't handle octal, and probably doesn't |
| 1544 // generate the same string in edge cases. |
| 1545 double double_value = 0.0; |
| 1546 double_value = strtod(key.start(), NULL); |
| 1547 int length; |
| 1548 if (errno == ERANGE && double_value == HUGE_VAL) { |
| 1549 // Overflow. |
| 1550 // Negative overflow (-HUGE_VAL) cannit happen as number literals |
| 1551 // don't have signs. |
| 1552 // Underflow is handled by the default code, since it returns 0. |
| 1553 length = 8; // strlen("Infinity"); |
| 1554 memcpy(number_buffer_, "Infinity", length); |
| 1555 } else { |
| 1556 length = snprintf(number_buffer_, kBufferSize, "%g", double_value); |
| 1557 } |
| 1558 return AddAsciiSymbol(i::Vector<const char>(number_buffer_, length), value); |
| 1559 } |
| 1560 |
| 1561 |
| 1562 bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) { |
| 1563 // Test for a safe approximation of number literals that are already |
| 1564 // in canonical form: max 15 digits, no leading zeroes, except an |
| 1565 // integer part that is a single zero, and no trailing zeros below |
| 1566 // the decimal point. |
| 1567 int pos = 0; |
| 1568 int length = number.length(); |
| 1569 if (number.length() > 15) return false; |
| 1570 if (number[pos] == '0') { |
| 1571 pos++; |
| 1572 } else { |
| 1573 while (pos < length && |
| 1574 static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++; |
| 1575 } |
| 1576 if (length == pos) return true; |
| 1577 if (number[pos] != '.') return false; |
| 1578 pos++; |
| 1579 bool invalid_last_digit = true; |
| 1580 while (pos < length) { |
| 1581 byte digit = number[pos] - '0'; |
| 1582 if (digit > '9' - '0') return false; |
| 1583 invalid_last_digit = (digit == 0); |
| 1584 pos++; |
| 1585 } |
| 1586 return !invalid_last_digit; |
| 1587 } |
| 1588 |
| 1589 |
| 1590 uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) { |
| 1591 // Primitive hash function, almost identical to the one used |
| 1592 // for strings (except that it's seeded by the length and ASCII-ness). |
| 1593 int length = key.length(); |
| 1594 uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ; |
| 1595 for (int i = 0; i < length; i++) { |
| 1596 uint32_t c = key[i]; |
| 1597 hash = (hash + c) * 1025; |
| 1598 hash ^= (hash >> 6); |
| 1599 } |
| 1600 return hash; |
| 1601 } |
| 1602 |
| 1603 |
| 1604 bool DuplicateFinder::Match(void* first, void* second) { |
| 1605 // Decode lengths. |
| 1606 // Length + ASCII-bit is encoded as base 128, most significant heptet first, |
| 1607 // with a 8th bit being non-zero while there are more heptets. |
| 1608 // The value encodes the number of bytes following, and whether the original |
| 1609 // was ASCII. |
| 1610 byte* s1 = reinterpret_cast<byte*>(first); |
| 1611 byte* s2 = reinterpret_cast<byte*>(second); |
| 1612 uint32_t length_ascii_field = 0; |
| 1613 byte c1; |
| 1614 do { |
| 1615 c1 = *s1; |
| 1616 if (c1 != *s2) return false; |
| 1617 length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f); |
| 1618 s1++; |
| 1619 s2++; |
| 1620 } while ((c1 & 0x80) != 0); |
| 1621 int length = static_cast<int>(length_ascii_field >> 1); |
| 1622 return memcmp(s1, s2, length) == 0; |
| 1623 } |
| 1624 |
| 1625 |
| 1626 byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes, |
| 1627 bool is_ascii) { |
| 1628 uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0); |
| 1629 backing_store_.StartSequence(); |
| 1630 // Emit ascii_length as base-128 encoded number, with the 7th bit set |
| 1631 // on the byte of every heptet except the last, least significant, one. |
| 1632 if (ascii_length >= (1 << 7)) { |
| 1633 if (ascii_length >= (1 << 14)) { |
| 1634 if (ascii_length >= (1 << 21)) { |
| 1635 if (ascii_length >= (1 << 28)) { |
| 1636 backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80)); |
| 1637 } |
| 1638 backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u)); |
| 1639 } |
| 1640 backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u)); |
| 1641 } |
| 1642 backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u)); |
| 1643 } |
| 1644 backing_store_.Add(static_cast<byte>(ascii_length & 0x7f)); |
| 1645 |
| 1646 backing_store_.AddBlock(bytes); |
| 1647 return backing_store_.EndSequence().start(); |
| 1648 } |
1463 } } // v8::preparser | 1649 } } // v8::preparser |
OLD | NEW |