Changeset 89257 in webkit for trunk/Source/JavaScriptCore/parser/JSParser.cpp
- Timestamp:
- Jun 20, 2011, 10:49:34 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/parser/JSParser.cpp
r88719 r89257 44 44 45 45 namespace JSC { 46 #define fail() do { m_error = true; return 0; } while (0) 46 #define fail() do { if (!m_error) updateErrorMessage(); return 0; } while (0) 47 #define failWithToken(tok) do { if (!m_error) updateErrorMessage(tok); return 0; } while (0) 48 #define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0) 49 #define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0) 47 50 #define failIfFalse(cond) do { if (!(cond)) fail(); } while (0) 51 #define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0) 52 #define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0) 48 53 #define failIfTrue(cond) do { if ((cond)) fail(); } while (0) 54 #define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0) 55 #define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0) 49 56 #define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0) 57 #define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0) 58 #define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0) 50 59 #define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0) 51 #define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0) 52 #define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) fail(); } while (0) 53 #define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0) 54 #define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0) 60 #define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0) 61 #define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0) 62 #define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0) 63 #define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0) 64 #define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0) 65 #define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0) 55 66 56 67 // Macros to make the more common TreeBuilder types a little less verbose … … 72 83 class JSParser { 73 84 public: 74 JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);75 const char*parseProgram();85 JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, const SourceCode*); 86 UString parseProgram(); 76 87 private: 77 88 struct AllowInOverride { … … 124 135 { 125 136 bool result = m_token.m_type == expected; 126 failIfFalse(result);127 next(flags);137 if (result) 138 next(flags); 128 139 return result; 129 140 } 130 141 142 ALWAYS_INLINE UString getToken() { 143 SourceProvider* sourceProvider = m_source->provider(); 144 return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl()); 145 } 146 131 147 ALWAYS_INLINE bool match(JSTokenType expected) 132 148 { … … 147 163 { 148 164 return m_token.m_info.endOffset; 165 } 166 167 const char* getTokenName(JSTokenType tok) 168 { 169 switch (tok) { 170 case NULLTOKEN: 171 return "null"; 172 case TRUETOKEN: 173 return "true"; 174 case FALSETOKEN: 175 return "false"; 176 case BREAK: 177 return "break"; 178 case CASE: 179 return "case"; 180 case DEFAULT: 181 return "defualt"; 182 case FOR: 183 return "for"; 184 case NEW: 185 return "new"; 186 case VAR: 187 return "var"; 188 case CONSTTOKEN: 189 return "const"; 190 case CONTINUE: 191 return "continue"; 192 case FUNCTION: 193 return "function"; 194 case RETURN: 195 return 0; 196 case IF: 197 return "if"; 198 case THISTOKEN: 199 return "this"; 200 case DO: 201 return "do"; 202 case WHILE: 203 return "while"; 204 case SWITCH: 205 return "switch"; 206 case WITH: 207 return "with"; 208 case RESERVED_IF_STRICT: 209 case RESERVED: 210 return 0; 211 case THROW: 212 return "throw"; 213 case TRY: 214 return "try"; 215 case CATCH: 216 return "catch"; 217 case FINALLY: 218 return "finally"; 219 case DEBUGGER: 220 return "debugger"; 221 case ELSE: 222 return "else"; 223 case OPENBRACE: 224 return "{"; 225 case CLOSEBRACE: 226 return "}"; 227 case OPENPAREN: 228 return "("; 229 case CLOSEPAREN: 230 return ")"; 231 case OPENBRACKET: 232 return "["; 233 case CLOSEBRACKET: 234 return "]"; 235 case COMMA: 236 return ","; 237 case QUESTION: 238 return "?"; 239 case NUMBER: 240 return 0; 241 case IDENT: 242 return 0; 243 case STRING: 244 return 0; 245 case SEMICOLON: 246 return ";"; 247 case COLON: 248 return ":"; 249 case DOT: 250 return "."; 251 case ERRORTOK: 252 return 0; 253 case EOFTOK: 254 return 0; 255 case EQUAL: 256 return "="; 257 case PLUSEQUAL: 258 return "+="; 259 case MINUSEQUAL: 260 return "-="; 261 case MULTEQUAL: 262 return "*="; 263 case DIVEQUAL: 264 return "/="; 265 case LSHIFTEQUAL: 266 return "<<="; 267 case RSHIFTEQUAL: 268 return ">>="; 269 case URSHIFTEQUAL: 270 return ">>>="; 271 case ANDEQUAL: 272 return "&="; 273 case MODEQUAL: 274 return "%="; 275 case XOREQUAL: 276 return "^="; 277 case OREQUAL: 278 return "|="; 279 case AUTOPLUSPLUS: 280 case PLUSPLUS: 281 return "++"; 282 case AUTOMINUSMINUS: 283 case MINUSMINUS: 284 return "--"; 285 case EXCLAMATION: 286 return "!"; 287 case TILDE: 288 return "~"; 289 case TYPEOF: 290 return "typeof"; 291 case VOIDTOKEN: 292 return "void"; 293 case DELETETOKEN: 294 return "delete"; 295 case OR: 296 return "||"; 297 case AND: 298 return "&&"; 299 case BITOR: 300 return "|"; 301 case BITXOR: 302 return "^"; 303 case BITAND: 304 return "&"; 305 case EQEQ: 306 return "=="; 307 case NE: 308 return "!="; 309 case STREQ: 310 return "==="; 311 case STRNEQ: 312 return "!=="; 313 case LT: 314 return "<"; 315 case GT: 316 return ">"; 317 case LE: 318 return "<="; 319 case GE: 320 return ">="; 321 case INSTANCEOF: 322 return "instanceof"; 323 case INTOKEN: 324 return "in"; 325 case LSHIFT: 326 return "<<"; 327 case RSHIFT: 328 return ">>"; 329 case URSHIFT: 330 return ">>>"; 331 case PLUS: 332 return "+"; 333 case MINUS: 334 return "-"; 335 case TIMES: 336 return "*"; 337 case DIVIDE: 338 return "/"; 339 case MOD: 340 return "%"; 341 case LastUntaggedToken: 342 break; 343 } 344 ASSERT_NOT_REACHED(); 345 return "internal error"; 346 } 347 348 ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken) 349 { 350 String errorMessage; 351 switch (expectedToken) { 352 case RESERVED: 353 errorMessage = "Use of reserved word '"; 354 errorMessage += getToken().impl(); 355 errorMessage += "'"; 356 m_errorMessage = errorMessage.impl(); 357 return; 358 case NUMBER: 359 errorMessage = "Unexpected number '"; 360 errorMessage += getToken().impl(); 361 errorMessage += "'"; 362 m_errorMessage = errorMessage.impl(); 363 return; 364 case IDENT: 365 errorMessage = "Expected an identifier but found '"; 366 errorMessage += getToken().impl(); 367 errorMessage += "' instead"; 368 m_errorMessage = errorMessage.impl(); 369 return; 370 case STRING: 371 errorMessage = "Unexpected string "; 372 errorMessage += getToken().impl(); 373 m_errorMessage = errorMessage.impl(); 374 return; 375 case ERRORTOK: 376 errorMessage = "Unrecognized token '"; 377 errorMessage += getToken().impl(); 378 errorMessage += "'"; 379 m_errorMessage = errorMessage.impl(); 380 return; 381 case EOFTOK: 382 m_errorMessage = "Unexpected EOF"; 383 return; 384 case RETURN: 385 m_errorMessage = "Return statements are only valid inside functions"; 386 return; 387 default: 388 ASSERT_NOT_REACHED(); 389 m_errorMessage = "internal error"; 390 return; 391 } 392 } 393 394 ALWAYS_INLINE void updateErrorMessage() 395 { 396 m_error = true; 397 const char* name = getTokenName(m_token.m_type); 398 if (!name) 399 updateErrorMessageSpecialCase(m_token.m_type); 400 else 401 m_errorMessage = UString(String::format("Unexpected token '%s'", name).impl()); 402 } 403 404 ALWAYS_INLINE void updateErrorMessage(JSTokenType expectedToken) 405 { 406 m_error = true; 407 const char* name = getTokenName(expectedToken); 408 if (!name) 409 updateErrorMessageSpecialCase(expectedToken); 410 else 411 m_errorMessage = UString(String::format("Expected token '%s'", name).impl()); 412 } 413 414 ALWAYS_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg) 415 { 416 m_error = true; 417 String prefix(beforeMsg); 418 String postfix(afterMsg); 419 prefix += " '"; 420 prefix += name.impl(); 421 prefix += "' "; 422 prefix += postfix; 423 m_errorMessage = prefix.impl(); 424 } 425 426 ALWAYS_INLINE void updateErrorMessage(const char* msg) 427 { 428 m_error = true; 429 m_errorMessage = UString(msg); 149 430 } 150 431 … … 258 539 StackBounds m_stack; 259 540 bool m_error; 260 const char*m_errorMessage;541 UString m_errorMessage; 261 542 JSGlobalData* m_globalData; 262 543 JSToken m_token; … … 616 897 617 898 SourceProviderCache* m_functionCache; 899 const SourceCode* m_source; 618 900 }; 619 901 620 const char*jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)621 { 622 JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source ->provider());902 UString jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source) 903 { 904 JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source); 623 905 return parser.parseProgram(); 624 906 } 625 907 626 JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)908 JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, const SourceCode* source) 627 909 : m_lexer(lexer) 628 910 , m_stack(globalData->stack()) … … 635 917 , m_assignmentCount(0) 636 918 , m_nonLHSCount(0) 637 , m_syntaxAlreadyValidated( provider->isValid())919 , m_syntaxAlreadyValidated(source->provider()->isValid()) 638 920 , m_statementDepth(0) 639 921 , m_nonTrivialExpressionCount(0) 640 922 , m_lastIdentifier(0) 641 923 , m_functionCache(m_lexer->sourceProvider()->cache()) 924 , m_source(source) 642 925 { 643 926 ScopeRef scope = pushScope(); … … 654 937 } 655 938 656 const char*JSParser::parseProgram()939 UString JSParser::parseProgram() 657 940 { 658 941 unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0; … … 678 961 m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features, 679 962 m_lastLine, context.numConstants(), capturedVariables); 680 return 0;963 return UString(); 681 964 } 682 965 … … 801 1084 next(); 802 1085 bool hasInitializer = match(EQUAL); 803 failIfFalseIfStrict (declareVariable(name));1086 failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode."); 804 1087 context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); 805 1088 if (hasInitializer) { … … 885 1168 // Handle for-in with var declaration 886 1169 int inLocation = tokenStart(); 887 if (!consume(INTOKEN)) 888 fail(); 1170 consumeOrFail(INTOKEN); 889 1171 890 1172 TreeExpression expr = parseExpression(context); … … 967 1249 968 1250 if (autoSemiColon()) { 969 failIfFalse (breakIsValid());1251 failIfFalseWithMessage(breakIsValid(), "'break' is only valid inside a switch or loop statement"); 970 1252 return context.createBreakStatement(startCol, endCol, startLine, endLine); 971 1253 } 972 1254 matchOrFail(IDENT); 973 1255 const Identifier* ident = m_token.m_data.ident; 974 failIfFalse (getLabel(ident));1256 failIfFalseWithNameAndMessage(getLabel(ident), "Label", ident->impl(), "is not defined"); 975 1257 endCol = tokenEnd(); 976 1258 endLine = tokenLine(); … … 990 1272 991 1273 if (autoSemiColon()) { 992 failIfFalse (continueIsValid());1274 failIfFalseWithMessage(continueIsValid(), "'continue' is only valid inside a loop statement"); 993 1275 return context.createContinueStatement(startCol, endCol, startLine, endLine); 994 1276 } … … 996 1278 const Identifier* ident = m_token.m_data.ident; 997 1279 ScopeLabelInfo* label = getLabel(ident); 998 failIfFalse (label);999 failIfFalse (label->m_isLoop);1280 failIfFalseWithNameAndMessage(label, "Label", ident->impl(), "is not defined"); 1281 failIfFalseWithMessage(label->m_isLoop, "'continue' is only valid inside a loop statement"); 1000 1282 endCol = tokenEnd(); 1001 1283 endLine = tokenLine(); … … 1051 1333 { 1052 1334 ASSERT(match(WITH)); 1053 failIfTrue (strictMode());1335 failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode"); 1054 1336 currentScope()->setNeedsFullActivation(); 1055 1337 int startLine = tokenLine(); … … 1159 1441 next(); 1160 1442 AutoPopScopeRef catchScope(this, pushScope()); 1161 failIfFalseIfStrict (catchScope->declareVariable(ident));1443 failIfFalseIfStrictWithNameAndMessage(catchScope->declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode"); 1162 1444 catchScope->preventNewDecls(); 1163 1445 consumeOrFail(CLOSEPAREN); … … 1165 1447 int initialEvalCount = context.evalCount(); 1166 1448 catchBlock = parseBlockStatement(context); 1167 failIfFalse (catchBlock);1449 failIfFalseWithMessage(catchBlock, "'try' must have a catch or finally block"); 1168 1450 catchHasEval = initialEvalCount != context.evalCount(); 1169 1451 failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo)); … … 1223 1505 return parseConstDeclaration(context); 1224 1506 case FUNCTION: 1225 failIfFalseIfStrict (m_statementDepth == 1);1507 failIfFalseIfStrictWithMessage(m_statementDepth == 1, "Functions cannot be declared in a nested block in strict mode"); 1226 1508 return parseFunctionDeclaration(context); 1227 1509 case SEMICOLON: … … 1274 1556 { 1275 1557 matchOrFail(IDENT); 1276 failIfFalseIfStrict (declareParameter(m_token.m_data.ident));1558 failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode"); 1277 1559 TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident); 1278 1560 TreeFormalParameterList tail = list; … … 1282 1564 matchOrFail(IDENT); 1283 1565 const Identifier* ident = m_token.m_data.ident; 1284 failIfFalseIfStrict (declareParameter(ident));1566 failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode"); 1285 1567 next(); 1286 1568 tail = context.createFormalParameterList(tail, *ident); … … 1306 1588 if (match(IDENT)) { 1307 1589 name = m_token.m_data.ident; 1308 failIfTrue (*name == m_globalData->propertyNames->underscoreProto);1590 failIfTrueWithMessage(*name == m_globalData->propertyNames->underscoreProto, "Cannot name a function __proto__"); 1309 1591 next(); 1310 1592 if (!nameIsInContainingScope) … … 1344 1626 failIfFalse(body); 1345 1627 if (functionScope->strictMode() && name) { 1346 failIfTrue (m_globalData->propertyNames->arguments == *name);1347 failIfTrue (m_globalData->propertyNames->eval == *name);1628 failIfTrueWithNameAndMessage(m_globalData->propertyNames->arguments == *name, "Function name", name->impl(), "is not valid in strict mode"); 1629 failIfTrueWithNameAndMessage(m_globalData->propertyNames->eval == *name, "Function name", name->impl(), "is not valid in strict mode"); 1348 1630 } 1349 1631 closeBracePos = m_token.m_data.intValue; … … 1609 1891 next(TreeBuilder::DontBuildStrings); 1610 1892 if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) { 1611 failIfTrueIfStrict (m_globalData->propertyNames->eval == *m_lastIdentifier);1612 failIfTrueIfStrict (m_globalData->propertyNames->arguments == *m_lastIdentifier);1893 failIfTrueIfStrictWithMessage(m_globalData->propertyNames->eval == *m_lastIdentifier, "'eval' cannot be modified in strict mode"); 1894 failIfTrueIfStrictWithMessage(m_globalData->propertyNames->arguments == *m_lastIdentifier, "'arguments' cannot be modified in strict mode"); 1613 1895 declareWrite(m_lastIdentifier); 1614 1896 m_lastIdentifier = 0; … … 1949 2231 TreeExpression re = context.createRegExp(*pattern, *flags, start); 1950 2232 if (!re) { 1951 m_errorMessage= Yarr::checkSyntax(pattern->ustring());1952 ASSERT( m_errorMessage);1953 fail ();2233 const char* yarrErrorMsg = Yarr::checkSyntax(pattern->ustring()); 2234 ASSERT(!m_errorMessage.isNull()); 2235 failWithMessage(yarrErrorMsg); 1954 2236 } 1955 2237 return re; … … 2018 2300 failIfFalse(property); 2019 2301 base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd()); 2020 if (!consume(CLOSEBRACKET)) 2021 fail(); 2302 consumeOrFail(CLOSEBRACKET); 2022 2303 m_nonLHSCount = nonLHSCount; 2023 2304 break; … … 2104 2385 } 2105 2386 } 2106 failIfTrueIfStrict (isEvalOrArguments && modifiesExpr);2387 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments && modifiesExpr, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); 2107 2388 switch (m_token.m_type) { 2108 2389 case PLUSPLUS: … … 2111 2392 expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd()); 2112 2393 m_assignmentCount++; 2113 failIfTrueIfStrict (isEvalOrArguments);2394 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); 2114 2395 failIfTrueIfStrict(requiresLExpr); 2115 2396 next(); … … 2120 2401 expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd()); 2121 2402 m_assignmentCount++; 2122 failIfTrueIfStrict (isEvalOrArguments);2403 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); 2123 2404 failIfTrueIfStrict(requiresLExpr); 2124 2405 next(); … … 2164 2445 break; 2165 2446 case DELETETOKEN: 2166 failIfTrueIfStrict (context.isResolve(expr));2447 failIfTrueIfStrictWithNameAndMessage(context.isResolve(expr), "Cannot delete unqualified property", m_lastIdentifier->impl(), "in strict mode"); 2167 2448 expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end); 2168 2449 break;
Note:
See TracChangeset
for help on using the changeset viewer.