diff options
author | Leon Clarke <leonclarke@google.com> | 2010-07-15 12:03:35 +0100 |
---|---|---|
committer | Leon Clarke <leonclarke@google.com> | 2010-07-20 16:57:23 +0100 |
commit | e458d70a0d18538346f41b503114c9ebe6b2ce12 (patch) | |
tree | 86f1637deca2c524432a822e5fcedd4bef221091 /JavaScriptCore/parser | |
parent | f43eabc081f7ce6af24b9df4953498a3cd6ca24d (diff) | |
download | external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.zip external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.tar.gz external_webkit-e458d70a0d18538346f41b503114c9ebe6b2ce12.tar.bz2 |
Merge WebKit at r63173 : Initial merge by git.
Change-Id: Ife5af0c7c6261fbbc8ae6bc08c390efa9ef10b44
Diffstat (limited to 'JavaScriptCore/parser')
-rw-r--r-- | JavaScriptCore/parser/ASTBuilder.h | 37 | ||||
-rw-r--r-- | JavaScriptCore/parser/JSParser.cpp | 349 | ||||
-rw-r--r-- | JavaScriptCore/parser/JSParser.h | 179 | ||||
-rw-r--r-- | JavaScriptCore/parser/Lexer.cpp | 344 | ||||
-rw-r--r-- | JavaScriptCore/parser/Lexer.h | 21 | ||||
-rw-r--r-- | JavaScriptCore/parser/Nodes.cpp | 2 | ||||
-rw-r--r-- | JavaScriptCore/parser/Nodes.h | 3 | ||||
-rw-r--r-- | JavaScriptCore/parser/Parser.cpp | 2 | ||||
-rw-r--r-- | JavaScriptCore/parser/ParserArena.cpp | 5 | ||||
-rw-r--r-- | JavaScriptCore/parser/SourceProvider.h | 5 | ||||
-rw-r--r-- | JavaScriptCore/parser/SyntaxChecker.h | 51 |
11 files changed, 544 insertions, 454 deletions
diff --git a/JavaScriptCore/parser/ASTBuilder.h b/JavaScriptCore/parser/ASTBuilder.h index 7dcdff0..3b7ffb5 100644 --- a/JavaScriptCore/parser/ASTBuilder.h +++ b/JavaScriptCore/parser/ASTBuilder.h @@ -249,16 +249,9 @@ public: return FunctionBodyNode::create(m_globalData); } - PropertyNode* createGetterOrSetterProperty(const Identifier* getOrSet, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) + template <bool> PropertyNode* createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine) { ASSERT(name); - PropertyNode::Type type; - if (*getOrSet == "get") - type = PropertyNode::Getter; - else if (*getOrSet == "set") - type = PropertyNode::Setter; - else - return 0; body->setLoc(bodyStartLine, bodyEndLine); return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(m_globalData, m_globalData->propertyNames->nullIdentifier, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), params), type); } @@ -269,8 +262,8 @@ public: ArgumentListNode* createArgumentsList(ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, arg); } ArgumentListNode* createArgumentsList(ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, args, arg); } - PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); } - PropertyNode* createProperty(double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); } + template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); } + template <bool> PropertyNode* createProperty(JSGlobalData*, double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); } PropertyListNode* createPropertyList(PropertyNode* property) { return new (m_globalData) PropertyListNode(m_globalData, property); } PropertyListNode* createPropertyList(PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(m_globalData, property, tail); } @@ -576,7 +569,9 @@ public: assignmentStackDepth--; return result; } - + + const Identifier& getName(Property property) { return property->name(); } + PropertyNode::Type getType(Property property) { return property->type(); } private: struct Scope { Scope(JSGlobalData* globalData) @@ -767,13 +762,13 @@ ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, Bina case AND: return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalAnd); - case '|': + case BITOR: return new (m_globalData) BitOrNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); - case '^': + case BITXOR: return new (m_globalData) BitXOrNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); - case '&': + case BITAND: return new (m_globalData) BitAndNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); case EQEQ: @@ -788,10 +783,10 @@ ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, Bina case STRNEQ: return new (m_globalData) NotStrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); - case '<': + case LT: return new (m_globalData) LessNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); - case '>': + case GT: return new (m_globalData) GreaterNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); case LE: @@ -821,19 +816,19 @@ ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, Bina case URSHIFT: return new (m_globalData) UnsignedRightShiftNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); - case '+': + case PLUS: return makeAddNode(lhs.first, rhs.first, rhs.second.hasAssignment); - case '-': + case MINUS: return makeSubNode(lhs.first, rhs.first, rhs.second.hasAssignment); - case '*': + case TIMES: return makeMultNode(lhs.first, rhs.first, rhs.second.hasAssignment); - case '/': + case DIVIDE: return makeDivNode(lhs.first, rhs.first, rhs.second.hasAssignment); - case '%': + case MOD: return new (m_globalData) ModNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment); } CRASH(); 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: diff --git a/JavaScriptCore/parser/JSParser.h b/JavaScriptCore/parser/JSParser.h index 554556f..60f284c 100644 --- a/JavaScriptCore/parser/JSParser.h +++ b/JavaScriptCore/parser/JSParser.h @@ -30,71 +30,108 @@ namespace JSC { class Identifier; class JSGlobalData; +class SourceCode; + +enum { + UnaryOpTokenFlag = 64, + BinaryOpTokenPrecedenceShift = 7, + BinaryOpTokenAllowsInPrecedenceAdditionalShift = 4, + BinaryOpTokenPrecedenceMask = 15 << BinaryOpTokenPrecedenceShift +}; + +#define BINARY_OP_PRECEDENCE(prec) (((prec) << BinaryOpTokenPrecedenceShift) | ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift))) +#define IN_OP_PRECEDENCE(prec) ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift)) enum JSTokenType { - NULLTOKEN = 258, - TRUETOKEN = 259, - FALSETOKEN = 260, - BREAK = 261, - CASE = 262, - DEFAULT = 263, - FOR = 264, - NEW = 265, - VAR = 266, - CONSTTOKEN = 267, - CONTINUE = 268, - FUNCTION = 269, - RETURN = 270, - VOIDTOKEN = 271, - DELETETOKEN = 272, - IF = 273, - THISTOKEN = 274, - DO = 275, - WHILE = 276, - INTOKEN = 277, - INSTANCEOF = 278, - TYPEOF = 279, - SWITCH = 280, - WITH = 281, - RESERVED = 282, - THROW = 283, - TRY = 284, - CATCH = 285, - FINALLY = 286, - DEBUGGER = 287, - IF_WITHOUT_ELSE = 288, - ELSE = 289, - EQEQ = 290, - NE = 291, - STREQ = 292, - STRNEQ = 293, - LE = 294, - GE = 295, - OR = 296, - AND = 297, - PLUSPLUS = 298, - MINUSMINUS = 299, - LSHIFT = 300, - RSHIFT = 301, - URSHIFT = 302, - PLUSEQUAL = 303, - MINUSEQUAL = 304, - MULTEQUAL = 305, - DIVEQUAL = 306, - LSHIFTEQUAL = 307, - RSHIFTEQUAL = 308, - URSHIFTEQUAL = 309, - ANDEQUAL = 310, - MODEQUAL = 311, - XOREQUAL = 312, - OREQUAL = 313, - OPENBRACE = 314, - CLOSEBRACE = 315, - NUMBER = 316, - IDENT = 317, - STRING = 318, - AUTOPLUSPLUS = 319, - AUTOMINUSMINUS = 320 + NULLTOKEN, + TRUETOKEN, + FALSETOKEN, + BREAK, + CASE, + DEFAULT, + FOR, + NEW, + VAR, + CONSTTOKEN, + CONTINUE, + FUNCTION, + RETURN, + IF, + THISTOKEN, + DO, + WHILE, + SWITCH, + WITH, + RESERVED, + THROW, + TRY, + CATCH, + FINALLY, + DEBUGGER, + ELSE, + OPENBRACE, + CLOSEBRACE, + OPENPAREN, + CLOSEPAREN, + OPENBRACKET, + CLOSEBRACKET, + COMMA, + QUESTION, + NUMBER, + IDENT, + STRING, + SEMICOLON, + COLON, + DOT, + ERRORTOK, + EOFTOK, + EQUAL, + PLUSEQUAL, + MINUSEQUAL, + MULTEQUAL, + DIVEQUAL, + LSHIFTEQUAL, + RSHIFTEQUAL, + URSHIFTEQUAL, + ANDEQUAL, + MODEQUAL, + XOREQUAL, + OREQUAL, + LastUntaggedToken, + + // Begin tagged tokens + PLUSPLUS = 0 | UnaryOpTokenFlag, + MINUSMINUS = 1 | UnaryOpTokenFlag, + EXCLAMATION = 2 | UnaryOpTokenFlag, + TILDE = 3 | UnaryOpTokenFlag, + AUTOPLUSPLUS = 4 | UnaryOpTokenFlag, + AUTOMINUSMINUS = 5 | UnaryOpTokenFlag, + TYPEOF = 6 | UnaryOpTokenFlag, + VOIDTOKEN = 7 | UnaryOpTokenFlag, + DELETETOKEN = 8 | UnaryOpTokenFlag, + OR = 0 | BINARY_OP_PRECEDENCE(1), + AND = 1 | BINARY_OP_PRECEDENCE(2), + BITOR = 2 | BINARY_OP_PRECEDENCE(3), + BITXOR = 3 | BINARY_OP_PRECEDENCE(4), + BITAND = 4 | BINARY_OP_PRECEDENCE(5), + EQEQ = 5 | BINARY_OP_PRECEDENCE(6), + NE = 6 | BINARY_OP_PRECEDENCE(6), + STREQ = 7 | BINARY_OP_PRECEDENCE(6), + STRNEQ = 8 | BINARY_OP_PRECEDENCE(6), + LT = 9 | BINARY_OP_PRECEDENCE(7), + GT = 10 | BINARY_OP_PRECEDENCE(7), + LE = 11 | BINARY_OP_PRECEDENCE(7), + GE = 12 | BINARY_OP_PRECEDENCE(7), + INSTANCEOF = 13 | BINARY_OP_PRECEDENCE(7), + INTOKEN = 14 | IN_OP_PRECEDENCE(7), + LSHIFT = 15 | BINARY_OP_PRECEDENCE(8), + RSHIFT = 16 | BINARY_OP_PRECEDENCE(8), + URSHIFT = 17 | BINARY_OP_PRECEDENCE(8), + PLUS = 18 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag, + MINUS = 19 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag, + TIMES = 20 | BINARY_OP_PRECEDENCE(10), + DIVIDE = 21 | BINARY_OP_PRECEDENCE(10), + MOD = 22 | BINARY_OP_PRECEDENCE(10) }; union JSTokenData { @@ -102,22 +139,20 @@ union JSTokenData { double doubleValue; const Identifier* ident; }; -typedef JSTokenData YYSTYPE; struct JSTokenInfo { - JSTokenInfo() : last_line(0) {} - int first_line; - int last_line; - int first_column; - int last_column; + JSTokenInfo() : line(0) {} + int line; + int startOffset; + int endOffset; }; -typedef JSTokenInfo YYLTYPE; + struct JSToken { - int m_type; + JSTokenType m_type; JSTokenData m_data; JSTokenInfo m_info; }; -int jsParse(JSGlobalData*); +int jsParse(JSGlobalData*, const SourceCode*); } #endif // JSParser_h diff --git a/JavaScriptCore/parser/Lexer.cpp b/JavaScriptCore/parser/Lexer.cpp index 660b1a4..45fe007 100644 --- a/JavaScriptCore/parser/Lexer.cpp +++ b/JavaScriptCore/parser/Lexer.cpp @@ -56,7 +56,14 @@ enum CharacterTypes { CharacterLineTerminator, CharacterExclamationMark, - CharacterSimple, + CharacterOpenParen, + CharacterCloseParen, + CharacterOpenBracket, + CharacterCloseBracket, + CharacterComma, + CharacterColon, + CharacterQuestion, + CharacterTilde, CharacterQuote, CharacterDot, CharacterSlash, @@ -81,7 +88,7 @@ enum CharacterTypes { }; // 128 ascii codes -static unsigned char AsciiCharacters[128] = { +static unsigned short AsciiCharacters[128] = { /* 0 - Null */ CharacterInvalid, /* 1 - Start of Heading */ CharacterInvalid, /* 2 - Start of Text */ CharacterInvalid, @@ -122,11 +129,11 @@ static unsigned char AsciiCharacters[128] = { /* 37 - % */ CharacterModulo, /* 38 - & */ CharacterAnd, /* 39 - ' */ CharacterQuote, -/* 40 - ( */ CharacterSimple, -/* 41 - ) */ CharacterSimple, +/* 40 - ( */ CharacterOpenParen, +/* 41 - ) */ CharacterCloseParen, /* 42 - * */ CharacterMultiply, /* 43 - + */ CharacterAdd, -/* 44 - , */ CharacterSimple, +/* 44 - , */ CharacterComma, /* 45 - - */ CharacterSub, /* 46 - . */ CharacterDot, /* 47 - / */ CharacterSlash, @@ -140,12 +147,12 @@ static unsigned char AsciiCharacters[128] = { /* 55 - 7 */ CharacterNumber, /* 56 - 8 */ CharacterNumber, /* 57 - 9 */ CharacterNumber, -/* 58 - : */ CharacterSimple, +/* 58 - : */ CharacterColon, /* 59 - ; */ CharacterSemicolon, /* 60 - < */ CharacterLess, /* 61 - = */ CharacterEqual, /* 62 - > */ CharacterGreater, -/* 63 - ? */ CharacterSimple, +/* 63 - ? */ CharacterQuestion, /* 64 - @ */ CharacterInvalid, /* 65 - A */ CharacterAlpha, /* 66 - B */ CharacterAlpha, @@ -173,9 +180,9 @@ static unsigned char AsciiCharacters[128] = { /* 88 - X */ CharacterAlpha, /* 89 - Y */ CharacterAlpha, /* 90 - Z */ CharacterAlpha, -/* 91 - [ */ CharacterSimple, +/* 91 - [ */ CharacterOpenBracket, /* 92 - \ */ CharacterBackSlash, -/* 93 - ] */ CharacterSimple, +/* 93 - ] */ CharacterCloseBracket, /* 94 - ^ */ CharacterXor, /* 95 - _ */ CharacterAlpha, /* 96 - ` */ CharacterInvalid, @@ -208,7 +215,7 @@ static unsigned char AsciiCharacters[128] = { /* 123 - { */ CharacterOpenBrace, /* 124 - | */ CharacterOr, /* 125 - } */ CharacterCloseBrace, -/* 126 - ~ */ CharacterSimple, +/* 126 - ~ */ CharacterTilde, /* 127 - Delete */ CharacterInvalid, }; @@ -357,8 +364,14 @@ static inline int singleEscape(int c) return 0x0C; case 'r': return 0x0D; + case '\\': + return '\\'; + case '\'': + return '\''; + case '"': + return '"'; default: - return c; + return 0; } } @@ -381,15 +394,92 @@ inline void Lexer::record16(int c) record16(UChar(static_cast<unsigned short>(c))); } -int Lexer::lex(void* p1, void* p2) +ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp) +{ + int stringQuoteCharacter = m_current; + shift(); + + const UChar* stringStart = currentCharacter(); + + while (m_current != stringQuoteCharacter) { + if (UNLIKELY(m_current == '\\')) { + if (stringStart != currentCharacter()) + m_buffer16.append(stringStart, currentCharacter() - stringStart); + shift(); + + int escape = singleEscape(m_current); + + // Most common escape sequences first + if (escape) { + record16(escape); + shift(); + } else if (UNLIKELY(isLineTerminator(m_current))) + shiftLineTerminator(); + else if (m_current == 'x') { + shift(); + if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) { + int prev = m_current; + shift(); + record16(convertHex(prev, m_current)); + shift(); + } else + record16('x'); + } else if (m_current == 'u') { + shift(); + int character = getUnicodeCharacter(); + if (character != -1) + record16(character); + else if (m_current == stringQuoteCharacter) + record16('u'); + else // Only stringQuoteCharacter allowed after \u + return false; + } else if (isASCIIOctalDigit(m_current)) { + // Octal character sequences + int character1 = m_current; + shift(); + if (isASCIIOctalDigit(m_current)) { + // Two octal characters + int character2 = m_current; + shift(); + if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) { + record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0'); + shift(); + } else + record16((character1 - '0') * 8 + character2 - '0'); + } else + record16(character1 - '0'); + } else if (m_current != -1) { + record16(m_current); + shift(); + } else + return false; + + stringStart = currentCharacter(); + continue; + } else if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) { + // New-line or end of input is not allowed + if (UNLIKELY(isLineTerminator(m_current)) || UNLIKELY(m_current == -1)) + return false; + // Anything else is just a normal character + } + shift(); + } + + if (currentCharacter() != stringStart) + m_buffer16.append(stringStart, currentCharacter() - stringStart); + lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size()); + m_buffer16.resize(0); + return true; +} + +JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp) { ASSERT(!m_error); ASSERT(m_buffer8.isEmpty()); ASSERT(m_buffer16.isEmpty()); - YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1); - YYLTYPE* llocp = static_cast<YYLTYPE*>(p2); - int token = 0; + JSTokenType token = ERRORTOK; + int identChar = 0; m_terminator = false; start: @@ -398,20 +488,13 @@ start: int startOffset = currentOffset(); - if (UNLIKELY(m_current == -1)) { - if (!m_terminator && !m_delimited && !m_isReparsing) { - // automatic semicolon insertion if program incomplete - token = ';'; - goto doneSemicolon; - } - return 0; - } + if (UNLIKELY(m_current == -1)) + return EOFTOK; m_delimited = false; - ASSERT(m_current >= 0); - if (m_current < 128) { - ASSERT(isASCII(m_current)); + if (isASCII(m_current)) { + ASSERT(m_current >= 0 && m_current < 128); switch (AsciiCharacters[m_current]) { case CharacterGreater: @@ -441,7 +524,7 @@ start: token = GE; break; } - token = '>'; + token = GT; break; case CharacterEqual: shift(); @@ -455,7 +538,7 @@ start: token = EQEQ; break; } - token = '='; + token = EQUAL; break; case CharacterLess: shift(); @@ -478,7 +561,7 @@ start: token = LE; break; } - token = '<'; + token = LT; break; case CharacterExclamationMark: shift(); @@ -492,7 +575,7 @@ start: token = NE; break; } - token = '!'; + token = EXCLAMATION; break; case CharacterAdd: shift(); @@ -506,7 +589,7 @@ start: token = PLUSEQUAL; break; } - token = '+'; + token = PLUS; break; case CharacterSub: shift(); @@ -524,7 +607,7 @@ start: token = MINUSEQUAL; break; } - token = '-'; + token = MINUS; break; case CharacterMultiply: shift(); @@ -533,7 +616,7 @@ start: token = MULTEQUAL; break; } - token = '*'; + token = TIMES; break; case CharacterSlash: shift(); @@ -550,7 +633,7 @@ start: token = DIVEQUAL; break; } - token = '/'; + token = DIVIDE; break; case CharacterAnd: shift(); @@ -564,7 +647,7 @@ start: token = ANDEQUAL; break; } - token = '&'; + token = BITAND; break; case CharacterXor: shift(); @@ -573,7 +656,7 @@ start: token = XOREQUAL; break; } - token = '^'; + token = BITXOR; break; case CharacterModulo: shift(); @@ -582,7 +665,7 @@ start: token = MODEQUAL; break; } - token = '%'; + token = MOD; break; case CharacterOr: shift(); @@ -596,7 +679,7 @@ start: token = OR; break; } - token = '|'; + token = BITOR; break; case CharacterDot: shift(); @@ -604,16 +687,44 @@ start: record8('.'); goto inNumberAfterDecimalPoint; } - token = '.'; + token = DOT; + break; + case CharacterOpenParen: + token = OPENPAREN; + shift(); + break; + case CharacterCloseParen: + token = CLOSEPAREN; + shift(); + break; + case CharacterOpenBracket: + token = OPENBRACKET; + shift(); break; - case CharacterSimple: - token = m_current; + case CharacterCloseBracket: + token = CLOSEBRACKET; + shift(); + break; + case CharacterComma: + token = COMMA; + shift(); + break; + case CharacterColon: + token = COLON; + shift(); + break; + case CharacterQuestion: + token = QUESTION; + shift(); + break; + case CharacterTilde: + token = TILDE; shift(); break; case CharacterSemicolon: m_delimited = true; shift(); - token = ';'; + token = SEMICOLON; break; case CharacterOpenBrace: lvalp->intValue = currentOffset(); @@ -633,7 +744,12 @@ start: case CharacterNumber: goto startNumber; case CharacterQuote: - goto startString; + if (UNLIKELY(!parseString(lvalp))) + goto returnError; + shift(); + m_delimited = false; + token = STRING; + break; case CharacterAlpha: ASSERT(isIdentStart(m_current)); goto startIdentifierOrKeyword; @@ -643,7 +759,7 @@ start: m_atLineStart = true; m_terminator = true; if (lastTokenWasRestrKeyword()) { - token = ';'; + token = SEMICOLON; goto doneSemicolon; } goto start; @@ -655,7 +771,6 @@ start: } } else { // Rare characters - ASSERT(!isASCII(m_current)); if (isNonASCIIIdentStart(m_current)) goto startIdentifierOrKeyword; @@ -663,10 +778,8 @@ start: shiftLineTerminator(); m_atLineStart = true; m_terminator = true; - if (lastTokenWasRestrKeyword()) { - token = ';'; + if (lastTokenWasRestrKeyword()) goto doneSemicolon; - } goto start; } goto returnError; @@ -675,109 +788,16 @@ start: m_atLineStart = false; goto returnToken; -startString: { - int stringQuoteCharacter = m_current; - shift(); - - const UChar* stringStart = currentCharacter(); - while (m_current != stringQuoteCharacter) { - // Fast check for characters that require special handling. - // Catches -1, \n, \r, \, 0x2028, and 0x2029 as efficiently - // as possible, and lets through all common ASCII characters. - if (UNLIKELY(m_current == '\\') || UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) { - m_buffer16.append(stringStart, currentCharacter() - stringStart); - goto inString; - } - shift(); - } - lvalp->ident = makeIdentifier(stringStart, currentCharacter() - stringStart); - shift(); - m_atLineStart = false; - m_delimited = false; - token = STRING; - goto returnToken; - -inString: - while (m_current != stringQuoteCharacter) { - if (m_current == '\\') - goto inStringEscapeSequence; - if (UNLIKELY(isLineTerminator(m_current))) - goto returnError; - if (UNLIKELY(m_current == -1)) - goto returnError; - record16(m_current); - shift(); - } - goto doneString; - -inStringEscapeSequence: - shift(); - if (m_current == 'x') { - shift(); - if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) { - int prev = m_current; - shift(); - record16(convertHex(prev, m_current)); - shift(); - goto inString; - } - record16('x'); - if (m_current == stringQuoteCharacter) - goto doneString; - goto inString; - } - if (m_current == 'u') { - shift(); - token = getUnicodeCharacter(); - if (token != -1) { - record16(token); - goto inString; - } - if (m_current == stringQuoteCharacter) { - record16('u'); - goto doneString; - } - goto returnError; - } - if (isASCIIOctalDigit(m_current)) { - int char1 = m_current; - shift(); - if (char1 >= '0' && char1 <= '3' && isASCIIOctalDigit(m_current) && isASCIIOctalDigit(peek(1))) { - int char2 = m_current; - shift(); - record16((char1 - '0') * 64 + (char2 - '0') * 8 + m_current - '0'); - shift(); - goto inString; - } - if (isASCIIOctalDigit(m_current)) { - record16((char1 - '0') * 8 + m_current - '0'); - shift(); - goto inString; - } - record16(char1 - '0'); - goto inString; - } - if (isLineTerminator(m_current)) { - shiftLineTerminator(); - goto inString; - } - if (m_current == -1) - goto returnError; - record16(singleEscape(m_current)); - shift(); - goto inString; -} - startIdentifierWithBackslash: { shift(); if (UNLIKELY(m_current != 'u')) goto returnError; shift(); - token = getUnicodeCharacter(); - if (UNLIKELY(token == -1)) + identChar = getUnicodeCharacter(); + if (UNLIKELY(identChar == -1)) goto returnError; - if (UNLIKELY(!isIdentStart(token))) + if (UNLIKELY(!isIdentStart(identChar))) goto returnError; goto inIdentifierAfterCharacterCheck; } @@ -800,13 +820,13 @@ startIdentifierOrKeyword: { if (UNLIKELY(m_current != 'u')) goto returnError; shift(); - token = getUnicodeCharacter(); - if (UNLIKELY(token == -1)) + identChar = getUnicodeCharacter(); + if (UNLIKELY(identChar == -1)) goto returnError; - if (UNLIKELY(!isIdentPart(token))) + if (UNLIKELY(!isIdentPart(identChar))) goto returnError; inIdentifierAfterCharacterCheck: - record16(token); + record16(identChar); while (isIdentPart(m_current)) { record16(m_current); @@ -818,7 +838,7 @@ inIdentifierAfterCharacterCheck: inSingleLineComment: while (!isLineTerminator(m_current)) { if (UNLIKELY(m_current == -1)) - return 0; + return EOFTOK; shift(); } shiftLineTerminator(); @@ -985,7 +1005,7 @@ doneNumeric: goto returnToken; doneSemicolon: - token = ';'; + token = SEMICOLON; m_delimited = true; goto returnToken; @@ -1002,34 +1022,23 @@ doneIdentifierOrKeyword: { m_delimited = false; m_buffer16.resize(0); const HashEntry* entry = m_keywordTable.entry(m_globalData, *lvalp->ident); - token = entry ? entry->lexerValue() : static_cast<int>(IDENT); - goto returnToken; -} - -doneString: - // Atomize constant strings in case they're later used in property lookup. - shift(); - m_atLineStart = false; - m_delimited = false; - lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size()); - m_buffer16.resize(0); - token = STRING; + token = entry ? static_cast<JSTokenType>(entry->lexerValue()) : IDENT; // Fall through into returnToken. +} returnToken: { int lineNumber = m_lineNumber; - llocp->first_line = lineNumber; - llocp->last_line = lineNumber; - llocp->first_column = startOffset; - llocp->last_column = currentOffset(); + llocp->line = lineNumber; + llocp->startOffset = startOffset; + llocp->endOffset = currentOffset(); m_lastToken = token; return token; } returnError: m_error = true; - return -1; + return ERRORTOK; } bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix) @@ -1136,7 +1145,6 @@ bool Lexer::skipRegExp() void Lexer::clear() { m_arena = 0; - m_codeWithoutBOMs.clear(); Vector<char> newBuffer8; m_buffer8.swap(newBuffer8); diff --git a/JavaScriptCore/parser/Lexer.h b/JavaScriptCore/parser/Lexer.h index ec254ce..5ab7ad7 100644 --- a/JavaScriptCore/parser/Lexer.h +++ b/JavaScriptCore/parser/Lexer.h @@ -23,6 +23,7 @@ #ifndef Lexer_h #define Lexer_h +#include "JSParser.h" #include "Lookup.h" #include "ParserArena.h" #include "SourceCode.h" @@ -49,7 +50,7 @@ namespace JSC { void setIsReparsing() { m_isReparsing = true; } // Functions for the parser itself. - int lex(void* lvalp, void* llocp); + JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp); int lineNumber() const { return m_lineNumber; } void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; } int lastLineNumber() const { return m_lastLineNumber; } @@ -61,6 +62,12 @@ namespace JSC { // Functions for use after parsing. bool sawError() const { return m_error; } void clear(); + int currentOffset() { return m_code - m_codeStart; } + void setOffset(int offset) + { + m_code = m_codeStart + offset; + m_current = *m_code; + } private: friend class JSGlobalData; @@ -86,8 +93,10 @@ namespace JSC { ALWAYS_INLINE bool lastTokenWasRestrKeyword() const; + ALWAYS_INLINE bool parseString(JSTokenData* lvalp); + static const size_t initialReadBufferCapacity = 32; - + int m_lineNumber; int m_lastLineNumber; @@ -113,8 +122,6 @@ namespace JSC { JSGlobalData* m_globalData; const HashTable m_keywordTable; - - Vector<UChar> m_codeWithoutBOMs; }; inline bool Lexer::isWhiteSpace(int ch) @@ -137,12 +144,6 @@ namespace JSC { return (convertHex(c1, c2) << 8) | convertHex(c3, c4); } - // A bridge for yacc from the C world to the C++ world. - inline int jscyylex(void* lvalp, void* llocp, void* globalData) - { - return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); - } - } // namespace JSC #endif // Lexer_h diff --git a/JavaScriptCore/parser/Nodes.cpp b/JavaScriptCore/parser/Nodes.cpp index 4b97e9a..ffea524 100644 --- a/JavaScriptCore/parser/Nodes.cpp +++ b/JavaScriptCore/parser/Nodes.cpp @@ -98,7 +98,7 @@ ScopeNode::ScopeNode(JSGlobalData* globalData) ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) : StatementNode(globalData) , ParserArenaRefCounted(globalData) - , m_data(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, numConstants)) + , m_data(adoptPtr(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, numConstants))) , m_features(features) , m_source(source) { diff --git a/JavaScriptCore/parser/Nodes.h b/JavaScriptCore/parser/Nodes.h index 57c8f4f..6206384 100644 --- a/JavaScriptCore/parser/Nodes.h +++ b/JavaScriptCore/parser/Nodes.h @@ -404,12 +404,13 @@ namespace JSC { class PropertyNode : public ParserArenaFreeable { public: - enum Type { Constant, Getter, Setter }; + enum Type { Constant = 1, Getter = 2, Setter = 4 }; PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* value, Type); PropertyNode(JSGlobalData*, double name, ExpressionNode* value, Type); const Identifier& name() const { return m_name; } + Type type() const { return m_type; } private: friend class PropertyListNode; diff --git a/JavaScriptCore/parser/Parser.cpp b/JavaScriptCore/parser/Parser.cpp index b97754f..39ff597 100644 --- a/JavaScriptCore/parser/Parser.cpp +++ b/JavaScriptCore/parser/Parser.cpp @@ -60,7 +60,7 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) Lexer& lexer = *globalData->lexer; lexer.setCode(*m_source, m_arena); - int parseError = jsParse(globalData); + int parseError = jsParse(globalData, m_source); int lineNumber = lexer.lineNumber(); bool lexError = lexer.sawError(); lexer.clear(); diff --git a/JavaScriptCore/parser/ParserArena.cpp b/JavaScriptCore/parser/ParserArena.cpp index a8e8159..9c96de7 100644 --- a/JavaScriptCore/parser/ParserArena.cpp +++ b/JavaScriptCore/parser/ParserArena.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,13 +27,14 @@ #include "ParserArena.h" #include "Nodes.h" +#include <wtf/PassOwnPtr.h> namespace JSC { ParserArena::ParserArena() : m_freeableMemory(0) , m_freeablePoolEnd(0) - , m_identifierArena(new IdentifierArena) + , m_identifierArena(adoptPtr(new IdentifierArena)) { } diff --git a/JavaScriptCore/parser/SourceProvider.h b/JavaScriptCore/parser/SourceProvider.h index 87ea960..6b9c028 100644 --- a/JavaScriptCore/parser/SourceProvider.h +++ b/JavaScriptCore/parser/SourceProvider.h @@ -38,6 +38,7 @@ namespace JSC { public: SourceProvider(const UString& url) : m_url(url) + , m_validated(false) { } virtual ~SourceProvider() { } @@ -49,8 +50,12 @@ namespace JSC { const UString& url() { return m_url; } intptr_t asID() { return reinterpret_cast<intptr_t>(this); } + bool isValid() const { return m_validated; } + void setValid() { m_validated = true; } + private: UString m_url; + bool m_validated; }; class UStringSourceProvider : public SourceProvider { diff --git a/JavaScriptCore/parser/SyntaxChecker.h b/JavaScriptCore/parser/SyntaxChecker.h index cad89f6..e05facd 100644 --- a/JavaScriptCore/parser/SyntaxChecker.h +++ b/JavaScriptCore/parser/SyntaxChecker.h @@ -29,7 +29,7 @@ namespace JSC { class SyntaxChecker { public: - SyntaxChecker(JSGlobalData*, Lexer*) + SyntaxChecker(JSGlobalData* , Lexer*) { } @@ -39,7 +39,25 @@ public: typedef int SourceElements; typedef int Arguments; typedef int Comma; - typedef int Property; + struct Property { + ALWAYS_INLINE Property(void* = 0) + : type((PropertyNode::Type)0) + { + } + ALWAYS_INLINE Property(const Identifier* ident, PropertyNode::Type ty) + : name(ident) + , type(ty) + { + } + ALWAYS_INLINE Property(PropertyNode::Type ty) + : name(0) + , type(ty) + { + } + ALWAYS_INLINE bool operator!() { return !type; } + const Identifier* name; + PropertyNode::Type type; + }; typedef int PropertyList; typedef int ElementList; typedef int ArgumentsList; @@ -90,10 +108,21 @@ public: int createArguments(int) { return 1; } int createArgumentsList(int) { return 1; } int createArgumentsList(int, int) { return 1; } - int createProperty(const Identifier*, int, PropertyNode::Type) { return 1; } - int createProperty(double, int, PropertyNode::Type) { return 1; } - int createPropertyList(int) { return 1; } - int createPropertyList(int, int) { return 1; } + template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type) + { + ASSERT(name); + if (!complete) + return Property(type); + return Property(name, type); + } + template <bool complete> Property createProperty(JSGlobalData* globalData, double name, int, PropertyNode::Type type) + { + if (!complete) + return Property(type); + return Property(&globalData->parser->arena().identifierArena().makeNumericIdentifier(globalData, name), type); + } + int createPropertyList(Property) { return 1; } + int createPropertyList(Property, int) { return 1; } int createElementList(int, int) { return 1; } int createElementList(int, int, int) { return 1; } int createFormalParameterList(const Identifier&) { return 1; } @@ -127,7 +156,13 @@ public: int createDebugger(int, int) { return 1; } int createConstStatement(int, int, int) { return 1; } int appendConstDecl(int, const Identifier*, int) { return 1; } - int createGetterOrSetterProperty(const Identifier*, const Identifier*, int, int, int, int, int, int) { return 1; } + template <bool strict> Property createGetterOrSetterProperty(PropertyNode::Type type, const Identifier* name, int, int, int, int, int, int) + { + ASSERT(name); + if (!strict) + return Property(type); + return Property(name, type); + } void appendStatement(int, int) { } void addVar(const Identifier*, bool) { } @@ -151,6 +186,8 @@ public: void assignmentStackAppend(int, int, int, int, int, Operator) { } int createAssignment(int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; } + const Identifier& getName(const Property& property) { ASSERT(property.name); return *property.name; } + PropertyNode::Type getType(const Property& property) { return property.type; } }; } |