Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(469)

Side by Side Diff: src/preparser.cc

Issue 7168016: Add duplicate parameter detection to preparser. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fixed a typo Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 case i::Token::FUTURE_RESERVED_WORD: 81 case i::Token::FUTURE_RESERVED_WORD:
81 return ReportMessageAt(source_location.beg_pos, source_location.end_pos, 82 return ReportMessageAt(source_location,
82 "unexpected_token_identifier", NULL); 83 "unexpected_token_identifier", NULL);
83 default: 84 default:
84 const char* name = i::Token::String(token); 85 const char* name = i::Token::String(token);
85 ReportMessageAt(source_location.beg_pos, source_location.end_pos, 86 ReportMessageAt(source_location, "unexpected_token", name);
86 "unexpected_token", name);
87 } 87 }
88 } 88 }
89 89
90 90
91 // Checks whether octal literal last seen is between beg_pos and end_pos. 91 // Checks whether octal literal last seen is between beg_pos and end_pos.
92 // If so, reports an error. 92 // If so, reports an error.
93 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) { 93 void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
94 i::Scanner::Location octal = scanner_->octal_position(); 94 i::Scanner::Location octal = scanner_->octal_position();
95 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) { 95 if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
96 ReportMessageAt(octal.beg_pos, octal.end_pos, "strict_octal_literal", NULL); 96 ReportMessageAt(octal, "strict_octal_literal", NULL);
97 scanner_->clear_octal_position(); 97 scanner_->clear_octal_position();
98 *ok = false; 98 *ok = false;
99 } 99 }
100 } 100 }
101 101
102 102
103 #define CHECK_OK ok); \ 103 #define CHECK_OK ok); \
104 if (!*ok) return kUnknownSourceElements; \ 104 if (!*ok) return kUnknownSourceElements; \
105 ((void)0 105 ((void)0
106 #define DUMMY ) // to make indentation work 106 #define DUMMY ) // to make indentation work
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 Expression function_value = ParseFunctionLiteral(CHECK_OK); 232 Expression function_value = ParseFunctionLiteral(CHECK_OK);
233 233
234 if (function_value.IsStrictFunction() && 234 if (function_value.IsStrictFunction() &&
235 !identifier.IsValidStrictVariable()) { 235 !identifier.IsValidStrictVariable()) {
236 // Strict mode violation, using either reserved word or eval/arguments 236 // Strict mode violation, using either reserved word or eval/arguments
237 // as name of strict function. 237 // as name of strict function.
238 const char* type = "strict_function_name"; 238 const char* type = "strict_function_name";
239 if (identifier.IsFutureReserved()) { 239 if (identifier.IsFutureReserved()) {
240 type = "strict_reserved_word"; 240 type = "strict_reserved_word";
241 } 241 }
242 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); 242 ReportMessageAt(location, type, NULL);
243 *ok = false; 243 *ok = false;
244 } 244 }
245 return Statement::FunctionDeclaration(); 245 return Statement::FunctionDeclaration();
246 } 246 }
247 247
248 248
249 // Language extension which is only enabled for source files loaded 249 // Language extension which is only enabled for source files loaded
250 // through the API's extension mechanism. A native function 250 // through the API's extension mechanism. A native function
251 // declaration is resolved by looking up the function through a 251 // declaration is resolved by looking up the function through a
252 // callback provided by the extension. 252 // callback provided by the extension.
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 int* num_decl, 312 int* num_decl,
313 bool* ok) { 313 bool* ok) {
314 // VariableDeclarations :: 314 // VariableDeclarations ::
315 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] 315 // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
316 316
317 if (peek() == i::Token::VAR) { 317 if (peek() == i::Token::VAR) {
318 Consume(i::Token::VAR); 318 Consume(i::Token::VAR);
319 } else if (peek() == i::Token::CONST) { 319 } else if (peek() == i::Token::CONST) {
320 if (strict_mode()) { 320 if (strict_mode()) {
321 i::Scanner::Location location = scanner_->peek_location(); 321 i::Scanner::Location location = scanner_->peek_location();
322 ReportMessageAt(location.beg_pos, location.end_pos, 322 ReportMessageAt(location, "strict_const", NULL);
323 "strict_const", NULL);
324 *ok = false; 323 *ok = false;
325 return Statement::Default(); 324 return Statement::Default();
326 } 325 }
327 Consume(i::Token::CONST); 326 Consume(i::Token::CONST);
328 } else { 327 } else {
329 *ok = false; 328 *ok = false;
330 return Statement::Default(); 329 return Statement::Default();
331 } 330 }
332 331
333 // The scope of a variable/const declared anywhere inside a function 332 // The scope of a variable/const declared anywhere inside a function
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 return Statement::Default(); 457 return Statement::Default();
459 } 458 }
460 459
461 460
462 PreParser::Statement PreParser::ParseWithStatement(bool* ok) { 461 PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
463 // WithStatement :: 462 // WithStatement ::
464 // 'with' '(' Expression ')' Statement 463 // 'with' '(' Expression ')' Statement
465 Expect(i::Token::WITH, CHECK_OK); 464 Expect(i::Token::WITH, CHECK_OK);
466 if (strict_mode()) { 465 if (strict_mode()) {
467 i::Scanner::Location location = scanner_->location(); 466 i::Scanner::Location location = scanner_->location();
468 ReportMessageAt(location.beg_pos, location.end_pos, 467 ReportMessageAt(location, "strict_mode_with", NULL);
469 "strict_mode_with", NULL);
470 *ok = false; 468 *ok = false;
471 return Statement::Default(); 469 return Statement::Default();
472 } 470 }
473 Expect(i::Token::LPAREN, CHECK_OK); 471 Expect(i::Token::LPAREN, CHECK_OK);
474 ParseExpression(true, CHECK_OK); 472 ParseExpression(true, CHECK_OK);
475 Expect(i::Token::RPAREN, CHECK_OK); 473 Expect(i::Token::RPAREN, CHECK_OK);
476 474
477 scope_->EnterWith(); 475 scope_->EnterWith();
478 ParseStatement(CHECK_OK); 476 ParseStatement(CHECK_OK);
479 scope_->LeaveWith(); 477 scope_->LeaveWith();
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 } 592 }
595 593
596 594
597 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) { 595 PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
598 // ThrowStatement :: 596 // ThrowStatement ::
599 // 'throw' [no line terminator] Expression ';' 597 // 'throw' [no line terminator] Expression ';'
600 598
601 Expect(i::Token::THROW, CHECK_OK); 599 Expect(i::Token::THROW, CHECK_OK);
602 if (scanner_->has_line_terminator_before_next()) { 600 if (scanner_->has_line_terminator_before_next()) {
603 i::JavaScriptScanner::Location pos = scanner_->location(); 601 i::JavaScriptScanner::Location pos = scanner_->location();
604 ReportMessageAt(pos.beg_pos, pos.end_pos, 602 ReportMessageAt(pos, "newline_after_throw", NULL);
605 "newline_after_throw", NULL);
606 *ok = false; 603 *ok = false;
607 return Statement::Default(); 604 return Statement::Default();
608 } 605 }
609 ParseExpression(true, CHECK_OK); 606 ParseExpression(true, CHECK_OK);
610 ExpectSemicolon(ok); 607 ExpectSemicolon(ok);
611 return Statement::Default(); 608 return Statement::Default();
612 } 609 }
613 610
614 611
615 PreParser::Statement PreParser::ParseTryStatement(bool* ok) { 612 PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
998 case i::Token::THIS: { 995 case i::Token::THIS: {
999 Next(); 996 Next();
1000 result = Expression::This(); 997 result = Expression::This();
1001 break; 998 break;
1002 } 999 }
1003 1000
1004 case i::Token::FUTURE_RESERVED_WORD: 1001 case i::Token::FUTURE_RESERVED_WORD:
1005 if (strict_mode()) { 1002 if (strict_mode()) {
1006 Next(); 1003 Next();
1007 i::Scanner::Location location = scanner_->location(); 1004 i::Scanner::Location location = scanner_->location();
1008 ReportMessageAt(location.beg_pos, location.end_pos, 1005 ReportMessageAt(location, "strict_reserved_word", NULL);
1009 "strict_reserved_word", NULL);
1010 *ok = false; 1006 *ok = false;
1011 return Expression::Default(); 1007 return Expression::Default();
1012 } 1008 }
1013 // FALLTHROUGH 1009 // FALLTHROUGH
1014 case i::Token::IDENTIFIER: { 1010 case i::Token::IDENTIFIER: {
1015 Identifier id = ParseIdentifier(CHECK_OK); 1011 Identifier id = ParseIdentifier(CHECK_OK);
1016 result = Expression::FromIdentifier(id); 1012 result = Expression::FromIdentifier(id);
1017 break; 1013 break;
1018 } 1014 }
1019 1015
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1080 if (peek() != i::Token::RBRACK) { 1076 if (peek() != i::Token::RBRACK) {
1081 Expect(i::Token::COMMA, CHECK_OK); 1077 Expect(i::Token::COMMA, CHECK_OK);
1082 } 1078 }
1083 } 1079 }
1084 Expect(i::Token::RBRACK, CHECK_OK); 1080 Expect(i::Token::RBRACK, CHECK_OK);
1085 1081
1086 scope_->NextMaterializedLiteralIndex(); 1082 scope_->NextMaterializedLiteralIndex();
1087 return Expression::Default(); 1083 return Expression::Default();
1088 } 1084 }
1089 1085
1086 void PreParser::CheckDuplicate(DuplicateFinder* finder,
1087 i::Token::Value property,
1088 int type,
1089 bool* ok) {
1090 int old_value;
1091 if (property == i::Token::NUMBER) {
1092 old_value = finder->AddNumber(scanner_->literal_ascii_string(), type);
1093 } else if (scanner_->is_literal_ascii()) {
1094 old_value = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
1095 type);
1096 } else {
1097 old_value = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type);
1098 }
1099 int intersect = old_value & type;
Mads Ager (chromium) 2011/06/16 06:48:56 And this is what that comment on the enum should s
1100 if (intersect != 0) {
1101 if ((intersect & kValueFlag) != 0) {
Mads Ager (chromium) 2011/06/16 06:48:56 Maybe have methods for these bit operations? Both
1102 // Both are data properties.
1103 if (!strict_mode()) return;
1104 ReportMessageAt(scanner_->location(),
1105 "strict_duplicate_property", NULL);
1106 } else if (((old_value ^ type) & kValueFlag) != 0) {
1107 // Both a data and an accessor property with the same name.
1108 ReportMessageAt(scanner_->location(),
1109 "accessor_data_property", NULL);
1110 } else {
1111 // Both accessors of the same type.
1112 ReportMessageAt(scanner_->location(),
1113 "accessor_get_set", NULL);
1114 }
1115 *ok = false;
1116 }
1117 }
1118
1090 1119
1091 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) { 1120 PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
1092 // ObjectLiteral :: 1121 // ObjectLiteral ::
1093 // '{' ( 1122 // '{' (
1094 // ((IdentifierName | String | Number) ':' AssignmentExpression) 1123 // ((IdentifierName | String | Number) ':' AssignmentExpression)
1095 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral) 1124 // | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
1096 // )*[','] '}' 1125 // )*[','] '}'
1097 1126
1098 Expect(i::Token::LBRACE, CHECK_OK); 1127 Expect(i::Token::LBRACE, CHECK_OK);
1128 DuplicateFinder duplicate_finder;
1099 while (peek() != i::Token::RBRACE) { 1129 while (peek() != i::Token::RBRACE) {
1100 i::Token::Value next = peek(); 1130 i::Token::Value next = peek();
1101 switch (next) { 1131 switch (next) {
1102 case i::Token::IDENTIFIER: 1132 case i::Token::IDENTIFIER:
1103 case i::Token::FUTURE_RESERVED_WORD: { 1133 case i::Token::FUTURE_RESERVED_WORD: {
1104 bool is_getter = false; 1134 bool is_getter = false;
1105 bool is_setter = false; 1135 bool is_setter = false;
1106 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK); 1136 ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
1107 if ((is_getter || is_setter) && peek() != i::Token::COLON) { 1137 if ((is_getter || is_setter) && peek() != i::Token::COLON) {
1108 i::Token::Value name = Next(); 1138 i::Token::Value name = Next();
1109 bool is_keyword = i::Token::IsKeyword(name); 1139 bool is_keyword = i::Token::IsKeyword(name);
1110 if (name != i::Token::IDENTIFIER && 1140 if (name != i::Token::IDENTIFIER &&
1111 name != i::Token::FUTURE_RESERVED_WORD && 1141 name != i::Token::FUTURE_RESERVED_WORD &&
1112 name != i::Token::NUMBER && 1142 name != i::Token::NUMBER &&
1113 name != i::Token::STRING && 1143 name != i::Token::STRING &&
1114 !is_keyword) { 1144 !is_keyword) {
1115 *ok = false; 1145 *ok = false;
1116 return Expression::Default(); 1146 return Expression::Default();
1117 } 1147 }
1118 if (!is_keyword) { 1148 if (!is_keyword) {
1119 LogSymbol(); 1149 LogSymbol();
1120 } 1150 }
1151 int type = is_getter ? kGetterProperty : kSetterProperty;
1152 CheckDuplicate(&duplicate_finder, name, type, CHECK_OK);
1121 ParseFunctionLiteral(CHECK_OK); 1153 ParseFunctionLiteral(CHECK_OK);
1122 if (peek() != i::Token::RBRACE) { 1154 if (peek() != i::Token::RBRACE) {
1123 Expect(i::Token::COMMA, CHECK_OK); 1155 Expect(i::Token::COMMA, CHECK_OK);
1124 } 1156 }
1125 continue; // restart the while 1157 continue; // restart the while
1126 } 1158 }
1159 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1127 break; 1160 break;
1128 } 1161 }
1129 case i::Token::STRING: 1162 case i::Token::STRING:
1130 Consume(next); 1163 Consume(next);
1164 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1131 GetStringSymbol(); 1165 GetStringSymbol();
1132 break; 1166 break;
1133 case i::Token::NUMBER: 1167 case i::Token::NUMBER:
1134 Consume(next); 1168 Consume(next);
1169 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1135 break; 1170 break;
1136 default: 1171 default:
1137 if (i::Token::IsKeyword(next)) { 1172 if (i::Token::IsKeyword(next)) {
1138 Consume(next); 1173 Consume(next);
1174 CheckDuplicate(&duplicate_finder, next, kValueProperty, CHECK_OK);
1139 } else { 1175 } else {
1140 // Unexpected token. 1176 // Unexpected token.
1141 *ok = false; 1177 *ok = false;
1142 return Expression::Default(); 1178 return Expression::Default();
1143 } 1179 }
1144 } 1180 }
1145 1181
1146 Expect(i::Token::COLON, CHECK_OK); 1182 Expect(i::Token::COLON, CHECK_OK);
1147 ParseAssignmentExpression(true, CHECK_OK); 1183 ParseAssignmentExpression(true, CHECK_OK);
1148 1184
1149 // TODO(1240767): Consider allowing trailing comma. 1185 // TODO(1240767): Consider allowing trailing comma.
1150 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK); 1186 if (peek() != i::Token::RBRACE) Expect(i::Token::COMMA, CHECK_OK);
1151 } 1187 }
1152 Expect(i::Token::RBRACE, CHECK_OK); 1188 Expect(i::Token::RBRACE, CHECK_OK);
1153 1189
1154 scope_->NextMaterializedLiteralIndex(); 1190 scope_->NextMaterializedLiteralIndex();
1155 return Expression::Default(); 1191 return Expression::Default();
1156 } 1192 }
1157 1193
1158 1194
1159 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal, 1195 PreParser::Expression PreParser::ParseRegExpLiteral(bool seen_equal,
1160 bool* ok) { 1196 bool* ok) {
1161 if (!scanner_->ScanRegExpPattern(seen_equal)) { 1197 if (!scanner_->ScanRegExpPattern(seen_equal)) {
1162 Next(); 1198 Next();
1163 i::JavaScriptScanner::Location location = scanner_->location(); 1199 ReportMessageAt(scanner_->location(), "unterminated_regexp", NULL);
1164 ReportMessageAt(location.beg_pos, location.end_pos,
1165 "unterminated_regexp", NULL);
1166 *ok = false; 1200 *ok = false;
1167 return Expression::Default(); 1201 return Expression::Default();
1168 } 1202 }
1169 1203
1170 scope_->NextMaterializedLiteralIndex(); 1204 scope_->NextMaterializedLiteralIndex();
1171 1205
1172 if (!scanner_->ScanRegExpFlags()) { 1206 if (!scanner_->ScanRegExpFlags()) {
1173 Next(); 1207 Next();
1174 i::JavaScriptScanner::Location location = scanner_->location(); 1208 ReportMessageAt(scanner_->location(), "invalid_regexp_flags", NULL);
1175 ReportMessageAt(location.beg_pos, location.end_pos,
1176 "invalid_regexp_flags", NULL);
1177 *ok = false; 1209 *ok = false;
1178 return Expression::Default(); 1210 return Expression::Default();
1179 } 1211 }
1180 Next(); 1212 Next();
1181 return Expression::Default(); 1213 return Expression::Default();
1182 } 1214 }
1183 1215
1184 1216
1185 PreParser::Arguments PreParser::ParseArguments(bool* ok) { 1217 PreParser::Arguments PreParser::ParseArguments(bool* ok) {
1186 // Arguments :: 1218 // Arguments ::
(...skipping 24 matching lines...) Expand all
1211 1243
1212 // Parse function body. 1244 // Parse function body.
1213 ScopeType outer_scope_type = scope_->type(); 1245 ScopeType outer_scope_type = scope_->type();
1214 bool inside_with = scope_->IsInsideWith(); 1246 bool inside_with = scope_->IsInsideWith();
1215 Scope function_scope(&scope_, kFunctionScope); 1247 Scope function_scope(&scope_, kFunctionScope);
1216 // FormalParameterList :: 1248 // FormalParameterList ::
1217 // '(' (Identifier)*[','] ')' 1249 // '(' (Identifier)*[','] ')'
1218 Expect(i::Token::LPAREN, CHECK_OK); 1250 Expect(i::Token::LPAREN, CHECK_OK);
1219 int start_position = scanner_->location().beg_pos; 1251 int start_position = scanner_->location().beg_pos;
1220 bool done = (peek() == i::Token::RPAREN); 1252 bool done = (peek() == i::Token::RPAREN);
1253 DuplicateFinder duplicate_finder;
1221 while (!done) { 1254 while (!done) {
1222 Identifier id = ParseIdentifier(CHECK_OK); 1255 Identifier id = ParseIdentifier(CHECK_OK);
1223 if (!id.IsValidStrictVariable()) { 1256 if (!id.IsValidStrictVariable()) {
1224 StrictModeIdentifierViolation(scanner_->location(), 1257 StrictModeIdentifierViolation(scanner_->location(),
1225 "strict_param_name", 1258 "strict_param_name",
1226 id, 1259 id,
1227 CHECK_OK); 1260 CHECK_OK);
1228 } 1261 }
1262 int prev_value;
1263 if (scanner_->is_literal_ascii()) {
1264 prev_value =
1265 duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
1266 } else {
1267 prev_value =
1268 duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1);
1269 }
1270
1271 if (prev_value != 0) {
1272 SetStrictModeViolation(scanner_->location(),
1273 "strict_param_dupe",
1274 CHECK_OK);
1275 }
1229 done = (peek() == i::Token::RPAREN); 1276 done = (peek() == i::Token::RPAREN);
1230 if (!done) { 1277 if (!done) {
1231 Expect(i::Token::COMMA, CHECK_OK); 1278 Expect(i::Token::COMMA, CHECK_OK);
1232 } 1279 }
1233 } 1280 }
1234 Expect(i::Token::RPAREN, CHECK_OK); 1281 Expect(i::Token::RPAREN, CHECK_OK);
1235 1282
1236 Expect(i::Token::LBRACE, CHECK_OK); 1283 Expect(i::Token::LBRACE, CHECK_OK);
1237 int function_block_pos = scanner_->location().beg_pos; 1284 int function_block_pos = scanner_->location().beg_pos;
1238 1285
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
1356 if (!*ok) return Identifier::Default(); 1403 if (!*ok) return Identifier::Default();
1357 } 1404 }
1358 return GetIdentifierSymbol(); 1405 return GetIdentifierSymbol();
1359 } 1406 }
1360 1407
1361 1408
1362 void PreParser::SetStrictModeViolation(i::Scanner::Location location, 1409 void PreParser::SetStrictModeViolation(i::Scanner::Location location,
1363 const char* type, 1410 const char* type,
1364 bool* ok) { 1411 bool* ok) {
1365 if (strict_mode()) { 1412 if (strict_mode()) {
1366 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); 1413 ReportMessageAt(location, type, NULL);
1367 *ok = false; 1414 *ok = false;
1368 return; 1415 return;
1369 } 1416 }
1370 // Delay report in case this later turns out to be strict code 1417 // Delay report in case this later turns out to be strict code
1371 // (i.e., for function names and parameters prior to a "use strict" 1418 // (i.e., for function names and parameters prior to a "use strict"
1372 // directive). 1419 // directive).
1420 // It's safe to overwrite an existing violation.
1421 // It's either from a function that turned out to be non-strict,
1422 // or it's in the current function (and we just need to report
1423 // one error), or it's in a unclosed nesting function that wasn't
1424 // strict (otherwise we would already be in strict mode).
1373 strict_mode_violation_location_ = location; 1425 strict_mode_violation_location_ = location;
1374 strict_mode_violation_type_ = type; 1426 strict_mode_violation_type_ = type;
1375 } 1427 }
1376 1428
1377 1429
1378 void PreParser::CheckDelayedStrictModeViolation(int beg_pos, 1430 void PreParser::CheckDelayedStrictModeViolation(int beg_pos,
1379 int end_pos, 1431 int end_pos,
1380 bool* ok) { 1432 bool* ok) {
1381 i::Scanner::Location location = strict_mode_violation_location_; 1433 i::Scanner::Location location = strict_mode_violation_location_;
1382 if (location.IsValid() && 1434 if (location.IsValid() &&
1383 location.beg_pos > beg_pos && location.end_pos < end_pos) { 1435 location.beg_pos > beg_pos && location.end_pos < end_pos) {
1384 ReportMessageAt(location.beg_pos, location.end_pos, 1436 ReportMessageAt(location, strict_mode_violation_type_, NULL);
1385 strict_mode_violation_type_, NULL);
1386 *ok = false; 1437 *ok = false;
1387 } 1438 }
1388 strict_mode_violation_location_ = i::Scanner::Location::invalid();
1389 } 1439 }
1390 1440
1391 1441
1392 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location, 1442 void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
1393 const char* eval_args_type, 1443 const char* eval_args_type,
1394 Identifier identifier, 1444 Identifier identifier,
1395 bool* ok) { 1445 bool* ok) {
1396 const char* type = eval_args_type; 1446 const char* type = eval_args_type;
1397 if (identifier.IsFutureReserved()) { 1447 if (identifier.IsFutureReserved()) {
1398 type = "strict_reserved_word"; 1448 type = "strict_reserved_word";
1399 } 1449 }
1400 if (strict_mode()) { 1450 if (strict_mode()) {
1401 ReportMessageAt(location.beg_pos, location.end_pos, type, NULL); 1451 ReportMessageAt(location, type, NULL);
1402 *ok = false; 1452 *ok = false;
1403 return; 1453 return;
1404 } 1454 }
1405 strict_mode_violation_location_ = location; 1455 strict_mode_violation_location_ = location;
1406 strict_mode_violation_type_ = type; 1456 strict_mode_violation_type_ = type;
1407 } 1457 }
1408 1458
1409 1459
1410 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) { 1460 PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
1411 i::Token::Value next = Next(); 1461 i::Token::Value next = Next();
(...skipping 29 matching lines...) Expand all
1441 *is_set = !*is_get && strncmp(token, "set", 3) == 0; 1491 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
1442 } 1492 }
1443 return result; 1493 return result;
1444 } 1494 }
1445 1495
1446 bool PreParser::peek_any_identifier() { 1496 bool PreParser::peek_any_identifier() {
1447 i::Token::Value next = peek(); 1497 i::Token::Value next = peek();
1448 return next == i::Token::IDENTIFIER || 1498 return next == i::Token::IDENTIFIER ||
1449 next == i::Token::FUTURE_RESERVED_WORD; 1499 next == i::Token::FUTURE_RESERVED_WORD;
1450 } 1500 }
1501
1502
1503 int DuplicateFinder::AddAsciiSymbol(i::Vector<const char> key, int value) {
1504 return AddSymbol(i::Vector<const byte>::cast(key), true, value);
1505 }
1506
1507 int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) {
1508 return AddSymbol(i::Vector<const byte>::cast(key), false, value);
1509 }
1510
1511 int DuplicateFinder::AddSymbol(i::Vector<const byte> key,
1512 bool is_ascii,
1513 int value) {
1514 uint32_t hash = Hash(key, is_ascii);
1515 byte* encoding = BackupKey(key, is_ascii);
1516 i::HashMap::Entry* entry = map_->Lookup(encoding, hash, true);
1517 int old_value = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
1518 entry->value =
1519 reinterpret_cast<void*>(static_cast<intptr_t>(value | old_value));
1520 return old_value;
1521 }
1522
1523
1524 int DuplicateFinder::AddNumber(i::Vector<const char> key, int value) {
1525 // Quick check for already being in canonical form.
1526 if (IsNumberCanonical(key)) {
1527 return AddAsciiSymbol(key, value);
1528 }
1529
1530 // TODO(lrn): Use correct string->number->string conversions that
1531 // generate the same string as v8's ToString(ToNumber(literal)).
1532 // Current solution doesn't handle octal, and probably doesn't
1533 // generate the same string in edge cases.
1534 double double_value = 0.0;
1535 double_value = strtod(key.start(), NULL);
1536 int length;
1537 if (errno == ERANGE && double_value == HUGE_VAL) {
1538 // Overflow.
1539 // Negative overflow (-HUGE_VAL) cannit happen as number literals
1540 // don't have signs.
1541 // Underflow is handled by the default code, since it returns 0.
1542 length = 8; // strlen("Infinity");
1543 memcpy(number_buffer_, "Infinity", length);
1544 } else {
1545 length = snprintf(number_buffer_, kBufferSize, "%g", double_value);
1546 }
1547 return AddAsciiSymbol(i::Vector<const char>(number_buffer_, length), value);
1548 }
1549
1550
1551 bool DuplicateFinder::IsNumberCanonical(i::Vector<const char> number) {
1552 // Test for a safe approximation of number literals that are already
1553 // in canonical form: max 15 digits, no leading zeroes, except an
1554 // integer part that is a single zero, and no trailing zeros below
1555 // the decimal point.
1556 int pos = 0;
1557 int length = number.length();
1558 if (number.length() > 15) return false;
1559 if (number[pos] == '0') {
1560 pos++;
1561 } else {
1562 while (pos < length &&
1563 static_cast<unsigned>(number[pos] - '0') <= ('9' - '0')) pos++;
1564 }
1565 if (length == pos) return true;
1566 if (number[pos] != '.') return false;
1567 pos++;
1568 bool invalid_last_digit = true;
1569 while (pos < length) {
1570 byte digit = number[pos] - '0';
1571 if (digit > '9' - '0') return false;
1572 invalid_last_digit = (digit == 0);
1573 pos++;
1574 }
1575 return !invalid_last_digit;
1576 }
1577
1578
1579 uint32_t DuplicateFinder::Hash(i::Vector<const byte> key, bool is_ascii) {
1580 // Primitive hash function, almost identical to the one used
1581 // for strings (except that it's seeded by the length and ASCII-ness).
1582 int length = key.length();
1583 uint32_t hash = (length << 1) | (is_ascii ? 1 : 0) ;
1584 for (int i = 0; i < length; i++) {
1585 uint32_t c = key[i];
1586 hash = (hash + c) * 1025;
1587 hash ^= (hash >> 6);
1588 }
1589 return hash;
1590 }
1591
1592
1593 bool DuplicateFinder::Match(void* first, void* second) {
1594 // Decode lengths.
1595 // Length + ASCII-bit is encoded as base 128, most significant heptet first,
1596 // with a 8th bit being non-zero while there are more heptets.
1597 // The value encodes the number of bytes following, and whether the original
1598 // was ASCII.
1599 byte* s1 = reinterpret_cast<byte*>(first);
1600 byte* s2 = reinterpret_cast<byte*>(second);
1601 uint32_t length_ascii_field = 0;
1602 byte c1;
1603 do {
1604 c1 = *s1;
1605 if (c1 != *s2) return false;
1606 length_ascii_field = (length_ascii_field << 7) | (c1 & 0x7f);
1607 s1++;
1608 s2++;
1609 } while ((c1 & 0x80) != 0);
1610 int length = static_cast<int>(length_ascii_field >> 1);
1611 return memcmp(s1, s2, length) == 0;
1612 }
1613
1614
1615 byte* DuplicateFinder::BackupKey(i::Vector<const byte> bytes,
1616 bool is_ascii) {
Mads Ager (chromium) 2011/06/16 06:48:56 indentation
1617 uint32_t ascii_length = (bytes.length() << 1) | (is_ascii ? 1 : 0);
1618 backing_store_.StartSequence();
1619 // Emit ascii_length as base-128 encoded number, with the 7th bit set
1620 // on the byte of every heptet except the last, least significant, one.
1621 if (ascii_length >= (1 << 7)) {
1622 if (ascii_length >= (1 << 14)) {
1623 if (ascii_length >= (1 << 21)) {
1624 if (ascii_length >= (1 << 28)) {
1625 backing_store_.Add(static_cast<byte>((ascii_length >> 28) | 0x80));
1626 }
1627 backing_store_.Add(static_cast<byte>((ascii_length >> 21) | 0x80u));
1628 }
1629 backing_store_.Add(static_cast<byte>((ascii_length >> 14) | 0x80u));
1630 }
1631 backing_store_.Add(static_cast<byte>((ascii_length >> 7) | 0x80u));
1632 }
1633 backing_store_.Add(static_cast<byte>(ascii_length & 0x7f));
1634
1635 backing_store_.AddBlock(bytes);
1636 return backing_store_.EndSequence().start();
1637 }
1451 } } // v8::preparser 1638 } } // v8::preparser
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698