Chromium Code Reviews| 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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |