diff options
Diffstat (limited to 'JavaScriptCore/parser/JSParser.cpp')
-rw-r--r-- | JavaScriptCore/parser/JSParser.cpp | 349 |
1 files changed, 178 insertions, 171 deletions
diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp index 5825270..1fb1a9187 100644 --- a/JavaScriptCore/parser/JSParser.cpp +++ b/JavaScriptCore/parser/JSParser.cpp @@ -32,6 +32,7 @@ using namespace JSC; #include "JSGlobalData.h" #include "NodeInfo.h" #include "ASTBuilder.h" +#include <wtf/HashFunctions.h> #include <utility> using namespace std; @@ -58,12 +59,14 @@ namespace JSC { #define TreeProperty typename TreeBuilder::Property #define TreePropertyList typename TreeBuilder::PropertyList +COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens); + // This matches v8 static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024; class JSParser { public: - JSParser(Lexer*, JSGlobalData*); + JSParser(Lexer*, JSGlobalData*, SourceProvider*); bool parseProgram(); private: struct AllowInOverride { @@ -84,14 +87,14 @@ private: const JSToken& token() { return m_token; } void next() { - m_lastLine = token().m_info.last_line; - m_lastTokenEnd = token().m_info.last_column; + m_lastLine = token().m_info.line; + m_lastTokenEnd = token().m_info.endOffset; m_lexer->setLastLineNumber(m_lastLine); m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info); m_tokenCount++; } - bool consume(int expected) + bool consume(JSTokenType expected) { bool result = m_token.m_type == expected; failIfFalse(result); @@ -99,24 +102,24 @@ private: return result; } - bool match(int expected) + bool match(JSTokenType expected) { return m_token.m_type == expected; } int tokenStart() { - return token().m_info.first_column; + return token().m_info.startOffset; } int tokenLine() { - return token().m_info.first_line; + return token().m_info.line; } int tokenEnd() { - return token().m_info.last_column; + return token().m_info.endOffset; } template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&); @@ -150,20 +153,21 @@ private: template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&); template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&); template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&); template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&); - template <class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&); + template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&); template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&); template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&, bool& usesArguments); template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd); template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context); enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine); - int isBinaryOperator(int token); + ALWAYS_INLINE int isBinaryOperator(JSTokenType token); bool allowAutomaticSemicolon(); bool autoSemiColon() { - if (token().m_type == ';') { + if (token().m_type == SEMICOLON) { next(); return true; } @@ -194,15 +198,16 @@ private: int m_lastTokenEnd; int m_assignmentCount; int m_nonLHSCount; + bool m_syntaxAlreadyValidated; }; -int jsParse(JSGlobalData* globalData) +int jsParse(JSGlobalData* globalData, const SourceCode* source) { - JSParser parser(globalData->lexer, globalData); + JSParser parser(globalData->lexer, globalData, source->provider()); return parser.parseProgram(); } -JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData) +JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider) : m_lexer(lexer) , m_endAddress(0) , m_error(false) @@ -213,6 +218,7 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData) , m_lastTokenEnd(0) , m_assignmentCount(0) , m_nonLHSCount(0) + , m_syntaxAlreadyValidated(provider->isValid()) { m_endAddress = *(globalData->stackGuards); if (!m_endAddress) { @@ -228,7 +234,7 @@ bool JSParser::parseProgram() { ASTBuilder context(m_globalData, m_lexer); SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context); - if (!sourceElements || !consume(0)) + if (!sourceElements || !consume(EOFTOK)) return true; m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(), m_lastLine, context.numConstants()); @@ -237,7 +243,7 @@ bool JSParser::parseProgram() bool JSParser::allowAutomaticSemicolon() { - return match(CLOSEBRACE) || match(0) || m_lexer->prevTerminator(); + return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator(); } template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context) @@ -288,11 +294,11 @@ template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeB failIfFalse(statement); int endLine = tokenLine(); consumeOrFail(WHILE); - consumeOrFail('('); + consumeOrFail(OPENPAREN); TreeExpression expr = parseExpression(context); failIfFalse(expr); - consumeOrFail(')'); - if (match(';')) + consumeOrFail(CLOSEPAREN); + if (match(SEMICOLON)) next(); // Always performs automatic semicolon insertion. return context.createDoWhileStatement(statement, expr, startLine, endLine); } @@ -302,11 +308,11 @@ template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBui ASSERT(match(WHILE)); int startLine = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); TreeExpression expr = parseExpression(context); failIfFalse(expr); int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement statement = parseStatement(context); failIfFalse(statement); return context.createWhileStatement(expr, statement, startLine, endLine); @@ -325,7 +331,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr const Identifier* name = token().m_data.ident; lastIdent = name; next(); - bool hasInitializer = match('='); + bool hasInitializer = match(EQUAL); context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); if (hasInitializer) { int varDivot = tokenStart() + 1; @@ -343,7 +349,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr else varDecls = context.combineCommaNodes(varDecls, node); } - } while (match(',')); + } while (match(COMMA)); return varDecls; } @@ -356,7 +362,7 @@ template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationLi matchOrFail(IDENT); const Identifier* name = token().m_data.ident; next(); - bool hasInitializer = match('='); + bool hasInitializer = match(EQUAL); context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); TreeExpression initializer = 0; if (hasInitializer) { @@ -366,7 +372,7 @@ template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationLi tail = context.appendConstDecl(tail, name, initializer); if (!constDecls) constDecls = tail; - } while (match(',')); + } while (match(COMMA)); return constDecls; } @@ -375,7 +381,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild ASSERT(match(FOR)); int startLine = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); int nonLHSCount = m_nonLHSCount; int declarations = 0; int declsStart = 0; @@ -400,7 +406,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild fail(); // Remainder of a standard for loop is handled identically - if (declarations > 1 || match(';')) + if (declarations > 1 || match(SEMICOLON)) goto standardForLoop; // Handle for-in with var declaration @@ -413,7 +419,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild int exprEnd = lastTokenEnd(); int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement statement = parseStatement(context); failIfFalse(statement); @@ -421,7 +427,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine); } - if (!match(';')) { + if (!match(SEMICOLON)) { m_allowsIn = false; declsStart = tokenStart(); decls = parseExpression(context); @@ -430,25 +436,25 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild failIfFalse(decls); } - if (match(';')) { + if (match(SEMICOLON)) { standardForLoop: // Standard for loop next(); TreeExpression condition = 0; - if (!match(';')) { + if (!match(SEMICOLON)) { condition = parseExpression(context); failIfFalse(condition); } - consumeOrFail(';'); + consumeOrFail(SEMICOLON); TreeExpression increment = 0; - if (!match(')')) { + if (!match(CLOSEPAREN)) { increment = parseExpression(context); failIfFalse(increment); } int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement statement = parseStatement(context); failIfFalse(statement); return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine); @@ -461,7 +467,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild failIfFalse(expr); int exprEnd = lastTokenEnd(); int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement statement = parseStatement(context); failIfFalse(statement); @@ -519,14 +525,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBu // We do the auto semicolon check before attempting to parse an expression // as we need to ensure the a line break after the return correctly terminates // the statement - if (match(';')) + if (match(SEMICOLON)) endLine = tokenLine(); if (autoSemiColon()) return context.createReturnStatement(0, start, end, startLine, endLine); TreeExpression expr = parseExpression(context); failIfFalse(expr); end = lastTokenEnd(); - if (match(';')) + if (match(SEMICOLON)) endLine = tokenLine(); failIfFalse(autoSemiColon()); return context.createReturnStatement(expr, start, end, startLine, endLine); @@ -553,14 +559,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuil ASSERT(match(WITH)); int startLine = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); int start = tokenStart(); TreeExpression expr = parseExpression(context); failIfFalse(expr); int end = lastTokenEnd(); int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement statement = parseStatement(context); failIfFalse(statement); @@ -573,11 +579,11 @@ template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBu ASSERT(match(SWITCH)); int startLine = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); TreeExpression expr = parseExpression(context); failIfFalse(expr); int endLine = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); consumeOrFail(OPENBRACE); TreeClauseList firstClauses = parseSwitchClauses(context); @@ -601,7 +607,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui next(); TreeExpression condition = parseExpression(context); failIfFalse(condition); - consumeOrFail(':'); + consumeOrFail(COLON); TreeSourceElements statements = parseSourceElements(context); failIfFalse(statements); TreeClause clause = context.createClause(condition, statements); @@ -612,7 +618,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui next(); TreeExpression condition = parseExpression(context); failIfFalse(condition); - consumeOrFail(':'); + consumeOrFail(COLON); TreeSourceElements statements = parseSourceElements(context); failIfFalse(statements); clause = context.createClause(condition, statements); @@ -626,7 +632,7 @@ template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeB if (!match(DEFAULT)) return 0; next(); - consumeOrFail(':'); + consumeOrFail(COLON); TreeSourceElements statements = parseSourceElements(context); failIfFalse(statements); return context.createClause(0, statements); @@ -650,11 +656,11 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild if (match(CATCH)) { next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); matchOrFail(IDENT); ident = token().m_data.ident; next(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); int initialEvalCount = context.evalCount(); catchBlock = parseBlockStatement(context); @@ -678,7 +684,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(Tree int startLine = tokenLine(); int endLine = startLine; next(); - if (match(';')) + if (match(SEMICOLON)) startLine = tokenLine(); failIfFalse(autoSemiColon()); return context.createDebugger(startLine, endLine); @@ -712,7 +718,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& return parseConstDeclaration(context); case FUNCTION: return parseFunctionDeclaration(context); - case ';': + case SEMICOLON: next(); return context.createEmptyStatement(); case IF: @@ -739,7 +745,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& return parseTryStatement(context); case DEBUGGER: return parseDebuggerStatement(context); - case 0: + case EOFTOK: case CASE: case CLOSEBRACE: case DEFAULT: @@ -759,7 +765,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame TreeFormalParameterList list = context.createFormalParameterList(*token().m_data.ident); TreeFormalParameterList tail = list; next(); - while (match(',')) { + while (match(COMMA)) { next(); matchOrFail(IDENT); const Identifier* ident = token().m_data.ident; @@ -786,13 +792,13 @@ template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool J next(); } else if (requirements == FunctionNeedsName) return false; - consumeOrFail('('); + consumeOrFail(OPENPAREN); bool usesArguments = false; - if (!match(')')) { + if (!match(CLOSEPAREN)) { parameters = parseFormalParameters(context, usesArguments); failIfFalse(parameters); } - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); openBracePos = token().m_data.intValue; @@ -843,7 +849,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelState return context.createExprStatement(expression, startLine, m_lastLine); failIfFalse(currentToken + 1 == m_tokenCount); int end = tokenEnd(); - consumeOrFail(':'); + consumeOrFail(COLON); TreeStatement statement = parseStatement(context); failIfFalse(statement); return context.createLabelStatement(ident, statement, start, end); @@ -865,12 +871,12 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde int start = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); TreeExpression condition = parseExpression(context); failIfFalse(condition); int end = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement trueBlock = parseStatement(context); failIfFalse(trueBlock); @@ -894,12 +900,12 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde int innerStart = tokenLine(); next(); - consumeOrFail('('); + consumeOrFail(OPENPAREN); TreeExpression innerCondition = parseExpression(context); failIfFalse(innerCondition); int innerEnd = tokenLine(); - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); TreeStatement innerTrueBlock = parseStatement(context); failIfFalse(innerTrueBlock); @@ -938,14 +944,14 @@ template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilde failIfStackOverflow(); TreeExpression node = parseAssignmentExpression(context); failIfFalse(node); - if (!match(',')) + if (!match(COMMA)) return node; next(); m_nonLHSCount++; TreeExpression right = parseAssignmentExpression(context); failIfFalse(right); typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right); - while (match(',')) { + while (match(COMMA)) { next(); right = parseAssignmentExpression(context); failIfFalse(right); @@ -971,7 +977,7 @@ template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpressi bool hadAssignment = false; while (true) { switch (token().m_type) { - case '=': op = OpEqual; break; + case EQUAL: op = OpEqual; break; case PLUSEQUAL: op = OpPlusEq; break; case MINUSEQUAL: op = OpMinusEq; break; case MULTEQUAL: op = OpMultEq; break; @@ -1013,92 +1019,28 @@ template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression { TreeExpression cond = parseBinaryExpression(context); failIfFalse(cond); - if (!match('?')) + if (!match(QUESTION)) return cond; m_nonLHSCount++; next(); TreeExpression lhs = parseAssignmentExpression(context); - consumeOrFail(':'); + consumeOrFail(COLON); TreeExpression rhs = parseAssignmentExpression(context); failIfFalse(rhs); return context.createConditionalExpr(cond, lhs, rhs); } -static bool isUnaryOp(int token) +ALWAYS_INLINE static bool isUnaryOp(JSTokenType token) { - switch (token) { - case '!': - case '~': - case '-': - case '+': - case PLUSPLUS: - case AUTOPLUSPLUS: - case MINUSMINUS: - case AUTOMINUSMINUS: - case TYPEOF: - case VOIDTOKEN: - case DELETETOKEN: - return true; - default: - return false; - } + return token & UnaryOpTokenFlag; } -int JSParser::isBinaryOperator(int token) +int JSParser::isBinaryOperator(JSTokenType token) { - switch (token) { - case OR: - return 1; - - case AND: - return 2; - - case '|': - return 3; - - case '^': - return 4; - - case '&': - return 5; - - case EQEQ: - case NE: - case STREQ: - case STRNEQ: - return 6; - - case '<': - case '>': - case LE: - case GE: - case INSTANCEOF: - return 7; - - case INTOKEN: - // same precedence as the above but needs a validity check - if (m_allowsIn) - return 7; - return 0; - - case LSHIFT: - case RSHIFT: - case URSHIFT: - return 8; - - case '+': - case '-': - return 9; - - case '*': - case '/': - case '%': - return 10; - - default: - return 0; - } + if (m_allowsIn) + return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift); + return token & BinaryOpTokenPrecedenceMask; } template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context) @@ -1145,7 +1087,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree } -template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context) +template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context) { bool wasIdent = false; switch (token().m_type) { @@ -1154,11 +1096,11 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c case STRING: { const Identifier* ident = token().m_data.ident; next(); - if (match(':')) { + if (match(COLON)) { next(); TreeExpression node = parseAssignmentExpression(context); failIfFalse(node); - return context.createProperty(ident, node, PropertyNode::Constant); + return context.template createProperty<complete>(ident, node, PropertyNode::Constant); } failIfFalse(wasIdent); matchOrFail(IDENT); @@ -1168,23 +1110,32 @@ template <class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& c int openBracePos = 0; int closeBracePos = 0; int bodyStartLine = 0; + PropertyNode::Type type; + if (*ident == m_globalData->propertyNames->get) + type = PropertyNode::Getter; + else if (*ident == m_globalData->propertyNames->set) + type = PropertyNode::Setter; + else + fail(); failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)); - return context.createGetterOrSetterProperty(ident, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine); + return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine); } case NUMBER: { double propertyName = token().m_data.doubleValue; next(); - consumeOrFail(':'); + consumeOrFail(COLON); TreeExpression node = parseAssignmentExpression(context); failIfFalse(node); - return context.createProperty(propertyName, node, PropertyNode::Constant); + return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant); } + default: + fail(); } - fail(); } template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context) { + int startOffset = token().m_data.intValue; consumeOrFail(OPENBRACE); if (match(CLOSEBRACE)) { @@ -1192,20 +1143,27 @@ template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBui return context.createObjectLiteral(); } - TreeProperty property = parseProperty(context); + TreeProperty property = parseProperty<false>(context); failIfFalse(property); - + if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { + m_lexer->setOffset(startOffset); + next(); + return parseStrictObjectLiteral(context); + } TreePropertyList propertyList = context.createPropertyList(property); TreePropertyList tail = propertyList; - - while (match(',')) { + while (match(COMMA)) { next(); // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 if (match(CLOSEBRACE)) break; - property = parseProperty(context); + property = parseProperty<false>(context); failIfFalse(property); - + if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { + m_lexer->setOffset(startOffset); + next(); + return parseStrictObjectLiteral(context); + } tail = context.createPropertyList(property, tail); } @@ -1214,16 +1172,62 @@ template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBui return context.createObjectLiteral(propertyList); } +template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context) +{ + consumeOrFail(OPENBRACE); + + if (match(CLOSEBRACE)) { + next(); + return context.createObjectLiteral(); + } + + TreeProperty property = parseProperty<true>(context); + failIfFalse(property); + + typedef HashMap<RefPtr<UString::Rep>, unsigned, IdentifierRepHash> ObjectValidationMap; + ObjectValidationMap objectValidator; + // Add the first property + if (!m_syntaxAlreadyValidated) + objectValidator.add(context.getName(property).ustring().rep(), context.getType(property)); + + TreePropertyList propertyList = context.createPropertyList(property); + TreePropertyList tail = propertyList; + while (match(COMMA)) { + next(); + // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 + if (match(CLOSEBRACE)) + break; + property = parseProperty<true>(context); + failIfFalse(property); + if (!m_syntaxAlreadyValidated) { + std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).ustring().rep(), context.getType(property)); + if (!propertyEntryIter.second) { + if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) { + // Can't have multiple getters or setters with the same name, nor can we define + // a property as both an accessor and a constant value + failIfTrue(context.getType(property) & propertyEntryIter.first->second); + failIfTrue((context.getType(property) | propertyEntryIter.first->second) & PropertyNode::Constant); + } + } + } + tail = context.createPropertyList(property, tail); + } + + consumeOrFail(CLOSEBRACE); + + return context.createObjectLiteral(propertyList); +} + template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context) { - consumeOrFail('['); + consumeOrFail(OPENBRACKET); int elisions = 0; - while (match(',')) { + while (match(COMMA)) { next(); elisions++; } - if (match(']')) { + if (match(CLOSEBRACKET)) { next(); return context.createArray(elisions); } @@ -1233,16 +1237,16 @@ template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuil typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem); typename TreeBuilder::ElementList tail = elementList; elisions = 0; - while (match(',')) { + while (match(COMMA)) { next(); elisions = 0; - while (match(',')) { + while (match(COMMA)) { next(); elisions++; } - if (match(']')) { + if (match(CLOSEBRACKET)) { next(); return context.createArray(elisions, elementList); } @@ -1251,7 +1255,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuil tail = context.createElementList(tail, elisions, elem); } - consumeOrFail(']'); + consumeOrFail(CLOSEBRACKET); return context.createArray(elementList); } @@ -1261,14 +1265,14 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre switch (token().m_type) { case OPENBRACE: return parseObjectLiteral(context); - case '[': + case OPENBRACKET: return parseArrayLiteral(context); - case '(': { + case OPENPAREN: { next(); int oldNonLHSCount = m_nonLHSCount; TreeExpression result = parseExpression(context); m_nonLHSCount = oldNonLHSCount; - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); return result; } @@ -1305,7 +1309,7 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre return context.createBoolean(false); } case DIVEQUAL: - case '/': { + case DIVIDE: { /* regexp */ const Identifier* pattern; const Identifier* flags; @@ -1318,14 +1322,15 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre next(); return context.createRegex(*pattern, *flags, start); } + default: + fail(); } - fail(); } template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context) { - consumeOrFail('('); - if (match(')')) { + consumeOrFail(OPENPAREN); + if (match(CLOSEPAREN)) { next(); return context.createArguments(); } @@ -1334,13 +1339,13 @@ template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& TreeArgumentsList argList = context.createArgumentsList(firstArg); TreeArgumentsList tail = argList; - while (match(',')) { + while (match(COMMA)) { next(); TreeExpression arg = parseAssignmentExpression(context); failIfFalse(arg); tail = context.createArgumentsList(tail, arg); } - consumeOrFail(')'); + consumeOrFail(CLOSEPAREN); return context.createArguments(argList); } @@ -1370,7 +1375,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree failIfFalse(base); while (true) { switch (token().m_type) { - case '[': { + case OPENBRACKET: { int expressionEnd = lastTokenEnd(); next(); int nonLHSCount = m_nonLHSCount; @@ -1378,15 +1383,15 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree TreeExpression property = parseExpression(context); failIfFalse(property); base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd()); - if (!consume(']')) + if (!consume(CLOSEBRACKET)) fail(); m_nonLHSCount = nonLHSCount; break; } - case '(': { + case OPENPAREN: { if (newCount) { newCount--; - if (match('(')) { + if (match(OPENPAREN)) { int exprEnd = lastTokenEnd(); TreeArguments arguments = parseArguments(context); failIfFalse(arguments); @@ -1403,7 +1408,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree } break; } - case '.': { + case DOT: { int expressionEnd = lastTokenEnd(); next(); matchOrFail(IDENT); @@ -1446,6 +1451,8 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB m_assignmentCount++; next(); break; + default: + break; } int end = lastTokenEnd(); @@ -1455,16 +1462,16 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB while (tokenStackDepth) { switch (context.unaryTokenStackLastType(tokenStackDepth)) { - case '!': + case EXCLAMATION: expr = context.createLogicalNot(expr); break; - case '~': + case TILDE: expr = context.makeBitwiseNotNode(expr); break; - case '-': + case MINUS: expr = context.makeNegateNode(expr); break; - case '+': + case PLUS: expr = context.createUnaryPlus(expr); break; case PLUSPLUS: |