summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/parser
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2015-10-15 09:45:50 +0000
commite15dd966d523731101f70ccf768bba12435a0208 (patch)
treeae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/parser
downloadWebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/parser')
-rw-r--r--Source/JavaScriptCore/parser/ASTBuilder.h1253
-rw-r--r--Source/JavaScriptCore/parser/Keywords.table57
-rw-r--r--Source/JavaScriptCore/parser/Lexer.cpp2417
-rw-r--r--Source/JavaScriptCore/parser/Lexer.h389
-rw-r--r--Source/JavaScriptCore/parser/ModuleAnalyzer.cpp155
-rw-r--r--Source/JavaScriptCore/parser/ModuleAnalyzer.h62
-rw-r--r--Source/JavaScriptCore/parser/ModuleRecord.cpp95
-rw-r--r--Source/JavaScriptCore/parser/ModuleRecord.h128
-rw-r--r--Source/JavaScriptCore/parser/NodeConstructors.h1018
-rw-r--r--Source/JavaScriptCore/parser/Nodes.cpp205
-rw-r--r--Source/JavaScriptCore/parser/Nodes.h2127
-rw-r--r--Source/JavaScriptCore/parser/NodesAnalyzeModule.cpp96
-rw-r--r--Source/JavaScriptCore/parser/Parser.cpp3700
-rw-r--r--Source/JavaScriptCore/parser/Parser.h1385
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.cpp76
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.h193
-rw-r--r--Source/JavaScriptCore/parser/ParserError.h124
-rw-r--r--Source/JavaScriptCore/parser/ParserFunctionInfo.h53
-rw-r--r--Source/JavaScriptCore/parser/ParserModes.h157
-rw-r--r--Source/JavaScriptCore/parser/ParserTokens.h234
-rw-r--r--Source/JavaScriptCore/parser/ResultType.h189
-rw-r--r--Source/JavaScriptCore/parser/SourceCode.cpp43
-rw-r--r--Source/JavaScriptCore/parser/SourceCode.h129
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.cpp59
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.h130
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCache.cpp48
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCache.h51
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCacheItem.h153
-rw-r--r--Source/JavaScriptCore/parser/SyntaxChecker.h372
-rw-r--r--Source/JavaScriptCore/parser/VariableEnvironment.cpp98
-rw-r--r--Source/JavaScriptCore/parser/VariableEnvironment.h98
31 files changed, 15294 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
new file mode 100644
index 000000000..7b587730a
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -0,0 +1,1253 @@
+/*
+ * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ASTBuilder_h
+#define ASTBuilder_h
+
+#include "BuiltinNames.h"
+#include "BytecodeIntrinsicRegistry.h"
+#include "NodeConstructors.h"
+#include "SyntaxChecker.h"
+#include "VariableEnvironment.h"
+#include <utility>
+
+namespace JSC {
+
+class ASTBuilder {
+ struct BinaryOpInfo {
+ BinaryOpInfo() {}
+ BinaryOpInfo(const JSTextPosition& otherStart, const JSTextPosition& otherDivot, const JSTextPosition& otherEnd, bool rhsHasAssignment)
+ : start(otherStart)
+ , divot(otherDivot)
+ , end(otherEnd)
+ , hasAssignment(rhsHasAssignment)
+ {
+ }
+ BinaryOpInfo(const BinaryOpInfo& lhs, const BinaryOpInfo& rhs)
+ : start(lhs.start)
+ , divot(rhs.start)
+ , end(rhs.end)
+ , hasAssignment(lhs.hasAssignment || rhs.hasAssignment)
+ {
+ }
+ JSTextPosition start;
+ JSTextPosition divot;
+ JSTextPosition end;
+ bool hasAssignment;
+ };
+
+
+ struct AssignmentInfo {
+ AssignmentInfo() {}
+ AssignmentInfo(ExpressionNode* node, const JSTextPosition& start, const JSTextPosition& divot, int initAssignments, Operator op)
+ : m_node(node)
+ , m_start(start)
+ , m_divot(divot)
+ , m_initAssignments(initAssignments)
+ , m_op(op)
+ {
+ ASSERT(m_divot.offset >= m_divot.lineStartOffset);
+ ASSERT(m_start.offset >= m_start.lineStartOffset);
+ }
+ ExpressionNode* m_node;
+ JSTextPosition m_start;
+ JSTextPosition m_divot;
+ int m_initAssignments;
+ Operator m_op;
+ };
+public:
+ ASTBuilder(VM* vm, ParserArena& parserArena, SourceCode* sourceCode)
+ : m_vm(vm)
+ , m_parserArena(parserArena)
+ , m_sourceCode(sourceCode)
+ , m_evalCount(0)
+ {
+ }
+
+ struct BinaryExprContext {
+ BinaryExprContext(ASTBuilder&) {}
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(ASTBuilder&) {}
+ };
+
+ typedef ExpressionNode* Expression;
+ typedef JSC::SourceElements* SourceElements;
+ typedef ArgumentsNode* Arguments;
+ typedef CommaNode* Comma;
+ typedef PropertyNode* Property;
+ typedef PropertyListNode* PropertyList;
+ typedef ElementNode* ElementList;
+ typedef ArgumentListNode* ArgumentsList;
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ typedef TemplateExpressionListNode* TemplateExpressionList;
+ typedef TemplateStringNode* TemplateString;
+ typedef TemplateStringListNode* TemplateStringList;
+ typedef TemplateLiteralNode* TemplateLiteral;
+#endif
+ typedef FunctionParameters* FormalParameterList;
+ typedef FunctionMetadataNode* FunctionBody;
+#if ENABLE(ES6_CLASS_SYNTAX)
+ typedef ClassExprNode* ClassExpression;
+#endif
+ typedef ModuleNameNode* ModuleName;
+ typedef ImportSpecifierNode* ImportSpecifier;
+ typedef ImportSpecifierListNode* ImportSpecifierList;
+ typedef ExportSpecifierNode* ExportSpecifier;
+ typedef ExportSpecifierListNode* ExportSpecifierList;
+ typedef StatementNode* Statement;
+ typedef ClauseListNode* ClauseList;
+ typedef CaseClauseNode* Clause;
+ typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
+ typedef DestructuringPatternNode* DestructuringPattern;
+ typedef ArrayPatternNode* ArrayPattern;
+ typedef ObjectPatternNode* ObjectPattern;
+ typedef BindingNode* BindingPattern;
+ static const bool CreatesAST = true;
+ static const bool NeedsFreeVariableInfo = true;
+ static const bool CanUseFunctionCache = true;
+ static const int DontBuildKeywords = 0;
+ static const int DontBuildStrings = 0;
+
+ ExpressionNode* makeBinaryNode(const JSTokenLocation&, int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
+ ExpressionNode* makeFunctionCallNode(const JSTokenLocation&, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd);
+
+ JSC::SourceElements* createSourceElements() { return new (m_parserArena) JSC::SourceElements(); }
+
+ DeclarationStacks::FunctionStack& funcDeclarations() { return m_scope.m_funcDeclarations; }
+ int features() const { return m_scope.m_features; }
+ int numConstants() const { return m_scope.m_numConstants; }
+
+ ExpressionNode* makeAssignNode(const JSTokenLocation&, ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end);
+ ExpressionNode* makePrefixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end);
+ ExpressionNode* makePostfixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end);
+ ExpressionNode* makeTypeOfNode(const JSTokenLocation&, ExpressionNode*);
+ ExpressionNode* makeDeleteNode(const JSTokenLocation&, ExpressionNode*, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end);
+ ExpressionNode* makeNegateNode(const JSTokenLocation&, ExpressionNode*);
+ ExpressionNode* makeBitwiseNotNode(const JSTokenLocation&, ExpressionNode*);
+ ExpressionNode* makeMultNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeDivNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeModNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeAddNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeSubNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitXOrNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitAndNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitOrNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeLeftShiftNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeRightShiftNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeURightShiftNode(const JSTokenLocation&, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+
+ ExpressionNode* createLogicalNot(const JSTokenLocation& location, ExpressionNode* expr)
+ {
+ if (expr->isNumber())
+ return createBoolean(location, isZeroOrUnordered(static_cast<NumberNode*>(expr)->value()));
+
+ return new (m_parserArena) LogicalNotNode(location, expr);
+ }
+ ExpressionNode* createUnaryPlus(const JSTokenLocation& location, ExpressionNode* expr) { return new (m_parserArena) UnaryPlusNode(location, expr); }
+ ExpressionNode* createVoid(const JSTokenLocation& location, ExpressionNode* expr)
+ {
+ incConstants();
+ return new (m_parserArena) VoidNode(location, expr);
+ }
+ ExpressionNode* createThisExpr(const JSTokenLocation& location, ThisTDZMode thisTDZMode)
+ {
+ usesThis();
+ return new (m_parserArena) ThisNode(location, thisTDZMode);
+ }
+ ExpressionNode* createSuperExpr(const JSTokenLocation& location)
+ {
+ return new (m_parserArena) SuperNode(location);
+ }
+ ExpressionNode* createNewTargetExpr(const JSTokenLocation location)
+ {
+ return new (m_parserArena) NewTargetNode(location);
+ }
+ ExpressionNode* createResolve(const JSTokenLocation& location, const Identifier* ident, const JSTextPosition& start)
+ {
+ if (m_vm->propertyNames->arguments == *ident)
+ usesArguments();
+ return new (m_parserArena) ResolveNode(location, *ident, start);
+ }
+ ExpressionNode* createObjectLiteral(const JSTokenLocation& location) { return new (m_parserArena) ObjectLiteralNode(location); }
+ ExpressionNode* createObjectLiteral(const JSTokenLocation& location, PropertyListNode* properties) { return new (m_parserArena) ObjectLiteralNode(location, properties); }
+
+ ExpressionNode* createArray(const JSTokenLocation& location, int elisions)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_parserArena) ArrayNode(location, elisions);
+ }
+
+ ExpressionNode* createArray(const JSTokenLocation& location, ElementNode* elems) { return new (m_parserArena) ArrayNode(location, elems); }
+ ExpressionNode* createArray(const JSTokenLocation& location, int elisions, ElementNode* elems)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_parserArena) ArrayNode(location, elisions, elems);
+ }
+ ExpressionNode* createDoubleExpr(const JSTokenLocation& location, double d)
+ {
+ incConstants();
+ return new (m_parserArena) DoubleNode(location, d);
+ }
+ ExpressionNode* createIntegerExpr(const JSTokenLocation& location, double d)
+ {
+ incConstants();
+ return new (m_parserArena) IntegerNode(location, d);
+ }
+
+ ExpressionNode* createString(const JSTokenLocation& location, const Identifier* string)
+ {
+ incConstants();
+ return new (m_parserArena) StringNode(location, *string);
+ }
+
+ ExpressionNode* createBoolean(const JSTokenLocation& location, bool b)
+ {
+ incConstants();
+ return new (m_parserArena) BooleanNode(location, b);
+ }
+
+ ExpressionNode* createNull(const JSTokenLocation& location)
+ {
+ incConstants();
+ return new (m_parserArena) NullNode(location);
+ }
+
+ ExpressionNode* createBracketAccess(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* property, bool propertyHasAssignments, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ BracketAccessorNode* node = new (m_parserArena) BracketAccessorNode(location, base, property, propertyHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createDotAccess(const JSTokenLocation& location, ExpressionNode* base, const Identifier* property, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ DotAccessorNode* node = new (m_parserArena) DotAccessorNode(location, base, *property);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createSpreadExpression(const JSTokenLocation& location, ExpressionNode* expression, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ auto node = new (m_parserArena) SpreadExpressionNode(location, expression);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ TemplateStringNode* createTemplateString(const JSTokenLocation& location, const Identifier& cooked, const Identifier& raw)
+ {
+ return new (m_parserArena) TemplateStringNode(location, cooked, raw);
+ }
+
+ TemplateStringListNode* createTemplateStringList(TemplateStringNode* templateString)
+ {
+ return new (m_parserArena) TemplateStringListNode(templateString);
+ }
+
+ TemplateStringListNode* createTemplateStringList(TemplateStringListNode* templateStringList, TemplateStringNode* templateString)
+ {
+ return new (m_parserArena) TemplateStringListNode(templateStringList, templateString);
+ }
+
+ TemplateExpressionListNode* createTemplateExpressionList(ExpressionNode* expression)
+ {
+ return new (m_parserArena) TemplateExpressionListNode(expression);
+ }
+
+ TemplateExpressionListNode* createTemplateExpressionList(TemplateExpressionListNode* templateExpressionListNode, ExpressionNode* expression)
+ {
+ return new (m_parserArena) TemplateExpressionListNode(templateExpressionListNode, expression);
+ }
+
+ TemplateLiteralNode* createTemplateLiteral(const JSTokenLocation& location, TemplateStringListNode* templateStringList)
+ {
+ return new (m_parserArena) TemplateLiteralNode(location, templateStringList);
+ }
+
+ TemplateLiteralNode* createTemplateLiteral(const JSTokenLocation& location, TemplateStringListNode* templateStringList, TemplateExpressionListNode* templateExpressionList)
+ {
+ return new (m_parserArena) TemplateLiteralNode(location, templateStringList, templateExpressionList);
+ }
+
+ ExpressionNode* createTaggedTemplate(const JSTokenLocation& location, ExpressionNode* base, TemplateLiteralNode* templateLiteral, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ auto node = new (m_parserArena) TaggedTemplateNode(location, base, templateLiteral);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+#endif
+
+ ExpressionNode* createRegExp(const JSTokenLocation& location, const Identifier& pattern, const Identifier& flags, const JSTextPosition& start)
+ {
+ if (Yarr::checkSyntax(pattern.string()))
+ return 0;
+ RegExpNode* node = new (m_parserArena) RegExpNode(location, pattern, flags);
+ int size = pattern.length() + 2; // + 2 for the two /'s
+ JSTextPosition end = start + size;
+ setExceptionLocation(node, start, end, end);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(const JSTokenLocation& location, ExpressionNode* expr, ArgumentsNode* arguments, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ NewExprNode* node = new (m_parserArena) NewExprNode(location, expr, arguments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ NewExprNode* node = new (m_parserArena) NewExprNode(location, expr);
+ setExceptionLocation(node, start, end, end);
+ return node;
+ }
+
+ ExpressionNode* createConditionalExpr(const JSTokenLocation& location, ExpressionNode* condition, ExpressionNode* lhs, ExpressionNode* rhs)
+ {
+ return new (m_parserArena) ConditionalNode(location, condition, lhs, rhs);
+ }
+
+ ExpressionNode* createAssignResolve(const JSTokenLocation& location, const Identifier& ident, ExpressionNode* rhs, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end, AssignmentContext assignmentContext)
+ {
+ if (rhs->isFuncExprNode())
+ static_cast<FuncExprNode*>(rhs)->metadata()->setInferredName(ident);
+ AssignResolveNode* node = new (m_parserArena) AssignResolveNode(location, ident, rhs, assignmentContext);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ ClassExprNode* createClassExpr(const JSTokenLocation& location, const Identifier& name, ExpressionNode* constructor,
+ ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
+ {
+ return new (m_parserArena) ClassExprNode(location, name, constructor, parentClass, instanceMethods, staticMethods);
+ }
+#endif
+
+ ExpressionNode* createFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
+ {
+ FuncExprNode* result = new (m_parserArena) FuncExprNode(location, *functionInfo.name, functionInfo.body,
+ m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn));
+ functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ FunctionMetadataNode* createFunctionMetadata(
+ const JSTokenLocation& startLocation, const JSTokenLocation& endLocation,
+ unsigned startColumn, unsigned endColumn, int functionKeywordStart,
+ int functionNameStart, int parametersStart, bool inStrictContext,
+ ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode)
+ {
+ return new (m_parserArena) FunctionMetadataNode(
+ m_parserArena, startLocation, endLocation, startColumn, endColumn,
+ functionKeywordStart, functionNameStart, parametersStart,
+ inStrictContext, constructorKind, parameterCount, mode);
+ }
+
+ ExpressionNode* createArrowFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
+ {
+ SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+
+ FuncExprNode* result = new (m_parserArena) FuncExprNode(location, *functionInfo.name, functionInfo.body, source);
+ functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ NEVER_INLINE PropertyNode* createGetterOrSetterProperty(const JSTokenLocation& location, PropertyNode::Type type, bool,
+ const Identifier* name, const ParserFunctionInfo<ASTBuilder>& functionInfo, SuperBinding superBinding)
+ {
+ ASSERT(name);
+ functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+ functionInfo.body->setInferredName(*name);
+ SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+ FuncExprNode* funcExpr = new (m_parserArena) FuncExprNode(location, m_vm->propertyNames->nullIdentifier, functionInfo.body, source);
+ return new (m_parserArena) PropertyNode(*name, funcExpr, type, PropertyNode::Unknown, superBinding);
+ }
+
+ NEVER_INLINE PropertyNode* createGetterOrSetterProperty(VM* vm, ParserArena& parserArena, const JSTokenLocation& location, PropertyNode::Type type, bool,
+ double name, const ParserFunctionInfo<ASTBuilder>& functionInfo, SuperBinding superBinding)
+ {
+ functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+ const Identifier& ident = parserArena.identifierArena().makeNumericIdentifier(vm, name);
+ SourceCode source = m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn);
+ FuncExprNode* funcExpr = new (m_parserArena) FuncExprNode(location, vm->propertyNames->nullIdentifier, functionInfo.body, source);
+ return new (m_parserArena) PropertyNode(ident, funcExpr, type, PropertyNode::Unknown, superBinding);
+ }
+
+ ArgumentsNode* createArguments() { return new (m_parserArena) ArgumentsNode(); }
+ ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_parserArena) ArgumentsNode(args); }
+ ArgumentListNode* createArgumentsList(const JSTokenLocation& location, ExpressionNode* arg) { return new (m_parserArena) ArgumentListNode(location, arg); }
+ ArgumentListNode* createArgumentsList(const JSTokenLocation& location, ArgumentListNode* args, ExpressionNode* arg) { return new (m_parserArena) ArgumentListNode(location, args, arg); }
+
+ PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool, SuperBinding superBinding = SuperBinding::NotNeeded)
+ {
+ if (node->isFuncExprNode())
+ static_cast<FuncExprNode*>(node)->metadata()->setInferredName(*propertyName);
+ return new (m_parserArena) PropertyNode(*propertyName, node, type, putType, superBinding);
+ }
+ PropertyNode* createProperty(VM* vm, ParserArena& parserArena, double propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool)
+ {
+ return new (m_parserArena) PropertyNode(parserArena.identifierArena().makeNumericIdentifier(vm, propertyName), node, type, putType);
+ }
+ PropertyNode* createProperty(ExpressionNode* propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool) { return new (m_parserArena) PropertyNode(propertyName, node, type, putType); }
+ PropertyListNode* createPropertyList(const JSTokenLocation& location, PropertyNode* property) { return new (m_parserArena) PropertyListNode(location, property); }
+ PropertyListNode* createPropertyList(const JSTokenLocation& location, PropertyNode* property, PropertyListNode* tail) { return new (m_parserArena) PropertyListNode(location, property, tail); }
+
+ ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_parserArena) ElementNode(elisions, expr); }
+ ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_parserArena) ElementNode(elems, elisions, expr); }
+
+ FormalParameterList createFormalParameterList() { return new (m_parserArena) FunctionParameters(); }
+ void appendParameter(FormalParameterList list, DestructuringPattern pattern, ExpressionNode* defaultValue)
+ {
+ list->append(pattern, defaultValue);
+ }
+
+ CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_parserArena) CaseClauseNode(expr, statements); }
+ ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_parserArena) ClauseListNode(clause); }
+ ClauseListNode* createClauseList(ClauseListNode* tail, CaseClauseNode* clause) { return new (m_parserArena) ClauseListNode(tail, clause); }
+
+ StatementNode* createFuncDeclStatement(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
+ {
+ FuncDeclNode* decl = new (m_parserArena) FuncDeclNode(location, *functionInfo.name, functionInfo.body,
+ m_sourceCode->subExpression(functionInfo.startOffset, functionInfo.endOffset, functionInfo.startLine, functionInfo.bodyStartColumn));
+ if (*functionInfo.name == m_vm->propertyNames->arguments)
+ usesArguments();
+ m_scope.m_funcDeclarations.append(decl->metadata());
+ functionInfo.body->setLoc(functionInfo.startLine, functionInfo.endLine, location.startOffset, location.lineStartOffset);
+ return decl;
+ }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ StatementNode* createClassDeclStatement(const JSTokenLocation& location, ClassExprNode* classExpression,
+ const JSTextPosition& classStart, const JSTextPosition& classEnd, unsigned startLine, unsigned endLine)
+ {
+ ExpressionNode* assign = createAssignResolve(location, classExpression->name(), classExpression, classStart, classStart + 1, classEnd, AssignmentContext::DeclarationStatement);
+ ClassDeclNode* decl = new (m_parserArena) ClassDeclNode(location, assign);
+ decl->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return decl;
+ }
+#endif
+
+ StatementNode* createBlockStatement(const JSTokenLocation& location, JSC::SourceElements* elements, int startLine, int endLine, VariableEnvironment& lexicalVariables)
+ {
+ BlockNode* block = new (m_parserArena) BlockNode(location, elements, lexicalVariables);
+ block->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return block;
+ }
+
+ StatementNode* createExprStatement(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, int end)
+ {
+ ExprStatementNode* result = new (m_parserArena) ExprStatementNode(location, expr);
+ result->setLoc(start.line, end, start.offset, start.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createIfStatement(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
+ {
+ IfElseNode* result = new (m_parserArena) IfElseNode(location, condition, trueBlock, falseBlock);
+ result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createForLoop(const JSTokenLocation& location, ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, int start, int end, VariableEnvironment& lexicalVariables)
+ {
+ ForNode* result = new (m_parserArena) ForNode(location, initializer, condition, iter, statements, lexicalVariables);
+ result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createForInLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+ {
+ ForInNode* result = new (m_parserArena) ForInNode(location, lhs, iter, statements, lexicalVariables);
+ result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+ setExceptionLocation(result, eStart, eDivot, eEnd);
+ return result;
+ }
+
+ StatementNode* createForInLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+ {
+ auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
+ return createForInLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
+ }
+
+ StatementNode* createForOfLoop(const JSTokenLocation& location, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+ {
+ ForOfNode* result = new (m_parserArena) ForOfNode(location, lhs, iter, statements, lexicalVariables);
+ result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+ setExceptionLocation(result, eStart, eDivot, eEnd);
+ return result;
+ }
+
+ StatementNode* createForOfLoop(const JSTokenLocation& location, DestructuringPatternNode* pattern, ExpressionNode* iter, StatementNode* statements, const JSTextPosition& eStart, const JSTextPosition& eDivot, const JSTextPosition& eEnd, int start, int end, VariableEnvironment& lexicalVariables)
+ {
+ auto lexpr = new (m_parserArena) DestructuringAssignmentNode(location, pattern, 0);
+ return createForOfLoop(location, lexpr, iter, statements, eStart, eDivot, eEnd, start, end, lexicalVariables);
+ }
+
+ bool isBindingNode(const DestructuringPattern& pattern)
+ {
+ return pattern->isBindingNode();
+ }
+
+ StatementNode* createEmptyStatement(const JSTokenLocation& location) { return new (m_parserArena) EmptyStatementNode(location); }
+
+ StatementNode* createDeclarationStatement(const JSTokenLocation& location, ExpressionNode* expr, int start, int end)
+ {
+ StatementNode* result;
+ result = new (m_parserArena) DeclarationStatement(location, expr);
+ result->setLoc(start, end, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ ExpressionNode* createEmptyVarExpression(const JSTokenLocation& location, const Identifier& identifier)
+ {
+ return new (m_parserArena) EmptyVarExpression(location, identifier);
+ }
+
+ ExpressionNode* createEmptyLetExpression(const JSTokenLocation& location, const Identifier& identifier)
+ {
+ return new (m_parserArena) EmptyLetExpression(location, identifier);
+ }
+
+ StatementNode* createReturnStatement(const JSTokenLocation& location, ExpressionNode* expression, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ ReturnNode* result = new (m_parserArena) ReturnNode(location, expression);
+ setExceptionLocation(result, start, end, end);
+ result->setLoc(start.line, end.line, start.offset, start.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(const JSTokenLocation& location, const Identifier* ident, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ BreakNode* result = new (m_parserArena) BreakNode(location, *ident);
+ setExceptionLocation(result, start, end, end);
+ result->setLoc(start.line, end.line, start.offset, start.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(const JSTokenLocation& location, const Identifier* ident, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ ContinueNode* result = new (m_parserArena) ContinueNode(location, *ident);
+ setExceptionLocation(result, start, end, end);
+ result->setLoc(start.line, end.line, start.offset, start.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createTryStatement(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier* ident, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine, VariableEnvironment& catchEnvironment)
+ {
+ TryNode* result = new (m_parserArena) TryNode(location, tryBlock, *ident, catchBlock, catchEnvironment, finallyBlock);
+ if (catchBlock)
+ usesCatch();
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createSwitchStatement(const JSTokenLocation& location, ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine, VariableEnvironment& lexicalVariables)
+ {
+ CaseBlockNode* cases = new (m_parserArena) CaseBlockNode(firstClauses, defaultClause, secondClauses);
+ SwitchNode* result = new (m_parserArena) SwitchNode(location, expr, cases, lexicalVariables);
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createWhileStatement(const JSTokenLocation& location, ExpressionNode* expr, StatementNode* statement, int startLine, int endLine)
+ {
+ WhileNode* result = new (m_parserArena) WhileNode(location, expr, statement);
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createDoWhileStatement(const JSTokenLocation& location, StatementNode* statement, ExpressionNode* expr, int startLine, int endLine)
+ {
+ DoWhileNode* result = new (m_parserArena) DoWhileNode(location, statement, expr);
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createLabelStatement(const JSTokenLocation& location, const Identifier* ident, StatementNode* statement, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ LabelNode* result = new (m_parserArena) LabelNode(location, *ident, statement);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createWithStatement(const JSTokenLocation& location, ExpressionNode* expr, StatementNode* statement, unsigned start, const JSTextPosition& end, unsigned startLine, unsigned endLine)
+ {
+ usesWith();
+ WithNode* result = new (m_parserArena) WithNode(location, expr, statement, end, end - start);
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ StatementNode* createThrowStatement(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, const JSTextPosition& end)
+ {
+ ThrowNode* result = new (m_parserArena) ThrowNode(location, expr);
+ result->setLoc(start.line, end.line, start.offset, start.lineStartOffset);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createDebugger(const JSTokenLocation& location, int startLine, int endLine)
+ {
+ DebuggerStatementNode* result = new (m_parserArena) DebuggerStatementNode(location);
+ result->setLoc(startLine, endLine, location.startOffset, location.lineStartOffset);
+ return result;
+ }
+
+ ModuleNameNode* createModuleName(const JSTokenLocation& location, const Identifier& moduleName)
+ {
+ return new (m_parserArena) ModuleNameNode(location, moduleName);
+ }
+
+ ImportSpecifierNode* createImportSpecifier(const JSTokenLocation& location, const Identifier& importedName, const Identifier& localName)
+ {
+ return new (m_parserArena) ImportSpecifierNode(location, importedName, localName);
+ }
+
+ ImportSpecifierListNode* createImportSpecifierList()
+ {
+ return new (m_parserArena) ImportSpecifierListNode();
+ }
+
+ void appendImportSpecifier(ImportSpecifierListNode* specifierList, ImportSpecifierNode* specifier)
+ {
+ specifierList->append(specifier);
+ }
+
+ StatementNode* createImportDeclaration(const JSTokenLocation& location, ImportSpecifierListNode* importSpecifierList, ModuleNameNode* moduleName)
+ {
+ return new (m_parserArena) ImportDeclarationNode(location, importSpecifierList, moduleName);
+ }
+
+ StatementNode* createExportAllDeclaration(const JSTokenLocation& location, ModuleNameNode* moduleName)
+ {
+ return new (m_parserArena) ExportAllDeclarationNode(location, moduleName);
+ }
+
+ StatementNode* createExportDefaultDeclaration(const JSTokenLocation& location, StatementNode* declaration, const Identifier& localName)
+ {
+ return new (m_parserArena) ExportDefaultDeclarationNode(location, declaration, localName);
+ }
+
+ StatementNode* createExportLocalDeclaration(const JSTokenLocation& location, StatementNode* declaration)
+ {
+ return new (m_parserArena) ExportLocalDeclarationNode(location, declaration);
+ }
+
+ StatementNode* createExportNamedDeclaration(const JSTokenLocation& location, ExportSpecifierListNode* exportSpecifierList, ModuleNameNode* moduleName)
+ {
+ return new (m_parserArena) ExportNamedDeclarationNode(location, exportSpecifierList, moduleName);
+ }
+
+ ExportSpecifierNode* createExportSpecifier(const JSTokenLocation& location, const Identifier& localName, const Identifier& exportedName)
+ {
+ return new (m_parserArena) ExportSpecifierNode(location, localName, exportedName);
+ }
+
+ ExportSpecifierListNode* createExportSpecifierList()
+ {
+ return new (m_parserArena) ExportSpecifierListNode();
+ }
+
+ void appendExportSpecifier(ExportSpecifierListNode* specifierList, ExportSpecifierNode* specifier)
+ {
+ specifierList->append(specifier);
+ }
+
+ void appendStatement(JSC::SourceElements* elements, JSC::StatementNode* statement)
+ {
+ elements->append(statement);
+ }
+
+ CommaNode* createCommaExpr(const JSTokenLocation& location, ExpressionNode* node)
+ {
+ return new (m_parserArena) CommaNode(location, node);
+ }
+
+ CommaNode* appendToCommaExpr(const JSTokenLocation& location, ExpressionNode*, ExpressionNode* tail, ExpressionNode* next)
+ {
+ ASSERT(tail->isCommaNode());
+ CommaNode* newTail = new (m_parserArena) CommaNode(location, next);
+ static_cast<CommaNode*>(tail)->setNext(newTail);
+ return newTail;
+ }
+
+ int evalCount() const { return m_evalCount; }
+
+ void appendBinaryExpressionInfo(int& operandStackDepth, ExpressionNode* current, const JSTextPosition& exprStart, const JSTextPosition& lhs, const JSTextPosition& rhs, bool hasAssignments)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(current, BinaryOpInfo(exprStart, lhs, rhs, hasAssignments)));
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth)
+ {
+ operatorStackDepth--;
+ m_binaryOperatorStack.removeLast();
+ }
+ bool operatorStackHasHigherPrecedence(int&, int precedence)
+ {
+ return precedence <= m_binaryOperatorStack.last().second;
+ }
+ const BinaryOperand& getFromOperandStack(int i) { return m_binaryOperandStack[m_binaryOperandStack.size() + i]; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount)
+ {
+ operandStackDepth -= amount;
+ ASSERT(operandStackDepth >= 0);
+ m_binaryOperandStack.resize(m_binaryOperandStack.size() - amount);
+ }
+ void appendBinaryOperation(const JSTokenLocation& location, int& operandStackDepth, int&, const BinaryOperand& lhs, const BinaryOperand& rhs)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(makeBinaryNode(location, m_binaryOperatorStack.last().first, lhs, rhs), BinaryOpInfo(lhs.second, rhs.second)));
+ }
+ void operatorStackAppend(int& operatorStackDepth, int op, int precedence)
+ {
+ operatorStackDepth++;
+ m_binaryOperatorStack.append(std::make_pair(op, precedence));
+ }
+ ExpressionNode* popOperandStack(int&)
+ {
+ ExpressionNode* result = m_binaryOperandStack.last().first;
+ m_binaryOperandStack.removeLast();
+ return result;
+ }
+
+ void appendUnaryToken(int& tokenStackDepth, int type, const JSTextPosition& start)
+ {
+ tokenStackDepth++;
+ m_unaryTokenStack.append(std::make_pair(type, start));
+ }
+
+ int unaryTokenStackLastType(int&)
+ {
+ return m_unaryTokenStack.last().first;
+ }
+
+ const JSTextPosition& unaryTokenStackLastStart(int&)
+ {
+ return m_unaryTokenStack.last().second;
+ }
+
+ void unaryTokenStackRemoveLast(int& tokenStackDepth)
+ {
+ tokenStackDepth--;
+ m_unaryTokenStack.removeLast();
+ }
+
+ void assignmentStackAppend(int& assignmentStackDepth, ExpressionNode* node, const JSTextPosition& start, const JSTextPosition& divot, int assignmentCount, Operator op)
+ {
+ assignmentStackDepth++;
+ ASSERT(start.offset >= start.lineStartOffset);
+ ASSERT(divot.offset >= divot.lineStartOffset);
+ m_assignmentInfoStack.append(AssignmentInfo(node, start, divot, assignmentCount, op));
+ }
+
+ ExpressionNode* createAssignment(const JSTokenLocation& location, int& assignmentStackDepth, ExpressionNode* rhs, int initialAssignmentCount, int currentAssignmentCount, const JSTextPosition& lastTokenEnd)
+ {
+ AssignmentInfo& info = m_assignmentInfoStack.last();
+ ExpressionNode* result = makeAssignNode(location, info.m_node, info.m_op, rhs, info.m_initAssignments != initialAssignmentCount, info.m_initAssignments != currentAssignmentCount, info.m_start, info.m_divot + 1, lastTokenEnd);
+ m_assignmentInfoStack.removeLast();
+ assignmentStackDepth--;
+ return result;
+ }
+
+ const Identifier* getName(const Property& property) const { return property->name(); }
+ PropertyNode::Type getType(const Property& property) const { return property->type(); }
+
+ bool isResolve(ExpressionNode* expr) const { return expr->isResolveNode(); }
+
+ ExpressionNode* createDestructuringAssignment(const JSTokenLocation& location, DestructuringPattern pattern, ExpressionNode* initializer)
+ {
+ return new (m_parserArena) DestructuringAssignmentNode(location, pattern, initializer);
+ }
+
+ ArrayPattern createArrayPattern(const JSTokenLocation&)
+ {
+ return new (m_parserArena) ArrayPatternNode();
+ }
+
+ void appendArrayPatternSkipEntry(ArrayPattern node, const JSTokenLocation& location)
+ {
+ node->appendIndex(ArrayPatternNode::BindingType::Elision, location, 0, nullptr);
+ }
+
+ void appendArrayPatternEntry(ArrayPattern node, const JSTokenLocation& location, DestructuringPattern pattern, ExpressionNode* defaultValue)
+ {
+ node->appendIndex(ArrayPatternNode::BindingType::Element, location, pattern, defaultValue);
+ }
+
+ void appendArrayPatternRestEntry(ArrayPattern node, const JSTokenLocation& location, DestructuringPattern pattern)
+ {
+ node->appendIndex(ArrayPatternNode::BindingType::RestElement, location, pattern, nullptr);
+ }
+
+ void finishArrayPattern(ArrayPattern node, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd)
+ {
+ setExceptionLocation(node, divotStart, divot, divotEnd);
+ }
+
+ ObjectPattern createObjectPattern(const JSTokenLocation&)
+ {
+ return new (m_parserArena) ObjectPatternNode();
+ }
+
+ void appendObjectPatternEntry(ObjectPattern node, const JSTokenLocation& location, bool wasString, const Identifier& identifier, DestructuringPattern pattern, ExpressionNode* defaultValue)
+ {
+ node->appendEntry(location, identifier, wasString, pattern, defaultValue);
+ }
+
+ BindingPattern createBindingLocation(const JSTokenLocation&, const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end, AssignmentContext context)
+ {
+ return new (m_parserArena) BindingNode(boundProperty, start, end, context);
+ }
+
+ void setEndOffset(Node* node, int offset)
+ {
+ node->setEndOffset(offset);
+ }
+
+ int endOffset(Node* node)
+ {
+ return node->endOffset();
+ }
+
+ void setStartOffset(CaseClauseNode* node, int offset)
+ {
+ node->setStartOffset(offset);
+ }
+
+ void setStartOffset(Node* node, int offset)
+ {
+ node->setStartOffset(offset);
+ }
+
+private:
+ struct Scope {
+ Scope()
+ : m_features(0)
+ , m_numConstants(0)
+ {
+ }
+ DeclarationStacks::FunctionStack m_funcDeclarations;
+ int m_features;
+ int m_numConstants;
+ };
+
+ static void setExceptionLocation(ThrowableExpressionData* node, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd)
+ {
+ ASSERT(divot.offset >= divot.lineStartOffset);
+ node->setExceptionSourceCode(divot, divotStart, divotEnd);
+ }
+
+ void incConstants() { m_scope.m_numConstants++; }
+ void usesThis() { m_scope.m_features |= ThisFeature; }
+ void usesCatch() { m_scope.m_features |= CatchFeature; }
+ void usesArguments() { m_scope.m_features |= ArgumentsFeature; }
+ void usesWith() { m_scope.m_features |= WithFeature; }
+ void usesEval()
+ {
+ m_evalCount++;
+ m_scope.m_features |= EvalFeature;
+ }
+ ExpressionNode* createIntegerLikeNumber(const JSTokenLocation& location, double d)
+ {
+ return new (m_parserArena) IntegerNode(location, d);
+ }
+ ExpressionNode* createDoubleLikeNumber(const JSTokenLocation& location, double d)
+ {
+ return new (m_parserArena) DoubleNode(location, d);
+ }
+ ExpressionNode* createNumberFromBinaryOperation(const JSTokenLocation& location, double value, const NumberNode& originalNodeA, const NumberNode& originalNodeB)
+ {
+ if (originalNodeA.isIntegerNode() && originalNodeB.isIntegerNode())
+ return createIntegerLikeNumber(location, value);
+ return createDoubleLikeNumber(location, value);
+ }
+ ExpressionNode* createNumberFromUnaryOperation(const JSTokenLocation& location, double value, const NumberNode& originalNode)
+ {
+ if (originalNode.isIntegerNode())
+ return createIntegerLikeNumber(location, value);
+ return createDoubleLikeNumber(location, value);
+ }
+
+ VM* m_vm;
+ ParserArena& m_parserArena;
+ SourceCode* m_sourceCode;
+ Scope m_scope;
+ Vector<BinaryOperand, 10, UnsafeVectorOverflow> m_binaryOperandStack;
+ Vector<AssignmentInfo, 10, UnsafeVectorOverflow> m_assignmentInfoStack;
+ Vector<std::pair<int, int>, 10, UnsafeVectorOverflow> m_binaryOperatorStack;
+ Vector<std::pair<int, JSTextPosition>, 10, UnsafeVectorOverflow> m_unaryTokenStack;
+ int m_evalCount;
+};
+
+ExpressionNode* ASTBuilder::makeTypeOfNode(const JSTokenLocation& location, ExpressionNode* expr)
+{
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_parserArena) TypeOfResolveNode(location, resolve->identifier());
+ }
+ return new (m_parserArena) TypeOfValueNode(location, expr);
+}
+
+ExpressionNode* ASTBuilder::makeDeleteNode(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+{
+ if (!expr->isLocation())
+ return new (m_parserArena) DeleteValueNode(location, expr);
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_parserArena) DeleteResolveNode(location, resolve->identifier(), divot, start, end);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ return new (m_parserArena) DeleteBracketNode(location, bracket->base(), bracket->subscript(), divot, start, end);
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ return new (m_parserArena) DeleteDotNode(location, dot->base(), dot->identifier(), divot, start, end);
+}
+
+ExpressionNode* ASTBuilder::makeNegateNode(const JSTokenLocation& location, ExpressionNode* n)
+{
+ if (n->isNumber()) {
+ const NumberNode& numberNode = static_cast<const NumberNode&>(*n);
+ return createNumberFromUnaryOperation(location, -numberNode.value(), numberNode);
+ }
+
+ return new (m_parserArena) NegateNode(location, n);
+}
+
+ExpressionNode* ASTBuilder::makeBitwiseNotNode(const JSTokenLocation& location, ExpressionNode* expr)
+{
+ if (expr->isNumber())
+ return createIntegerLikeNumber(location, ~toInt32(static_cast<NumberNode*>(expr)->value()));
+ return new (m_parserArena) BitwiseNotNode(location, expr);
+}
+
+ExpressionNode* ASTBuilder::makeMultNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createNumberFromBinaryOperation(location, numberExpr1.value() * numberExpr2.value(), numberExpr1, numberExpr2);
+ }
+
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new (m_parserArena) UnaryPlusNode(location, expr2);
+
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new (m_parserArena) UnaryPlusNode(location, expr1);
+
+ return new (m_parserArena) MultNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeDivNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ double result = numberExpr1.value() / numberExpr2.value();
+ if (static_cast<int64_t>(result) == result)
+ return createNumberFromBinaryOperation(location, result, numberExpr1, numberExpr2);
+ return createDoubleLikeNumber(location, result);
+ }
+ return new (m_parserArena) DivNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeModNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, fmod(numberExpr1.value(), numberExpr2.value()));
+ }
+ return new (m_parserArena) ModNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeAddNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createNumberFromBinaryOperation(location, numberExpr1.value() + numberExpr2.value(), numberExpr1, numberExpr2);
+ }
+ return new (m_parserArena) AddNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeSubNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createNumberFromBinaryOperation(location, numberExpr1.value() - numberExpr2.value(), numberExpr1, numberExpr2);
+ }
+ return new (m_parserArena) SubNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeLeftShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) << (toUInt32(numberExpr2.value()) & 0x1f));
+ }
+ return new (m_parserArena) LeftShiftNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeRightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) >> (toUInt32(numberExpr2.value()) & 0x1f));
+ }
+ return new (m_parserArena) RightShiftNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeURightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toUInt32(numberExpr1.value()) >> (toUInt32(numberExpr2.value()) & 0x1f));
+ }
+ return new (m_parserArena) UnsignedRightShiftNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) | toInt32(numberExpr2.value()));
+ }
+ return new (m_parserArena) BitOrNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitAndNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) & toInt32(numberExpr2.value()));
+ }
+ return new (m_parserArena) BitAndNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitXOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber()) {
+ const NumberNode& numberExpr1 = static_cast<NumberNode&>(*expr1);
+ const NumberNode& numberExpr2 = static_cast<NumberNode&>(*expr2);
+ return createIntegerLikeNumber(location, toInt32(numberExpr1.value()) ^ toInt32(numberExpr2.value()));
+ }
+ return new (m_parserArena) BitXOrNode(location, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeFunctionCallNode(const JSTokenLocation& location, ExpressionNode* func, ArgumentsNode* args, const JSTextPosition& divotStart, const JSTextPosition& divot, const JSTextPosition& divotEnd)
+{
+ ASSERT(divot.offset >= divot.lineStartOffset);
+ if (!func->isLocation())
+ return new (m_parserArena) FunctionCallValueNode(location, func, args, divot, divotStart, divotEnd);
+ if (func->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(func);
+ const Identifier& identifier = resolve->identifier();
+ if (identifier == m_vm->propertyNames->eval) {
+ usesEval();
+ return new (m_parserArena) EvalFunctionCallNode(location, args, divot, divotStart, divotEnd);
+ }
+ if (BytecodeIntrinsicNode::EmitterType emitter = m_vm->propertyNames->bytecodeIntrinsicRegistry().lookup(identifier))
+ return new (m_parserArena) BytecodeIntrinsicNode(location, emitter, identifier, args, divot, divotStart, divotEnd);
+ return new (m_parserArena) FunctionCallResolveNode(location, identifier, args, divot, divotStart, divotEnd);
+ }
+ if (func->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
+ FunctionCallBracketNode* node = new (m_parserArena) FunctionCallBracketNode(location, bracket->base(), bracket->subscript(), bracket->subscriptHasAssignments(), args, divot, divotStart, divotEnd);
+ node->setSubexpressionInfo(bracket->divot(), bracket->divotEnd().offset);
+ return node;
+ }
+ ASSERT(func->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
+ FunctionCallDotNode* node;
+ if (dot->identifier() == m_vm->propertyNames->builtinNames().callPublicName() || dot->identifier() == m_vm->propertyNames->builtinNames().callPrivateName())
+ node = new (m_parserArena) CallFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
+ else if (dot->identifier() == m_vm->propertyNames->builtinNames().applyPublicName() || dot->identifier() == m_vm->propertyNames->builtinNames().applyPrivateName())
+ node = new (m_parserArena) ApplyFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
+ else
+ node = new (m_parserArena) FunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
+ node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makeBinaryNode(const JSTokenLocation& location, int token, std::pair<ExpressionNode*, BinaryOpInfo> lhs, std::pair<ExpressionNode*, BinaryOpInfo> rhs)
+{
+ switch (token) {
+ case OR:
+ return new (m_parserArena) LogicalOpNode(location, lhs.first, rhs.first, OpLogicalOr);
+
+ case AND:
+ return new (m_parserArena) LogicalOpNode(location, lhs.first, rhs.first, OpLogicalAnd);
+
+ case BITOR:
+ return makeBitOrNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITXOR:
+ return makeBitXOrNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITAND:
+ return makeBitAndNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case EQEQ:
+ return new (m_parserArena) EqualNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case NE:
+ return new (m_parserArena) NotEqualNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STREQ:
+ return new (m_parserArena) StrictEqualNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STRNEQ:
+ return new (m_parserArena) NotStrictEqualNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LT:
+ return new (m_parserArena) LessNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GT:
+ return new (m_parserArena) GreaterNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LE:
+ return new (m_parserArena) LessEqNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GE:
+ return new (m_parserArena) GreaterEqNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case INSTANCEOF: {
+ InstanceOfNode* node = new (m_parserArena) InstanceOfNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case INTOKEN: {
+ InNode* node = new (m_parserArena) InNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case LSHIFT:
+ return makeLeftShiftNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case RSHIFT:
+ return makeRightShiftNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case URSHIFT:
+ return makeURightShiftNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case PLUS:
+ return makeAddNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MINUS:
+ return makeSubNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case TIMES:
+ return makeMultNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case DIVIDE:
+ return makeDivNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MOD:
+ return makeModNode(location, lhs.first, rhs.first, rhs.second.hasAssignment);
+ }
+ CRASH();
+ return 0;
+}
+
+ExpressionNode* ASTBuilder::makeAssignNode(const JSTokenLocation& location, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+{
+ if (!loc->isLocation())
+ return new (m_parserArena) AssignErrorNode(location, divot, start, end);
+
+ if (loc->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(loc);
+ if (op == OpEqual) {
+ if (expr->isFuncExprNode())
+ static_cast<FuncExprNode*>(expr)->metadata()->setInferredName(resolve->identifier());
+ AssignResolveNode* node = new (m_parserArena) AssignResolveNode(location, resolve->identifier(), expr, AssignmentContext::AssignmentExpression);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+ return new (m_parserArena) ReadModifyResolveNode(location, resolve->identifier(), op, expr, exprHasAssignments, divot, start, end);
+ }
+ if (loc->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new (m_parserArena) AssignBracketNode(location, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), start, end);
+ ReadModifyBracketNode* node = new (m_parserArena) ReadModifyBracketNode(location, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, start, end);
+ node->setSubexpressionInfo(bracket->divot(), bracket->divotEnd().offset);
+ return node;
+ }
+ ASSERT(loc->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
+ if (op == OpEqual) {
+ if (expr->isFuncExprNode())
+ static_cast<FuncExprNode*>(expr)->metadata()->setInferredName(dot->identifier());
+ return new (m_parserArena) AssignDotNode(location, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), start, end);
+ }
+
+ ReadModifyDotNode* node = new (m_parserArena) ReadModifyDotNode(location, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, start, end);
+ node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePrefixNode(const JSTokenLocation& location, ExpressionNode* expr, Operator op, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+{
+ return new (m_parserArena) PrefixNode(location, expr, op, divot, start, end);
+}
+
+ExpressionNode* ASTBuilder::makePostfixNode(const JSTokenLocation& location, ExpressionNode* expr, Operator op, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+{
+ return new (m_parserArena) PostfixNode(location, expr, op, divot, start, end);
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/Keywords.table b/Source/JavaScriptCore/parser/Keywords.table
new file mode 100644
index 000000000..e2ba528a4
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Keywords.table
@@ -0,0 +1,57 @@
+# Main keywords.
+@begin mainTable 47
+
+# Types.
+null NULLTOKEN
+true TRUETOKEN
+false FALSETOKEN
+
+# Keywords.
+break BREAK
+case CASE
+catch CATCH
+class CLASSTOKEN
+const CONSTTOKEN
+default DEFAULT
+extends EXTENDS
+finally FINALLY
+for FOR
+instanceof INSTANCEOF
+new NEW
+var VAR
+let LET
+continue CONTINUE
+function FUNCTION
+return RETURN
+void VOIDTOKEN
+delete DELETETOKEN
+if IF
+this THISTOKEN
+do DO
+while WHILE
+else ELSE
+in INTOKEN
+super SUPER
+switch SWITCH
+throw THROW
+try TRY
+typeof TYPEOF
+with WITH
+debugger DEBUGGER
+
+# Reserved for future use.
+enum RESERVED
+export EXPORT
+import IMPORT
+
+# Reserved for future use in strict code.
+implements RESERVED_IF_STRICT
+interface RESERVED_IF_STRICT
+package RESERVED_IF_STRICT
+private RESERVED_IF_STRICT
+protected RESERVED_IF_STRICT
+public RESERVED_IF_STRICT
+static RESERVED_IF_STRICT
+yield RESERVED_IF_STRICT
+
+@end
diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp
new file mode 100644
index 000000000..c4db1618a
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.cpp
@@ -0,0 +1,2417 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012, 2013 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
+ * Copyright (C) 2012 Mathias Bynens (mathias@qiwi.be)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Lexer.h"
+
+#include "JSFunctionInlines.h"
+
+#include "BuiltinNames.h"
+#include "JSGlobalObjectFunctions.h"
+#include "Identifier.h"
+#include "Nodes.h"
+#include "JSCInlines.h"
+#include <wtf/dtoa.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+
+#include "KeywordLookup.h"
+#include "Lexer.lut.h"
+#include "Parser.h"
+
+namespace JSC {
+
+bool isLexerKeyword(const Identifier& identifier)
+{
+ return JSC::mainTable.entry(identifier);
+}
+
+enum CharacterType {
+ // Types for the main switch
+
+ // The first three types are fixed, and also used for identifying
+ // ASCII alpha and alphanumeric characters (see isIdentStart and isIdentPart).
+ CharacterIdentifierStart,
+ CharacterZero,
+ CharacterNumber,
+
+ CharacterInvalid,
+ CharacterLineTerminator,
+ CharacterExclamationMark,
+ CharacterOpenParen,
+ CharacterCloseParen,
+ CharacterOpenBracket,
+ CharacterCloseBracket,
+ CharacterComma,
+ CharacterColon,
+ CharacterQuestion,
+ CharacterTilde,
+ CharacterQuote,
+ CharacterBackQuote,
+ CharacterDot,
+ CharacterSlash,
+ CharacterBackSlash,
+ CharacterSemicolon,
+ CharacterOpenBrace,
+ CharacterCloseBrace,
+
+ CharacterAdd,
+ CharacterSub,
+ CharacterMultiply,
+ CharacterModulo,
+ CharacterAnd,
+ CharacterXor,
+ CharacterOr,
+ CharacterLess,
+ CharacterGreater,
+ CharacterEqual,
+
+ // Other types (only one so far)
+ CharacterWhiteSpace,
+ CharacterPrivateIdentifierStart
+};
+
+// 256 Latin-1 codes
+static const unsigned short typesOfLatin1Characters[256] = {
+/* 0 - Null */ CharacterInvalid,
+/* 1 - Start of Heading */ CharacterInvalid,
+/* 2 - Start of Text */ CharacterInvalid,
+/* 3 - End of Text */ CharacterInvalid,
+/* 4 - End of Transm. */ CharacterInvalid,
+/* 5 - Enquiry */ CharacterInvalid,
+/* 6 - Acknowledgment */ CharacterInvalid,
+/* 7 - Bell */ CharacterInvalid,
+/* 8 - Back Space */ CharacterInvalid,
+/* 9 - Horizontal Tab */ CharacterWhiteSpace,
+/* 10 - Line Feed */ CharacterLineTerminator,
+/* 11 - Vertical Tab */ CharacterWhiteSpace,
+/* 12 - Form Feed */ CharacterWhiteSpace,
+/* 13 - Carriage Return */ CharacterLineTerminator,
+/* 14 - Shift Out */ CharacterInvalid,
+/* 15 - Shift In */ CharacterInvalid,
+/* 16 - Data Line Escape */ CharacterInvalid,
+/* 17 - Device Control 1 */ CharacterInvalid,
+/* 18 - Device Control 2 */ CharacterInvalid,
+/* 19 - Device Control 3 */ CharacterInvalid,
+/* 20 - Device Control 4 */ CharacterInvalid,
+/* 21 - Negative Ack. */ CharacterInvalid,
+/* 22 - Synchronous Idle */ CharacterInvalid,
+/* 23 - End of Transmit */ CharacterInvalid,
+/* 24 - Cancel */ CharacterInvalid,
+/* 25 - End of Medium */ CharacterInvalid,
+/* 26 - Substitute */ CharacterInvalid,
+/* 27 - Escape */ CharacterInvalid,
+/* 28 - File Separator */ CharacterInvalid,
+/* 29 - Group Separator */ CharacterInvalid,
+/* 30 - Record Separator */ CharacterInvalid,
+/* 31 - Unit Separator */ CharacterInvalid,
+/* 32 - Space */ CharacterWhiteSpace,
+/* 33 - ! */ CharacterExclamationMark,
+/* 34 - " */ CharacterQuote,
+/* 35 - # */ CharacterInvalid,
+/* 36 - $ */ CharacterIdentifierStart,
+/* 37 - % */ CharacterModulo,
+/* 38 - & */ CharacterAnd,
+/* 39 - ' */ CharacterQuote,
+/* 40 - ( */ CharacterOpenParen,
+/* 41 - ) */ CharacterCloseParen,
+/* 42 - * */ CharacterMultiply,
+/* 43 - + */ CharacterAdd,
+/* 44 - , */ CharacterComma,
+/* 45 - - */ CharacterSub,
+/* 46 - . */ CharacterDot,
+/* 47 - / */ CharacterSlash,
+/* 48 - 0 */ CharacterZero,
+/* 49 - 1 */ CharacterNumber,
+/* 50 - 2 */ CharacterNumber,
+/* 51 - 3 */ CharacterNumber,
+/* 52 - 4 */ CharacterNumber,
+/* 53 - 5 */ CharacterNumber,
+/* 54 - 6 */ CharacterNumber,
+/* 55 - 7 */ CharacterNumber,
+/* 56 - 8 */ CharacterNumber,
+/* 57 - 9 */ CharacterNumber,
+/* 58 - : */ CharacterColon,
+/* 59 - ; */ CharacterSemicolon,
+/* 60 - < */ CharacterLess,
+/* 61 - = */ CharacterEqual,
+/* 62 - > */ CharacterGreater,
+/* 63 - ? */ CharacterQuestion,
+/* 64 - @ */ CharacterPrivateIdentifierStart,
+/* 65 - A */ CharacterIdentifierStart,
+/* 66 - B */ CharacterIdentifierStart,
+/* 67 - C */ CharacterIdentifierStart,
+/* 68 - D */ CharacterIdentifierStart,
+/* 69 - E */ CharacterIdentifierStart,
+/* 70 - F */ CharacterIdentifierStart,
+/* 71 - G */ CharacterIdentifierStart,
+/* 72 - H */ CharacterIdentifierStart,
+/* 73 - I */ CharacterIdentifierStart,
+/* 74 - J */ CharacterIdentifierStart,
+/* 75 - K */ CharacterIdentifierStart,
+/* 76 - L */ CharacterIdentifierStart,
+/* 77 - M */ CharacterIdentifierStart,
+/* 78 - N */ CharacterIdentifierStart,
+/* 79 - O */ CharacterIdentifierStart,
+/* 80 - P */ CharacterIdentifierStart,
+/* 81 - Q */ CharacterIdentifierStart,
+/* 82 - R */ CharacterIdentifierStart,
+/* 83 - S */ CharacterIdentifierStart,
+/* 84 - T */ CharacterIdentifierStart,
+/* 85 - U */ CharacterIdentifierStart,
+/* 86 - V */ CharacterIdentifierStart,
+/* 87 - W */ CharacterIdentifierStart,
+/* 88 - X */ CharacterIdentifierStart,
+/* 89 - Y */ CharacterIdentifierStart,
+/* 90 - Z */ CharacterIdentifierStart,
+/* 91 - [ */ CharacterOpenBracket,
+/* 92 - \ */ CharacterBackSlash,
+/* 93 - ] */ CharacterCloseBracket,
+/* 94 - ^ */ CharacterXor,
+/* 95 - _ */ CharacterIdentifierStart,
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+/* 96 - ` */ CharacterBackQuote,
+#else
+/* 96 - ` */ CharacterInvalid,
+#endif
+/* 97 - a */ CharacterIdentifierStart,
+/* 98 - b */ CharacterIdentifierStart,
+/* 99 - c */ CharacterIdentifierStart,
+/* 100 - d */ CharacterIdentifierStart,
+/* 101 - e */ CharacterIdentifierStart,
+/* 102 - f */ CharacterIdentifierStart,
+/* 103 - g */ CharacterIdentifierStart,
+/* 104 - h */ CharacterIdentifierStart,
+/* 105 - i */ CharacterIdentifierStart,
+/* 106 - j */ CharacterIdentifierStart,
+/* 107 - k */ CharacterIdentifierStart,
+/* 108 - l */ CharacterIdentifierStart,
+/* 109 - m */ CharacterIdentifierStart,
+/* 110 - n */ CharacterIdentifierStart,
+/* 111 - o */ CharacterIdentifierStart,
+/* 112 - p */ CharacterIdentifierStart,
+/* 113 - q */ CharacterIdentifierStart,
+/* 114 - r */ CharacterIdentifierStart,
+/* 115 - s */ CharacterIdentifierStart,
+/* 116 - t */ CharacterIdentifierStart,
+/* 117 - u */ CharacterIdentifierStart,
+/* 118 - v */ CharacterIdentifierStart,
+/* 119 - w */ CharacterIdentifierStart,
+/* 120 - x */ CharacterIdentifierStart,
+/* 121 - y */ CharacterIdentifierStart,
+/* 122 - z */ CharacterIdentifierStart,
+/* 123 - { */ CharacterOpenBrace,
+/* 124 - | */ CharacterOr,
+/* 125 - } */ CharacterCloseBrace,
+/* 126 - ~ */ CharacterTilde,
+/* 127 - Delete */ CharacterInvalid,
+/* 128 - Cc category */ CharacterInvalid,
+/* 129 - Cc category */ CharacterInvalid,
+/* 130 - Cc category */ CharacterInvalid,
+/* 131 - Cc category */ CharacterInvalid,
+/* 132 - Cc category */ CharacterInvalid,
+/* 133 - Cc category */ CharacterInvalid,
+/* 134 - Cc category */ CharacterInvalid,
+/* 135 - Cc category */ CharacterInvalid,
+/* 136 - Cc category */ CharacterInvalid,
+/* 137 - Cc category */ CharacterInvalid,
+/* 138 - Cc category */ CharacterInvalid,
+/* 139 - Cc category */ CharacterInvalid,
+/* 140 - Cc category */ CharacterInvalid,
+/* 141 - Cc category */ CharacterInvalid,
+/* 142 - Cc category */ CharacterInvalid,
+/* 143 - Cc category */ CharacterInvalid,
+/* 144 - Cc category */ CharacterInvalid,
+/* 145 - Cc category */ CharacterInvalid,
+/* 146 - Cc category */ CharacterInvalid,
+/* 147 - Cc category */ CharacterInvalid,
+/* 148 - Cc category */ CharacterInvalid,
+/* 149 - Cc category */ CharacterInvalid,
+/* 150 - Cc category */ CharacterInvalid,
+/* 151 - Cc category */ CharacterInvalid,
+/* 152 - Cc category */ CharacterInvalid,
+/* 153 - Cc category */ CharacterInvalid,
+/* 154 - Cc category */ CharacterInvalid,
+/* 155 - Cc category */ CharacterInvalid,
+/* 156 - Cc category */ CharacterInvalid,
+/* 157 - Cc category */ CharacterInvalid,
+/* 158 - Cc category */ CharacterInvalid,
+/* 159 - Cc category */ CharacterInvalid,
+/* 160 - Zs category (nbsp) */ CharacterWhiteSpace,
+/* 161 - Po category */ CharacterInvalid,
+/* 162 - Sc category */ CharacterInvalid,
+/* 163 - Sc category */ CharacterInvalid,
+/* 164 - Sc category */ CharacterInvalid,
+/* 165 - Sc category */ CharacterInvalid,
+/* 166 - So category */ CharacterInvalid,
+/* 167 - So category */ CharacterInvalid,
+/* 168 - Sk category */ CharacterInvalid,
+/* 169 - So category */ CharacterInvalid,
+/* 170 - Ll category */ CharacterIdentifierStart,
+/* 171 - Pi category */ CharacterInvalid,
+/* 172 - Sm category */ CharacterInvalid,
+/* 173 - Cf category */ CharacterInvalid,
+/* 174 - So category */ CharacterInvalid,
+/* 175 - Sk category */ CharacterInvalid,
+/* 176 - So category */ CharacterInvalid,
+/* 177 - Sm category */ CharacterInvalid,
+/* 178 - No category */ CharacterInvalid,
+/* 179 - No category */ CharacterInvalid,
+/* 180 - Sk category */ CharacterInvalid,
+/* 181 - Ll category */ CharacterIdentifierStart,
+/* 182 - So category */ CharacterInvalid,
+/* 183 - Po category */ CharacterInvalid,
+/* 184 - Sk category */ CharacterInvalid,
+/* 185 - No category */ CharacterInvalid,
+/* 186 - Ll category */ CharacterIdentifierStart,
+/* 187 - Pf category */ CharacterInvalid,
+/* 188 - No category */ CharacterInvalid,
+/* 189 - No category */ CharacterInvalid,
+/* 190 - No category */ CharacterInvalid,
+/* 191 - Po category */ CharacterInvalid,
+/* 192 - Lu category */ CharacterIdentifierStart,
+/* 193 - Lu category */ CharacterIdentifierStart,
+/* 194 - Lu category */ CharacterIdentifierStart,
+/* 195 - Lu category */ CharacterIdentifierStart,
+/* 196 - Lu category */ CharacterIdentifierStart,
+/* 197 - Lu category */ CharacterIdentifierStart,
+/* 198 - Lu category */ CharacterIdentifierStart,
+/* 199 - Lu category */ CharacterIdentifierStart,
+/* 200 - Lu category */ CharacterIdentifierStart,
+/* 201 - Lu category */ CharacterIdentifierStart,
+/* 202 - Lu category */ CharacterIdentifierStart,
+/* 203 - Lu category */ CharacterIdentifierStart,
+/* 204 - Lu category */ CharacterIdentifierStart,
+/* 205 - Lu category */ CharacterIdentifierStart,
+/* 206 - Lu category */ CharacterIdentifierStart,
+/* 207 - Lu category */ CharacterIdentifierStart,
+/* 208 - Lu category */ CharacterIdentifierStart,
+/* 209 - Lu category */ CharacterIdentifierStart,
+/* 210 - Lu category */ CharacterIdentifierStart,
+/* 211 - Lu category */ CharacterIdentifierStart,
+/* 212 - Lu category */ CharacterIdentifierStart,
+/* 213 - Lu category */ CharacterIdentifierStart,
+/* 214 - Lu category */ CharacterIdentifierStart,
+/* 215 - Sm category */ CharacterInvalid,
+/* 216 - Lu category */ CharacterIdentifierStart,
+/* 217 - Lu category */ CharacterIdentifierStart,
+/* 218 - Lu category */ CharacterIdentifierStart,
+/* 219 - Lu category */ CharacterIdentifierStart,
+/* 220 - Lu category */ CharacterIdentifierStart,
+/* 221 - Lu category */ CharacterIdentifierStart,
+/* 222 - Lu category */ CharacterIdentifierStart,
+/* 223 - Ll category */ CharacterIdentifierStart,
+/* 224 - Ll category */ CharacterIdentifierStart,
+/* 225 - Ll category */ CharacterIdentifierStart,
+/* 226 - Ll category */ CharacterIdentifierStart,
+/* 227 - Ll category */ CharacterIdentifierStart,
+/* 228 - Ll category */ CharacterIdentifierStart,
+/* 229 - Ll category */ CharacterIdentifierStart,
+/* 230 - Ll category */ CharacterIdentifierStart,
+/* 231 - Ll category */ CharacterIdentifierStart,
+/* 232 - Ll category */ CharacterIdentifierStart,
+/* 233 - Ll category */ CharacterIdentifierStart,
+/* 234 - Ll category */ CharacterIdentifierStart,
+/* 235 - Ll category */ CharacterIdentifierStart,
+/* 236 - Ll category */ CharacterIdentifierStart,
+/* 237 - Ll category */ CharacterIdentifierStart,
+/* 238 - Ll category */ CharacterIdentifierStart,
+/* 239 - Ll category */ CharacterIdentifierStart,
+/* 240 - Ll category */ CharacterIdentifierStart,
+/* 241 - Ll category */ CharacterIdentifierStart,
+/* 242 - Ll category */ CharacterIdentifierStart,
+/* 243 - Ll category */ CharacterIdentifierStart,
+/* 244 - Ll category */ CharacterIdentifierStart,
+/* 245 - Ll category */ CharacterIdentifierStart,
+/* 246 - Ll category */ CharacterIdentifierStart,
+/* 247 - Sm category */ CharacterInvalid,
+/* 248 - Ll category */ CharacterIdentifierStart,
+/* 249 - Ll category */ CharacterIdentifierStart,
+/* 250 - Ll category */ CharacterIdentifierStart,
+/* 251 - Ll category */ CharacterIdentifierStart,
+/* 252 - Ll category */ CharacterIdentifierStart,
+/* 253 - Ll category */ CharacterIdentifierStart,
+/* 254 - Ll category */ CharacterIdentifierStart,
+/* 255 - Ll category */ CharacterIdentifierStart
+};
+
+// This table provides the character that results from \X where X is the index in the table beginning
+// with SPACE. A table value of 0 means that more processing needs to be done.
+static const LChar singleCharacterEscapeValuesForASCII[128] = {
+/* 0 - Null */ 0,
+/* 1 - Start of Heading */ 0,
+/* 2 - Start of Text */ 0,
+/* 3 - End of Text */ 0,
+/* 4 - End of Transm. */ 0,
+/* 5 - Enquiry */ 0,
+/* 6 - Acknowledgment */ 0,
+/* 7 - Bell */ 0,
+/* 8 - Back Space */ 0,
+/* 9 - Horizontal Tab */ 0,
+/* 10 - Line Feed */ 0,
+/* 11 - Vertical Tab */ 0,
+/* 12 - Form Feed */ 0,
+/* 13 - Carriage Return */ 0,
+/* 14 - Shift Out */ 0,
+/* 15 - Shift In */ 0,
+/* 16 - Data Line Escape */ 0,
+/* 17 - Device Control 1 */ 0,
+/* 18 - Device Control 2 */ 0,
+/* 19 - Device Control 3 */ 0,
+/* 20 - Device Control 4 */ 0,
+/* 21 - Negative Ack. */ 0,
+/* 22 - Synchronous Idle */ 0,
+/* 23 - End of Transmit */ 0,
+/* 24 - Cancel */ 0,
+/* 25 - End of Medium */ 0,
+/* 26 - Substitute */ 0,
+/* 27 - Escape */ 0,
+/* 28 - File Separator */ 0,
+/* 29 - Group Separator */ 0,
+/* 30 - Record Separator */ 0,
+/* 31 - Unit Separator */ 0,
+/* 32 - Space */ ' ',
+/* 33 - ! */ '!',
+/* 34 - " */ '"',
+/* 35 - # */ '#',
+/* 36 - $ */ '$',
+/* 37 - % */ '%',
+/* 38 - & */ '&',
+/* 39 - ' */ '\'',
+/* 40 - ( */ '(',
+/* 41 - ) */ ')',
+/* 42 - * */ '*',
+/* 43 - + */ '+',
+/* 44 - , */ ',',
+/* 45 - - */ '-',
+/* 46 - . */ '.',
+/* 47 - / */ '/',
+/* 48 - 0 */ 0,
+/* 49 - 1 */ 0,
+/* 50 - 2 */ 0,
+/* 51 - 3 */ 0,
+/* 52 - 4 */ 0,
+/* 53 - 5 */ 0,
+/* 54 - 6 */ 0,
+/* 55 - 7 */ 0,
+/* 56 - 8 */ 0,
+/* 57 - 9 */ 0,
+/* 58 - : */ ':',
+/* 59 - ; */ ';',
+/* 60 - < */ '<',
+/* 61 - = */ '=',
+/* 62 - > */ '>',
+/* 63 - ? */ '?',
+/* 64 - @ */ '@',
+/* 65 - A */ 'A',
+/* 66 - B */ 'B',
+/* 67 - C */ 'C',
+/* 68 - D */ 'D',
+/* 69 - E */ 'E',
+/* 70 - F */ 'F',
+/* 71 - G */ 'G',
+/* 72 - H */ 'H',
+/* 73 - I */ 'I',
+/* 74 - J */ 'J',
+/* 75 - K */ 'K',
+/* 76 - L */ 'L',
+/* 77 - M */ 'M',
+/* 78 - N */ 'N',
+/* 79 - O */ 'O',
+/* 80 - P */ 'P',
+/* 81 - Q */ 'Q',
+/* 82 - R */ 'R',
+/* 83 - S */ 'S',
+/* 84 - T */ 'T',
+/* 85 - U */ 'U',
+/* 86 - V */ 'V',
+/* 87 - W */ 'W',
+/* 88 - X */ 'X',
+/* 89 - Y */ 'Y',
+/* 90 - Z */ 'Z',
+/* 91 - [ */ '[',
+/* 92 - \ */ '\\',
+/* 93 - ] */ ']',
+/* 94 - ^ */ '^',
+/* 95 - _ */ '_',
+/* 96 - ` */ '`',
+/* 97 - a */ 'a',
+/* 98 - b */ 0x08,
+/* 99 - c */ 'c',
+/* 100 - d */ 'd',
+/* 101 - e */ 'e',
+/* 102 - f */ 0x0C,
+/* 103 - g */ 'g',
+/* 104 - h */ 'h',
+/* 105 - i */ 'i',
+/* 106 - j */ 'j',
+/* 107 - k */ 'k',
+/* 108 - l */ 'l',
+/* 109 - m */ 'm',
+/* 110 - n */ 0x0A,
+/* 111 - o */ 'o',
+/* 112 - p */ 'p',
+/* 113 - q */ 'q',
+/* 114 - r */ 0x0D,
+/* 115 - s */ 's',
+/* 116 - t */ 0x09,
+/* 117 - u */ 0,
+/* 118 - v */ 0x0B,
+/* 119 - w */ 'w',
+/* 120 - x */ 0,
+/* 121 - y */ 'y',
+/* 122 - z */ 'z',
+/* 123 - { */ '{',
+/* 124 - | */ '|',
+/* 125 - } */ '}',
+/* 126 - ~ */ '~',
+/* 127 - Delete */ 0
+};
+
+template <typename T>
+Lexer<T>::Lexer(VM* vm, JSParserBuiltinMode builtinMode)
+ : m_isReparsingFunction(false)
+ , m_vm(vm)
+ , m_parsingBuiltinFunction(builtinMode == JSParserBuiltinMode::Builtin)
+{
+}
+
+static inline JSTokenType tokenTypeForIntegerLikeToken(double doubleValue)
+{
+ if ((doubleValue || !std::signbit(doubleValue)) && static_cast<int64_t>(doubleValue) == doubleValue)
+ return INTEGER;
+ return DOUBLE;
+}
+
+template <typename T>
+Lexer<T>::~Lexer()
+{
+}
+
+template <typename T>
+String Lexer<T>::invalidCharacterMessage() const
+{
+ switch (m_current) {
+ case 0:
+ return ASCIILiteral("Invalid character: '\\0'");
+ case 10:
+ return ASCIILiteral("Invalid character: '\\n'");
+ case 11:
+ return ASCIILiteral("Invalid character: '\\v'");
+ case 13:
+ return ASCIILiteral("Invalid character: '\\r'");
+ case 35:
+ return ASCIILiteral("Invalid character: '#'");
+ case 64:
+ return ASCIILiteral("Invalid character: '@'");
+ case 96:
+ return ASCIILiteral("Invalid character: '`'");
+ default:
+ return String::format("Invalid character '\\u%04u'", static_cast<unsigned>(m_current));
+ }
+}
+
+template <typename T>
+ALWAYS_INLINE const T* Lexer<T>::currentSourcePtr() const
+{
+ ASSERT(m_code <= m_codeEnd);
+ return m_code;
+}
+
+template <typename T>
+void Lexer<T>::setCode(const SourceCode& source, ParserArena* arena)
+{
+ m_arena = &arena->identifierArena();
+
+ m_lineNumber = source.firstLine();
+ m_lastToken = -1;
+
+ const String& sourceString = source.provider()->source();
+
+ if (!sourceString.isNull())
+ setCodeStart(sourceString.impl());
+ else
+ m_codeStart = 0;
+
+ m_source = &source;
+ m_sourceOffset = source.startOffset();
+ m_codeStartPlusOffset = m_codeStart + source.startOffset();
+ m_code = m_codeStartPlusOffset;
+ m_codeEnd = m_codeStart + source.endOffset();
+ m_error = false;
+ m_atLineStart = true;
+ m_lineStart = m_code;
+ m_lexErrorMessage = String();
+
+ m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
+ m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
+ m_bufferForRawTemplateString16.reserveInitialCapacity(initialReadBufferCapacity);
+
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ else
+ m_current = 0;
+ ASSERT(currentOffset() == source.startOffset());
+}
+
+template <typename T>
+template <int shiftAmount> ALWAYS_INLINE void Lexer<T>::internalShift()
+{
+ m_code += shiftAmount;
+ ASSERT(currentOffset() >= currentLineStartOffset());
+ m_current = *m_code;
+}
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::shift()
+{
+ // At one point timing showed that setting m_current to 0 unconditionally was faster than an if-else sequence.
+ m_current = 0;
+ ++m_code;
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::atEnd() const
+{
+ ASSERT(!m_current || m_code < m_codeEnd);
+ return UNLIKELY(UNLIKELY(!m_current) && m_code == m_codeEnd);
+}
+
+template <typename T>
+ALWAYS_INLINE T Lexer<T>::peek(int offset) const
+{
+ ASSERT(offset > 0 && offset < 5);
+ const T* code = m_code + offset;
+ return (code < m_codeEnd) ? *code : 0;
+}
+
+struct ParsedUnicodeEscapeValue {
+ ParsedUnicodeEscapeValue(UChar32 value)
+ : m_value(value)
+ {
+ ASSERT(isValid());
+ }
+
+ enum SpecialValueType { Incomplete = -2, Invalid = -1 };
+ ParsedUnicodeEscapeValue(SpecialValueType type)
+ : m_value(type)
+ {
+ }
+
+ bool isValid() const { return m_value >= 0; }
+ bool isIncomplete() const { return m_value == Incomplete; }
+
+ UChar32 value() const
+ {
+ ASSERT(isValid());
+ return m_value;
+ }
+
+private:
+ UChar32 m_value;
+};
+
+template<typename CharacterType> ParsedUnicodeEscapeValue Lexer<CharacterType>::parseUnicodeEscape()
+{
+ if (m_current == '{') {
+ shift();
+ UChar32 codePoint = 0;
+ do {
+ if (!isASCIIHexDigit(m_current))
+ return m_current ? ParsedUnicodeEscapeValue::Invalid : ParsedUnicodeEscapeValue::Incomplete;
+ codePoint = (codePoint << 4) | toASCIIHexValue(m_current);
+ if (codePoint > UCHAR_MAX_VALUE)
+ return ParsedUnicodeEscapeValue::Invalid;
+ shift();
+ } while (m_current != '}');
+ shift();
+ return codePoint;
+ }
+
+ auto character2 = peek(1);
+ auto character3 = peek(2);
+ auto character4 = peek(3);
+ if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4)))
+ return (m_code + 4) >= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
+ auto result = convertUnicode(m_current, character2, character3, character4);
+ shift();
+ shift();
+ shift();
+ shift();
+ return result;
+}
+
+template <typename T>
+void Lexer<T>::shiftLineTerminator()
+{
+ ASSERT(isLineTerminator(m_current));
+
+ m_positionBeforeLastNewline = currentPosition();
+ T prev = m_current;
+ shift();
+
+ // Allow both CRLF and LFCR.
+ if (prev + m_current == '\n' + '\r')
+ shift();
+
+ ++m_lineNumber;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::lastTokenWasRestrKeyword() const
+{
+ return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
+}
+
+static NEVER_INLINE bool isNonLatin1IdentStart(UChar c)
+{
+ return U_GET_GC_MASK(c) & U_GC_L_MASK;
+}
+
+static ALWAYS_INLINE bool isLatin1(LChar)
+{
+ return true;
+}
+
+static ALWAYS_INLINE bool isLatin1(UChar c)
+{
+ return c < 256;
+}
+
+static ALWAYS_INLINE bool isLatin1(UChar32 c)
+{
+ return !(c & ~0xFF);
+}
+
+static inline bool isIdentStart(LChar c)
+{
+ return typesOfLatin1Characters[c] == CharacterIdentifierStart;
+}
+
+static inline bool isIdentStart(UChar32 c)
+{
+ return isLatin1(c) ? isIdentStart(static_cast<LChar>(c)) : isNonLatin1IdentStart(c);
+}
+
+static NEVER_INLINE bool isNonLatin1IdentPart(UChar32 c)
+{
+ // FIXME: ES6 says this should be based on the Unicode property ID_Continue now instead.
+ return (U_GET_GC_MASK(c) & (U_GC_L_MASK | U_GC_MN_MASK | U_GC_MC_MASK | U_GC_ND_MASK | U_GC_PC_MASK)) || c == 0x200C || c == 0x200D;
+}
+
+static ALWAYS_INLINE bool isIdentPart(LChar c)
+{
+ // Character types are divided into two groups depending on whether they can be part of an
+ // identifier or not. Those whose type value is less or equal than CharacterNumber can be
+ // part of an identifier. (See the CharacterType definition for more details.)
+ return typesOfLatin1Characters[c] <= CharacterNumber;
+}
+
+static ALWAYS_INLINE bool isIdentPart(UChar32 c)
+{
+ return isLatin1(c) ? isIdentPart(static_cast<LChar>(c)) : isNonLatin1IdentPart(c);
+}
+
+static ALWAYS_INLINE bool isIdentPart(UChar c)
+{
+ return isIdentPart(static_cast<UChar32>(c));
+}
+
+template<typename CharacterType> ALWAYS_INLINE bool isIdentPartIncludingEscapeTemplate(const CharacterType* code, const CharacterType* codeEnd)
+{
+ if (isIdentPart(code[0]))
+ return true;
+
+ // Shortest sequence handled below is \u{0}, which is 5 characters.
+ if (!(code[0] == '\\' && codeEnd - code >= 5 && code[1] == 'u'))
+ return false;
+
+ if (code[2] == '{') {
+ UChar32 codePoint = 0;
+ const CharacterType* pointer;
+ for (pointer = &code[3]; pointer < codeEnd; ++pointer) {
+ auto digit = *pointer;
+ if (!isASCIIHexDigit(digit))
+ break;
+ codePoint = (codePoint << 4) | toASCIIHexValue(digit);
+ if (codePoint > UCHAR_MAX_VALUE)
+ return false;
+ }
+ return isIdentPart(codePoint) && pointer < codeEnd && *pointer == '}';
+ }
+
+ // Shortest sequence handled below is \uXXXX, which is 6 characters.
+ if (codeEnd - code < 6)
+ return false;
+
+ auto character1 = code[2];
+ auto character2 = code[3];
+ auto character3 = code[4];
+ auto character4 = code[5];
+ return isASCIIHexDigit(character1) && isASCIIHexDigit(character2) && isASCIIHexDigit(character3) && isASCIIHexDigit(character4)
+ && isIdentPart(Lexer<LChar>::convertUnicode(character1, character2, character3, character4));
+}
+
+static ALWAYS_INLINE bool isIdentPartIncludingEscape(const LChar* code, const LChar* codeEnd)
+{
+ return isIdentPartIncludingEscapeTemplate(code, codeEnd);
+}
+
+static ALWAYS_INLINE bool isIdentPartIncludingEscape(const UChar* code, const UChar* codeEnd)
+{
+ return isIdentPartIncludingEscapeTemplate(code, codeEnd);
+}
+
+static inline LChar singleEscape(int c)
+{
+ if (c < 128) {
+ ASSERT(static_cast<size_t>(c) < ARRAY_SIZE(singleCharacterEscapeValuesForASCII));
+ return singleCharacterEscapeValuesForASCII[c];
+ }
+ return 0;
+}
+
+template <typename T>
+inline void Lexer<T>::record8(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xFF);
+ m_buffer8.append(static_cast<LChar>(c));
+}
+
+template <typename T>
+inline void assertCharIsIn8BitRange(T c)
+{
+ UNUSED_PARAM(c);
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xFF);
+}
+
+template <>
+inline void assertCharIsIn8BitRange(UChar c)
+{
+ UNUSED_PARAM(c);
+ ASSERT(c <= 0xFF);
+}
+
+template <>
+inline void assertCharIsIn8BitRange(LChar)
+{
+}
+
+template <typename T>
+inline void Lexer<T>::append8(const T* p, size_t length)
+{
+ size_t currentSize = m_buffer8.size();
+ m_buffer8.grow(currentSize + length);
+ LChar* rawBuffer = m_buffer8.data() + currentSize;
+
+ for (size_t i = 0; i < length; i++) {
+ T c = p[i];
+ assertCharIsIn8BitRange(c);
+ rawBuffer[i] = c;
+ }
+}
+
+template <typename T>
+inline void Lexer<T>::append16(const LChar* p, size_t length)
+{
+ size_t currentSize = m_buffer16.size();
+ m_buffer16.grow(currentSize + length);
+ UChar* rawBuffer = m_buffer16.data() + currentSize;
+
+ for (size_t i = 0; i < length; i++)
+ rawBuffer[i] = p[i];
+}
+
+template <typename T>
+inline void Lexer<T>::record16(T c)
+{
+ m_buffer16.append(c);
+}
+
+template <typename T>
+inline void Lexer<T>::record16(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= static_cast<int>(USHRT_MAX));
+ m_buffer16.append(static_cast<UChar>(c));
+}
+
+template<typename CharacterType> inline void Lexer<CharacterType>::recordUnicodeCodePoint(UChar32 codePoint)
+{
+ ASSERT(codePoint >= 0);
+ ASSERT(codePoint <= UCHAR_MAX_VALUE);
+ if (U_IS_BMP(codePoint))
+ record16(codePoint);
+ else {
+ UChar codeUnits[2] = { U16_LEAD(codePoint), U16_TRAIL(codePoint) };
+ append16(codeUnits, 2);
+ }
+}
+
+#if !ASSERT_DISABLED
+bool isSafeBuiltinIdentifier(VM& vm, const Identifier* ident)
+{
+ if (!ident)
+ return true;
+ /* Just block any use of suspicious identifiers. This is intended to
+ * be used as a safety net while implementing builtins.
+ */
+ // FIXME: How can a debug-only assertion be a safety net?
+ if (*ident == vm.propertyNames->builtinNames().callPublicName())
+ return false;
+ if (*ident == vm.propertyNames->builtinNames().applyPublicName())
+ return false;
+ if (*ident == vm.propertyNames->eval)
+ return false;
+ if (*ident == vm.propertyNames->Function)
+ return false;
+ return true;
+}
+#endif
+
+template <>
+template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
+ JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
+ if (keyword != IDENT) {
+ ASSERT((!shouldCreateIdentifier) || tokenData->ident);
+ return keyword == RESERVED_IF_STRICT && !strictMode ? IDENT : keyword;
+ }
+ }
+
+ bool isPrivateName = m_current == '@' && m_parsingBuiltinFunction;
+ if (isPrivateName)
+ shift();
+
+ const LChar* identifierStart = currentSourcePtr();
+ unsigned identifierLineStart = currentLineStartOffset();
+
+ while (isIdentPart(m_current))
+ shift();
+
+ if (UNLIKELY(m_current == '\\')) {
+ setOffsetFromSourcePtr(identifierStart, identifierLineStart);
+ return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
+ }
+
+ const Identifier* ident = 0;
+
+ if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
+ int identifierLength = currentSourcePtr() - identifierStart;
+ ident = makeIdentifier(identifierStart, identifierLength);
+ if (m_parsingBuiltinFunction) {
+ if (!isSafeBuiltinIdentifier(*m_vm, ident) && !isPrivateName) {
+ m_lexErrorMessage = makeString("The use of '", ident->string(), "' is disallowed in builtin functions.");
+ return ERRORTOK;
+ }
+ if (isPrivateName)
+ ident = m_vm->propertyNames->getPrivateName(*ident);
+ else if (*ident == m_vm->propertyNames->undefinedKeyword)
+ tokenData->ident = &m_vm->propertyNames->undefinedPrivateName;
+ if (!ident)
+ return INVALID_PRIVATE_NAME_ERRORTOK;
+ }
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
+ ASSERT(shouldCreateIdentifier);
+ if (remaining < maxTokenLength) {
+ const HashTableValue* entry = JSC::mainTable.entry(*ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+ return IDENT;
+ }
+
+ return IDENT;
+}
+
+template <>
+template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
+ JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
+ if (keyword != IDENT) {
+ ASSERT((!shouldCreateIdentifier) || tokenData->ident);
+ return keyword == RESERVED_IF_STRICT && !strictMode ? IDENT : keyword;
+ }
+ }
+
+ bool isPrivateName = m_current == '@' && m_parsingBuiltinFunction;
+ if (isPrivateName)
+ shift();
+
+ const UChar* identifierStart = currentSourcePtr();
+ int identifierLineStart = currentLineStartOffset();
+
+ UChar orAllChars = 0;
+
+ while (isIdentPart(m_current)) {
+ orAllChars |= m_current;
+ shift();
+ }
+
+ if (UNLIKELY(m_current == '\\')) {
+ ASSERT(!isPrivateName);
+ setOffsetFromSourcePtr(identifierStart, identifierLineStart);
+ return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
+ }
+
+ bool isAll8Bit = false;
+
+ if (!(orAllChars & ~0xff))
+ isAll8Bit = true;
+
+ const Identifier* ident = 0;
+
+ if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
+ int identifierLength = currentSourcePtr() - identifierStart;
+ if (isAll8Bit)
+ ident = makeIdentifierLCharFromUChar(identifierStart, identifierLength);
+ else
+ ident = makeIdentifier(identifierStart, identifierLength);
+ if (m_parsingBuiltinFunction) {
+ if (!isSafeBuiltinIdentifier(*m_vm, ident) && !isPrivateName) {
+ m_lexErrorMessage = makeString("The use of '", ident->string(), "' is disallowed in builtin functions.");
+ return ERRORTOK;
+ }
+ if (isPrivateName)
+ ident = m_vm->propertyNames->getPrivateName(*ident);
+ else if (*ident == m_vm->propertyNames->undefinedKeyword)
+ tokenData->ident = &m_vm->propertyNames->undefinedPrivateName;
+ if (!ident)
+ return INVALID_PRIVATE_NAME_ERRORTOK;
+ }
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
+ ASSERT(shouldCreateIdentifier);
+ if (remaining < maxTokenLength) {
+ const HashTableValue* entry = JSC::mainTable.entry(*ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+ return IDENT;
+ }
+
+ return IDENT;
+}
+
+template<typename CharacterType> template<bool shouldCreateIdentifier> JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ auto identifierStart = currentSourcePtr();
+ bool bufferRequired = false;
+
+ while (true) {
+ if (LIKELY(isIdentPart(m_current))) {
+ shift();
+ continue;
+ }
+ if (LIKELY(m_current != '\\'))
+ break;
+
+ // \uXXXX unicode characters.
+ bufferRequired = true;
+ if (identifierStart != currentSourcePtr())
+ m_buffer16.append(identifierStart, currentSourcePtr() - identifierStart);
+ shift();
+ if (UNLIKELY(m_current != 'u'))
+ return atEnd() ? UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK : INVALID_IDENTIFIER_ESCAPE_ERRORTOK;
+ shift();
+ auto character = parseUnicodeEscape();
+ if (UNLIKELY(!character.isValid()))
+ return character.isIncomplete() ? UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK : INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK;
+ if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character.value()) : !isIdentStart(character.value())))
+ return INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK;
+ if (shouldCreateIdentifier)
+ recordUnicodeCodePoint(character.value());
+ identifierStart = currentSourcePtr();
+ }
+
+ int identifierLength;
+ const Identifier* ident = nullptr;
+ if (shouldCreateIdentifier) {
+ if (!bufferRequired) {
+ identifierLength = currentSourcePtr() - identifierStart;
+ ident = makeIdentifier(identifierStart, identifierLength);
+ } else {
+ if (identifierStart != currentSourcePtr())
+ m_buffer16.append(identifierStart, currentSourcePtr() - identifierStart);
+ ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ }
+
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = nullptr;
+
+ m_buffer16.shrink(0);
+
+ if (LIKELY(!(lexerFlags & LexerFlagsIgnoreReservedWords))) {
+ ASSERT(shouldCreateIdentifier);
+ const HashTableValue* entry = JSC::mainTable.entry(*ident);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+
+ return IDENT;
+}
+
+static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(LChar character)
+{
+ return character < 0xE;
+}
+
+static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(UChar character)
+{
+ return character < 0xE || character > 0xFF;
+}
+
+template <typename T>
+template <bool shouldBuildStrings> ALWAYS_INLINE typename Lexer<T>::StringParseResult Lexer<T>::parseString(JSTokenData* tokenData, bool strictMode)
+{
+ int startingOffset = currentOffset();
+ int startingLineStartOffset = currentLineStartOffset();
+ int startingLineNumber = lineNumber();
+ T stringQuoteCharacter = m_current;
+ shift();
+
+ const T* stringStart = currentSourcePtr();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY(m_current == '\\')) {
+ if (stringStart != currentSourcePtr() && shouldBuildStrings)
+ append8(stringStart, currentSourcePtr() - stringStart);
+ shift();
+
+ LChar escape = singleEscape(m_current);
+
+ // Most common escape sequences first.
+ if (escape) {
+ if (shouldBuildStrings)
+ record8(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current)))
+ shiftLineTerminator();
+ else if (m_current == 'x') {
+ shift();
+ if (!isASCIIHexDigit(m_current) || !isASCIIHexDigit(peek(1))) {
+ m_lexErrorMessage = ASCIILiteral("\\x can only be followed by a hex character sequence");
+ return (atEnd() || (isASCIIHexDigit(m_current) && (m_code + 1 == m_codeEnd))) ? StringUnterminated : StringCannotBeParsed;
+ }
+ T prev = m_current;
+ shift();
+ if (shouldBuildStrings)
+ record8(convertHex(prev, m_current));
+ shift();
+ } else {
+ setOffset(startingOffset, startingLineStartOffset);
+ setLineNumber(startingLineNumber);
+ m_buffer8.shrink(0);
+ return parseStringSlowCase<shouldBuildStrings>(tokenData, strictMode);
+ }
+ stringStart = currentSourcePtr();
+ continue;
+ }
+
+ if (UNLIKELY(characterRequiresParseStringSlowCase(m_current))) {
+ setOffset(startingOffset, startingLineStartOffset);
+ setLineNumber(startingLineNumber);
+ m_buffer8.shrink(0);
+ return parseStringSlowCase<shouldBuildStrings>(tokenData, strictMode);
+ }
+
+ shift();
+ }
+
+ if (currentSourcePtr() != stringStart && shouldBuildStrings)
+ append8(stringStart, currentSourcePtr() - stringStart);
+ if (shouldBuildStrings) {
+ tokenData->ident = makeIdentifier(m_buffer8.data(), m_buffer8.size());
+ m_buffer8.shrink(0);
+ } else
+ tokenData->ident = 0;
+
+ return StringParsedSuccessfully;
+}
+
+template <typename T>
+template <bool shouldBuildStrings> ALWAYS_INLINE auto Lexer<T>::parseComplexEscape(EscapeParseMode escapeParseMode, bool strictMode, T stringQuoteCharacter) -> StringParseResult
+{
+ if (m_current == 'x') {
+ shift();
+ if (!isASCIIHexDigit(m_current) || !isASCIIHexDigit(peek(1))) {
+ m_lexErrorMessage = ASCIILiteral("\\x can only be followed by a hex character sequence");
+ return StringCannotBeParsed;
+ }
+ T prev = m_current;
+ shift();
+ if (shouldBuildStrings)
+ record16(convertHex(prev, m_current));
+ shift();
+ return StringParsedSuccessfully;
+ }
+
+ if (m_current == 'u') {
+ shift();
+
+ if (escapeParseMode == EscapeParseMode::String && m_current == stringQuoteCharacter) {
+ if (shouldBuildStrings)
+ record16('u');
+ return StringParsedSuccessfully;
+ }
+
+ auto character = parseUnicodeEscape();
+ if (character.isValid()) {
+ if (shouldBuildStrings)
+ recordUnicodeCodePoint(character.value());
+ return StringParsedSuccessfully;
+ }
+
+ m_lexErrorMessage = ASCIILiteral("\\u can only be followed by a Unicode character sequence");
+ return character.isIncomplete() ? StringUnterminated : StringCannotBeParsed;
+ }
+
+ if (strictMode) {
+ if (isASCIIDigit(m_current)) {
+ // The only valid numeric escape in strict mode is '\0', and this must not be followed by a decimal digit.
+ int character1 = m_current;
+ shift();
+ if (character1 != '0' || isASCIIDigit(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("The only valid numeric escape in strict mode is '\\0'");
+ return StringCannotBeParsed;
+ }
+ if (shouldBuildStrings)
+ record16(0);
+ return StringParsedSuccessfully;
+ }
+ } else {
+ if (isASCIIOctalDigit(m_current)) {
+ // Octal character sequences
+ T character1 = m_current;
+ shift();
+ if (isASCIIOctalDigit(m_current)) {
+ // Two octal characters
+ T character2 = m_current;
+ shift();
+ if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
+ shift();
+ } else {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 8 + character2 - '0');
+ }
+ } else {
+ if (shouldBuildStrings)
+ record16(character1 - '0');
+ }
+ return StringParsedSuccessfully;
+ }
+ }
+
+ if (!atEnd()) {
+ if (shouldBuildStrings)
+ record16(m_current);
+ shift();
+ return StringParsedSuccessfully;
+ }
+
+ m_lexErrorMessage = ASCIILiteral("Unterminated string constant");
+ return StringUnterminated;
+}
+
+template <typename T>
+template <bool shouldBuildStrings> auto Lexer<T>::parseStringSlowCase(JSTokenData* tokenData, bool strictMode) -> StringParseResult
+{
+ T stringQuoteCharacter = m_current;
+ shift();
+
+ const T* stringStart = currentSourcePtr();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY(m_current == '\\')) {
+ if (stringStart != currentSourcePtr() && shouldBuildStrings)
+ append16(stringStart, currentSourcePtr() - stringStart);
+ shift();
+
+ LChar escape = singleEscape(m_current);
+
+ // Most common escape sequences first
+ if (escape) {
+ if (shouldBuildStrings)
+ record16(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current)))
+ shiftLineTerminator();
+ else {
+ StringParseResult result = parseComplexEscape<shouldBuildStrings>(EscapeParseMode::String, strictMode, stringQuoteCharacter);
+ if (result != StringParsedSuccessfully)
+ return result;
+ }
+
+ stringStart = currentSourcePtr();
+ continue;
+ }
+ // Fast check for characters that require special handling.
+ // Catches 0, \n, \r, 0x2028, and 0x2029 as efficiently
+ // as possible, and lets through all common ASCII characters.
+ if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
+ // New-line or end of input is not allowed
+ if (atEnd() || isLineTerminator(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("Unexpected EOF");
+ return atEnd() ? StringUnterminated : StringCannotBeParsed;
+ }
+ // Anything else is just a normal character
+ }
+ shift();
+ }
+
+ if (currentSourcePtr() != stringStart && shouldBuildStrings)
+ append16(stringStart, currentSourcePtr() - stringStart);
+ if (shouldBuildStrings)
+ tokenData->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ else
+ tokenData->ident = 0;
+
+ m_buffer16.shrink(0);
+ return StringParsedSuccessfully;
+}
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+// While the lexer accepts <LF><CR> (not <CR><LF>) sequence
+// as one line terminator and increments one line number,
+// TemplateLiteral considers it as two line terminators <LF> and <CR>.
+//
+// TemplateLiteral normalizes line terminators as follows.
+//
+// <LF> => <LF>
+// <CR> => <LF>
+// <CR><LF> => <LF>
+// <\u2028> => <\u2028>
+// <\u2029> => <\u2029>
+//
+// So, <LF><CR> should be normalized to <LF><LF>.
+// However, the lexer should increment the line number only once for <LF><CR>.
+//
+// To achieve this, LineNumberAdder holds the current status of line terminator sequence.
+// When TemplateLiteral lexer encounters a line terminator, it notifies to LineNumberAdder.
+// LineNumberAdder maintains the status and increments the line number when it's necessary.
+// For example, LineNumberAdder increments the line number only once for <LF><CR> and <CR><LF>.
+template<typename CharacterType>
+class LineNumberAdder {
+public:
+ LineNumberAdder(int& lineNumber)
+ : m_lineNumber(lineNumber)
+ {
+ }
+
+ void clear()
+ {
+ m_previous = 0;
+ }
+
+ void add(CharacterType character)
+ {
+ ASSERT(Lexer<CharacterType>::isLineTerminator(character));
+ if ((character + m_previous) == ('\n' + '\r'))
+ m_previous = 0;
+ else {
+ ++m_lineNumber;
+ m_previous = character;
+ }
+ }
+
+private:
+ int& m_lineNumber;
+ CharacterType m_previous { 0 };
+};
+
+template <typename T>
+template <bool shouldBuildStrings> typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
+{
+ const T* stringStart = currentSourcePtr();
+ const T* rawStringStart = currentSourcePtr();
+
+ LineNumberAdder<T> lineNumberAdder(m_lineNumber);
+
+ while (m_current != '`') {
+ if (UNLIKELY(m_current == '\\')) {
+ lineNumberAdder.clear();
+ if (stringStart != currentSourcePtr() && shouldBuildStrings)
+ append16(stringStart, currentSourcePtr() - stringStart);
+ shift();
+
+ LChar escape = singleEscape(m_current);
+
+ // Most common escape sequences first.
+ if (escape) {
+ if (shouldBuildStrings)
+ record16(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current))) {
+ if (m_current == '\r') {
+ lineNumberAdder.add(m_current);
+ shift();
+ if (m_current == '\n') {
+ lineNumberAdder.add(m_current);
+ shift();
+ }
+ } else {
+ lineNumberAdder.add(m_current);
+ shift();
+ }
+ } else {
+ bool strictMode = true;
+ StringParseResult result = parseComplexEscape<shouldBuildStrings>(EscapeParseMode::Template, strictMode, '`');
+ if (result != StringParsedSuccessfully)
+ return result;
+ }
+
+ stringStart = currentSourcePtr();
+ continue;
+ }
+
+ if (m_current == '$' && peek(1) == '{')
+ break;
+
+ // Fast check for characters that require special handling.
+ // Catches 0, \n, \r, 0x2028, and 0x2029 as efficiently
+ // as possible, and lets through all common ASCII characters.
+ if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
+ // End of input is not allowed.
+ // Unlike String, line terminator is allowed.
+ if (atEnd()) {
+ m_lexErrorMessage = ASCIILiteral("Unexpected EOF");
+ return atEnd() ? StringUnterminated : StringCannotBeParsed;
+ }
+
+ if (isLineTerminator(m_current)) {
+ if (m_current == '\r') {
+ // Normalize <CR>, <CR><LF> to <LF>.
+ if (shouldBuildStrings) {
+ if (stringStart != currentSourcePtr())
+ append16(stringStart, currentSourcePtr() - stringStart);
+ if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+
+ record16('\n');
+ if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append('\n');
+ }
+ lineNumberAdder.add(m_current);
+ shift();
+ if (m_current == '\n') {
+ lineNumberAdder.add(m_current);
+ shift();
+ }
+ stringStart = currentSourcePtr();
+ rawStringStart = currentSourcePtr();
+ } else {
+ lineNumberAdder.add(m_current);
+ shift();
+ }
+ continue;
+ }
+ // Anything else is just a normal character
+ }
+
+ lineNumberAdder.clear();
+ shift();
+ }
+
+ bool isTail = m_current == '`';
+
+ if (shouldBuildStrings) {
+ if (currentSourcePtr() != stringStart)
+ append16(stringStart, currentSourcePtr() - stringStart);
+ if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+ }
+
+ if (shouldBuildStrings) {
+ tokenData->cooked = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations.
+ if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
+ else
+ tokenData->raw = makeEmptyIdentifier();
+ } else {
+ tokenData->cooked = makeEmptyIdentifier();
+ tokenData->raw = makeEmptyIdentifier();
+ }
+ tokenData->isTail = isTail;
+
+ m_buffer16.shrink(0);
+ m_bufferForRawTemplateString16.shrink(0);
+
+ if (isTail) {
+ // Skip `
+ shift();
+ } else {
+ // Skip $ and {
+ shift();
+ shift();
+ }
+
+ return StringParsedSuccessfully;
+}
+#endif
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::parseHex(double& returnValue)
+{
+ // Optimization: most hexadecimal values fit into 4 bytes.
+ uint32_t hexValue = 0;
+ int maximumDigits = 7;
+
+ do {
+ hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
+ shift();
+ --maximumDigits;
+ } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
+
+ if (maximumDigits >= 0) {
+ returnValue = hexValue;
+ return;
+ }
+
+ // No more place in the hexValue buffer.
+ // The values are shifted out and placed into the m_buffer8 vector.
+ for (int i = 0; i < 8; ++i) {
+ int digit = hexValue >> 28;
+ if (digit < 10)
+ record8(digit + '0');
+ else
+ record8(digit - 10 + 'a');
+ hexValue <<= 4;
+ }
+
+ while (isASCIIHexDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseBinary(double& returnValue)
+{
+ // Optimization: most binary values fit into 4 bytes.
+ uint32_t binaryValue = 0;
+ const unsigned maximumDigits = 32;
+ int digit = maximumDigits - 1;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ LChar digits[maximumDigits];
+
+ do {
+ binaryValue = (binaryValue << 1) + (m_current - '0');
+ digits[digit] = m_current;
+ shift();
+ --digit;
+ } while (isASCIIBinaryDigit(m_current) && digit >= 0);
+
+ if (!isASCIIDigit(m_current) && digit >= 0) {
+ returnValue = binaryValue;
+ return true;
+ }
+
+ for (int i = maximumDigits - 1; i > digit; --i)
+ record8(digits[i]);
+
+ while (isASCIIBinaryDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ if (isASCIIDigit(m_current))
+ return false;
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 2);
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseOctal(double& returnValue)
+{
+ // Optimization: most octal values fit into 4 bytes.
+ uint32_t octalValue = 0;
+ const unsigned maximumDigits = 10;
+ int digit = maximumDigits - 1;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ LChar digits[maximumDigits];
+
+ do {
+ octalValue = octalValue * 8 + (m_current - '0');
+ digits[digit] = m_current;
+ shift();
+ --digit;
+ } while (isASCIIOctalDigit(m_current) && digit >= 0);
+
+ if (!isASCIIDigit(m_current) && digit >= 0) {
+ returnValue = octalValue;
+ return true;
+ }
+
+ for (int i = maximumDigits - 1; i > digit; --i)
+ record8(digits[i]);
+
+ while (isASCIIOctalDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ if (isASCIIDigit(m_current))
+ return false;
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseDecimal(double& returnValue)
+{
+ // Optimization: most decimal values fit into 4 bytes.
+ uint32_t decimalValue = 0;
+
+ // Since parseOctal may be executed before parseDecimal,
+ // the m_buffer8 may hold ascii digits.
+ if (!m_buffer8.size()) {
+ const unsigned maximumDigits = 10;
+ int digit = maximumDigits - 1;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ LChar digits[maximumDigits];
+
+ do {
+ decimalValue = decimalValue * 10 + (m_current - '0');
+ digits[digit] = m_current;
+ shift();
+ --digit;
+ } while (isASCIIDigit(m_current) && digit >= 0);
+
+ if (digit >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
+ returnValue = decimalValue;
+ return true;
+ }
+
+ for (int i = maximumDigits - 1; i > digit; --i)
+ record8(digits[i]);
+ }
+
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ return false;
+}
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::parseNumberAfterDecimalPoint()
+{
+ record8('.');
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseNumberAfterExponentIndicator()
+{
+ record8('e');
+ shift();
+ if (m_current == '+' || m_current == '-') {
+ record8(m_current);
+ shift();
+ }
+
+ if (!isASCIIDigit(m_current))
+ return false;
+
+ do {
+ record8(m_current);
+ shift();
+ } while (isASCIIDigit(m_current));
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseMultilineComment()
+{
+ while (true) {
+ while (UNLIKELY(m_current == '*')) {
+ shift();
+ if (m_current == '/') {
+ shift();
+ return true;
+ }
+ }
+
+ if (atEnd())
+ return false;
+
+ if (isLineTerminator(m_current)) {
+ shiftLineTerminator();
+ m_terminator = true;
+ } else
+ shift();
+ }
+}
+
+template <typename T>
+bool Lexer<T>::nextTokenIsColon()
+{
+ const T* code = m_code;
+ while (code < m_codeEnd && (isWhiteSpace(*code) || isLineTerminator(*code)))
+ code++;
+
+ return code < m_codeEnd && *code == ':';
+}
+
+template <typename T>
+void Lexer<T>::setTokenPosition(JSToken* tokenRecord)
+{
+ JSTokenData* tokenData = &tokenRecord->m_data;
+ tokenData->line = lineNumber();
+ tokenData->offset = currentOffset();
+ tokenData->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenData->offset >= tokenData->lineStartOffset);
+}
+
+template <typename T>
+JSTokenType Lexer<T>::lex(JSToken* tokenRecord, unsigned lexerFlags, bool strictMode)
+{
+ JSTokenData* tokenData = &tokenRecord->m_data;
+ JSTokenLocation* tokenLocation = &tokenRecord->m_location;
+ m_lastTockenLocation = JSTokenLocation(tokenRecord->m_location);
+
+ ASSERT(!m_error);
+ ASSERT(m_buffer8.isEmpty());
+ ASSERT(m_buffer16.isEmpty());
+
+ JSTokenType token = ERRORTOK;
+ m_terminator = false;
+
+start:
+ while (isWhiteSpace(m_current))
+ shift();
+
+ if (atEnd())
+ return EOFTOK;
+
+ tokenLocation->startOffset = currentOffset();
+ ASSERT(currentOffset() >= currentLineStartOffset());
+ tokenRecord->m_startPosition = currentPosition();
+
+ CharacterType type;
+ if (LIKELY(isLatin1(m_current)))
+ type = static_cast<CharacterType>(typesOfLatin1Characters[m_current]);
+ else if (isNonLatin1IdentStart(m_current))
+ type = CharacterIdentifierStart;
+ else if (isLineTerminator(m_current))
+ type = CharacterLineTerminator;
+ else
+ type = CharacterInvalid;
+
+ switch (type) {
+ case CharacterGreater:
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = URSHIFTEQUAL;
+ break;
+ }
+ token = URSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = RSHIFTEQUAL;
+ break;
+ }
+ token = RSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = GE;
+ break;
+ }
+ token = GT;
+ break;
+ case CharacterEqual: {
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ if (peek(1) == '>') {
+ token = ARROWFUNCTION;
+ tokenData->line = lineNumber();
+ tokenData->offset = currentOffset();
+ tokenData->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenData->offset >= tokenData->lineStartOffset);
+ shift();
+ shift();
+ break;
+ }
+#endif
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STREQ;
+ break;
+ }
+ token = EQEQ;
+ break;
+ }
+ token = EQUAL;
+ break;
+ }
+ case CharacterLess:
+ shift();
+ if (m_current == '!' && peek(1) == '-' && peek(2) == '-') {
+ // <!-- marks the beginning of a line comment (for www usage)
+ goto inSingleLineComment;
+ }
+ if (m_current == '<') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = LSHIFTEQUAL;
+ break;
+ }
+ token = LSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = LE;
+ break;
+ }
+ token = LT;
+ break;
+ case CharacterExclamationMark:
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STRNEQ;
+ break;
+ }
+ token = NE;
+ break;
+ }
+ token = EXCLAMATION;
+ break;
+ case CharacterAdd:
+ shift();
+ if (m_current == '+') {
+ shift();
+ token = (!m_terminator) ? PLUSPLUS : AUTOPLUSPLUS;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = PLUSEQUAL;
+ break;
+ }
+ token = PLUS;
+ break;
+ case CharacterSub:
+ shift();
+ if (m_current == '-') {
+ shift();
+ if (m_atLineStart && m_current == '>') {
+ shift();
+ goto inSingleLineComment;
+ }
+ token = (!m_terminator) ? MINUSMINUS : AUTOMINUSMINUS;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = MINUSEQUAL;
+ break;
+ }
+ token = MINUS;
+ break;
+ case CharacterMultiply:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MULTEQUAL;
+ break;
+ }
+ token = TIMES;
+ break;
+ case CharacterSlash:
+ shift();
+ if (m_current == '/') {
+ shift();
+ goto inSingleLineComment;
+ }
+ if (m_current == '*') {
+ shift();
+ if (parseMultilineComment())
+ goto start;
+ m_lexErrorMessage = ASCIILiteral("Multiline comment was not closed properly");
+ token = UNTERMINATED_MULTILINE_COMMENT_ERRORTOK;
+ goto returnError;
+ }
+ if (m_current == '=') {
+ shift();
+ token = DIVEQUAL;
+ break;
+ }
+ token = DIVIDE;
+ break;
+ case CharacterAnd:
+ shift();
+ if (m_current == '&') {
+ shift();
+ token = AND;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = ANDEQUAL;
+ break;
+ }
+ token = BITAND;
+ break;
+ case CharacterXor:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = XOREQUAL;
+ break;
+ }
+ token = BITXOR;
+ break;
+ case CharacterModulo:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MODEQUAL;
+ break;
+ }
+ token = MOD;
+ break;
+ case CharacterOr:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = OREQUAL;
+ break;
+ }
+ if (m_current == '|') {
+ shift();
+ token = OR;
+ break;
+ }
+ token = BITOR;
+ break;
+ case CharacterOpenParen:
+ token = OPENPAREN;
+ shift();
+ break;
+ case CharacterCloseParen:
+ token = CLOSEPAREN;
+ shift();
+ break;
+ case CharacterOpenBracket:
+ token = OPENBRACKET;
+ shift();
+ break;
+ 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:
+ shift();
+ token = SEMICOLON;
+ break;
+ case CharacterOpenBrace:
+ tokenData->line = lineNumber();
+ tokenData->offset = currentOffset();
+ tokenData->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenData->offset >= tokenData->lineStartOffset);
+ shift();
+ token = OPENBRACE;
+ break;
+ case CharacterCloseBrace:
+ tokenData->line = lineNumber();
+ tokenData->offset = currentOffset();
+ tokenData->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenData->offset >= tokenData->lineStartOffset);
+ shift();
+ token = CLOSEBRACE;
+ break;
+ case CharacterDot:
+ shift();
+ if (!isASCIIDigit(m_current)) {
+ if (UNLIKELY((m_current == '.') && (peek(1) == '.'))) {
+ shift();
+ shift();
+ token = DOTDOTDOT;
+ break;
+ }
+ token = DOT;
+ break;
+ }
+ goto inNumberAfterDecimalPoint;
+ case CharacterZero:
+ shift();
+ if ((m_current | 0x20) == 'x') {
+ if (!isASCIIHexDigit(peek(1))) {
+ m_lexErrorMessage = ASCIILiteral("No hexadecimal digits after '0x'");
+ token = INVALID_HEX_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+
+ // Shift out the 'x' prefix.
+ shift();
+
+ parseHex(tokenData->doubleValue);
+ if (isIdentStart(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("No space between hexadecimal literal and identifier");
+ token = INVALID_HEX_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ m_buffer8.shrink(0);
+ break;
+ }
+ if ((m_current | 0x20) == 'b') {
+ if (!isASCIIBinaryDigit(peek(1))) {
+ m_lexErrorMessage = ASCIILiteral("No binary digits after '0b'");
+ token = INVALID_BINARY_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+
+ // Shift out the 'b' prefix.
+ shift();
+
+ parseBinary(tokenData->doubleValue);
+ if (isIdentStart(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("No space between binary literal and identifier");
+ token = INVALID_BINARY_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ m_buffer8.shrink(0);
+ break;
+ }
+
+ if ((m_current | 0x20) == 'o') {
+ if (!isASCIIOctalDigit(peek(1))) {
+ m_lexErrorMessage = ASCIILiteral("No octal digits after '0o'");
+ token = INVALID_OCTAL_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+
+ // Shift out the 'o' prefix.
+ shift();
+
+ parseOctal(tokenData->doubleValue);
+ if (isIdentStart(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("No space between octal literal and identifier");
+ token = INVALID_OCTAL_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ m_buffer8.shrink(0);
+ break;
+ }
+
+ record8('0');
+ if (strictMode && isASCIIDigit(m_current)) {
+ m_lexErrorMessage = ASCIILiteral("Decimal integer literals with a leading zero are forbidden in strict mode");
+ token = INVALID_OCTAL_NUMBER_ERRORTOK;
+ goto returnError;
+ }
+ if (isASCIIOctalDigit(m_current)) {
+ if (parseOctal(tokenData->doubleValue)) {
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ }
+ }
+ FALLTHROUGH;
+ case CharacterNumber:
+ if (LIKELY(token != INTEGER && token != DOUBLE)) {
+ if (!parseDecimal(tokenData->doubleValue)) {
+ token = INTEGER;
+ if (m_current == '.') {
+ shift();
+inNumberAfterDecimalPoint:
+ parseNumberAfterDecimalPoint();
+ token = DOUBLE;
+ }
+ if ((m_current | 0x20) == 'e') {
+ if (!parseNumberAfterExponentIndicator()) {
+ m_lexErrorMessage = ASCIILiteral("Non-number found after exponent indicator");
+ token = atEnd() ? UNTERMINATED_NUMERIC_LITERAL_ERRORTOK : INVALID_NUMERIC_LITERAL_ERRORTOK;
+ goto returnError;
+ }
+ }
+ size_t parsedLength;
+ tokenData->doubleValue = parseDouble(m_buffer8.data(), m_buffer8.size(), parsedLength);
+ if (token == INTEGER)
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ } else
+ token = tokenTypeForIntegerLikeToken(tokenData->doubleValue);
+ }
+
+ if (UNLIKELY(isIdentStart(m_current))) {
+ m_lexErrorMessage = ASCIILiteral("No identifiers allowed directly after numeric literal");
+ token = atEnd() ? UNTERMINATED_NUMERIC_LITERAL_ERRORTOK : INVALID_NUMERIC_LITERAL_ERRORTOK;
+ goto returnError;
+ }
+ m_buffer8.shrink(0);
+ break;
+ case CharacterQuote: {
+ StringParseResult result = StringCannotBeParsed;
+ if (lexerFlags & LexerFlagsDontBuildStrings)
+ result = parseString<false>(tokenData, strictMode);
+ else
+ result = parseString<true>(tokenData, strictMode);
+
+ if (UNLIKELY(result != StringParsedSuccessfully)) {
+ token = result == StringUnterminated ? UNTERMINATED_STRING_LITERAL_ERRORTOK : INVALID_STRING_LITERAL_ERRORTOK;
+ goto returnError;
+ }
+ shift();
+ token = STRING;
+ break;
+ }
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ case CharacterBackQuote: {
+ // Skip backquote.
+ shift();
+ StringParseResult result = StringCannotBeParsed;
+ if (lexerFlags & LexerFlagsDontBuildStrings)
+ result = parseTemplateLiteral<false>(tokenData, RawStringsBuildMode::BuildRawStrings);
+ else
+ result = parseTemplateLiteral<true>(tokenData, RawStringsBuildMode::BuildRawStrings);
+
+ if (UNLIKELY(result != StringParsedSuccessfully)) {
+ token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
+ goto returnError;
+ }
+ token = TEMPLATE;
+ break;
+ }
+#endif
+ case CharacterIdentifierStart:
+ ASSERT(isIdentStart(m_current));
+ FALLTHROUGH;
+ case CharacterBackSlash:
+ parseIdent:
+ if (lexerFlags & LexexFlagsDontBuildKeywords)
+ token = parseIdentifier<false>(tokenData, lexerFlags, strictMode);
+ else
+ token = parseIdentifier<true>(tokenData, lexerFlags, strictMode);
+ break;
+ case CharacterLineTerminator:
+ ASSERT(isLineTerminator(m_current));
+ shiftLineTerminator();
+ m_atLineStart = true;
+ m_terminator = true;
+ m_lineStart = m_code;
+ goto start;
+ case CharacterPrivateIdentifierStart:
+ if (m_parsingBuiltinFunction)
+ goto parseIdent;
+
+ FALLTHROUGH;
+ case CharacterInvalid:
+ m_lexErrorMessage = invalidCharacterMessage();
+ token = ERRORTOK;
+ goto returnError;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ m_lexErrorMessage = ASCIILiteral("Internal Error");
+ token = ERRORTOK;
+ goto returnError;
+ }
+
+ m_atLineStart = false;
+ goto returnToken;
+
+inSingleLineComment:
+ while (!isLineTerminator(m_current)) {
+ if (atEnd())
+ return EOFTOK;
+ shift();
+ }
+ shiftLineTerminator();
+ m_atLineStart = true;
+ m_terminator = true;
+ m_lineStart = m_code;
+ if (!lastTokenWasRestrKeyword())
+ goto start;
+
+ token = SEMICOLON;
+ // Fall through into returnToken.
+
+returnToken:
+ tokenLocation->line = m_lineNumber;
+ tokenLocation->endOffset = currentOffset();
+ tokenLocation->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
+ tokenRecord->m_endPosition = currentPosition();
+ m_lastToken = token;
+ return token;
+
+returnError:
+ m_error = true;
+ tokenLocation->line = m_lineNumber;
+ tokenLocation->endOffset = currentOffset();
+ tokenLocation->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
+ tokenRecord->m_endPosition = currentPosition();
+ RELEASE_ASSERT(token & ErrorTokenFlag);
+ return token;
+}
+
+template <typename T>
+static inline void orCharacter(UChar&, UChar);
+
+template <>
+inline void orCharacter<LChar>(UChar&, UChar) { }
+
+template <>
+inline void orCharacter<UChar>(UChar& orAccumulator, UChar character)
+{
+ orAccumulator |= character;
+}
+
+template <typename T>
+bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
+{
+ ASSERT(m_buffer16.isEmpty());
+
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+ UChar charactersOredTogether = 0;
+
+ if (patternPrefix) {
+ ASSERT(!isLineTerminator(patternPrefix));
+ ASSERT(patternPrefix != '/');
+ ASSERT(patternPrefix != '[');
+ record16(patternPrefix);
+ }
+
+ while (true) {
+ if (isLineTerminator(m_current) || atEnd()) {
+ m_buffer16.shrink(0);
+ return false;
+ }
+
+ T prev = m_current;
+
+ shift();
+
+ if (prev == '/' && !lastWasEscape && !inBrackets)
+ break;
+
+ record16(prev);
+ orCharacter<T>(charactersOredTogether, prev);
+
+ if (lastWasEscape) {
+ lastWasEscape = false;
+ continue;
+ }
+
+ switch (prev) {
+ case '[':
+ inBrackets = true;
+ break;
+ case ']':
+ inBrackets = false;
+ break;
+ case '\\':
+ lastWasEscape = true;
+ break;
+ }
+ }
+
+ pattern = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
+
+ m_buffer16.shrink(0);
+ charactersOredTogether = 0;
+
+ while (isIdentPart(m_current)) {
+ record16(m_current);
+ orCharacter<T>(charactersOredTogether, m_current);
+ shift();
+ }
+
+ flags = makeRightSizedIdentifier(m_buffer16.data(), m_buffer16.size(), charactersOredTogether);
+ m_buffer16.shrink(0);
+
+ return true;
+}
+
+template <typename T>
+bool Lexer<T>::skipRegExp()
+{
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+
+ while (true) {
+ if (isLineTerminator(m_current) || atEnd())
+ return false;
+
+ T prev = m_current;
+
+ shift();
+
+ if (prev == '/' && !lastWasEscape && !inBrackets)
+ break;
+
+ if (lastWasEscape) {
+ lastWasEscape = false;
+ continue;
+ }
+
+ switch (prev) {
+ case '[':
+ inBrackets = true;
+ break;
+ case ']':
+ inBrackets = false;
+ break;
+ case '\\':
+ lastWasEscape = true;
+ break;
+ }
+ }
+
+ while (isIdentPart(m_current))
+ shift();
+
+ return true;
+}
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+template <typename T>
+JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
+{
+ JSTokenData* tokenData = &tokenRecord->m_data;
+ JSTokenLocation* tokenLocation = &tokenRecord->m_location;
+ ASSERT(!m_error);
+ ASSERT(m_buffer16.isEmpty());
+
+ // Leading closing brace } is already shifted in the previous token scan.
+ // So in this re-scan phase, shift() is not needed here.
+ StringParseResult result = parseTemplateLiteral<true>(tokenData, rawStringsBuildMode);
+ JSTokenType token = ERRORTOK;
+ if (UNLIKELY(result != StringParsedSuccessfully)) {
+ token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
+ m_error = true;
+ } else {
+ token = TEMPLATE;
+ m_lastToken = token;
+ }
+
+ // Since TemplateString always ends with ` or }, m_atLineStart always becomes false.
+ m_atLineStart = false;
+
+ // Adjust current tokenLocation data for TemplateString.
+ tokenLocation->line = m_lineNumber;
+ tokenLocation->endOffset = currentOffset();
+ tokenLocation->lineStartOffset = currentLineStartOffset();
+ ASSERT(tokenLocation->endOffset >= tokenLocation->lineStartOffset);
+ tokenRecord->m_endPosition = currentPosition();
+ return token;
+}
+#endif
+
+template <typename T>
+void Lexer<T>::clear()
+{
+ m_arena = 0;
+
+ Vector<LChar> newBuffer8;
+ m_buffer8.swap(newBuffer8);
+
+ Vector<UChar> newBuffer16;
+ m_buffer16.swap(newBuffer16);
+
+ Vector<UChar> newBufferForRawTemplateString16;
+ m_bufferForRawTemplateString16.swap(newBufferForRawTemplateString16);
+
+ m_isReparsingFunction = false;
+}
+
+// Instantiate the two flavors of Lexer we need instead of putting most of this file in Lexer.h
+template class Lexer<LChar>;
+template class Lexer<UChar>;
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Lexer.h b/Source/JavaScriptCore/parser/Lexer.h
new file mode 100644
index 000000000..e5f56cca4
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Lexer_h
+#define Lexer_h
+
+#include "Lookup.h"
+#include "ParserArena.h"
+#include "ParserTokens.h"
+#include "SourceCode.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/SegmentedVector.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+enum LexerFlags {
+ LexerFlagsIgnoreReservedWords = 1,
+ LexerFlagsDontBuildStrings = 2,
+ LexexFlagsDontBuildKeywords = 4
+};
+
+struct ParsedUnicodeEscapeValue;
+
+bool isLexerKeyword(const Identifier&);
+
+template <typename T>
+class Lexer {
+ WTF_MAKE_NONCOPYABLE(Lexer);
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ Lexer(VM*, JSParserBuiltinMode);
+ ~Lexer();
+
+ // Character manipulation functions.
+ static bool isWhiteSpace(T character);
+ static bool isLineTerminator(T character);
+ static unsigned char convertHex(int c1, int c2);
+ static UChar convertUnicode(int c1, int c2, int c3, int c4);
+
+ // Functions to set up parsing.
+ void setCode(const SourceCode&, ParserArena*);
+ void setIsReparsingFunction() { m_isReparsingFunction = true; }
+ bool isReparsingFunction() const { return m_isReparsingFunction; }
+
+ void setTokenPosition(JSToken* tokenRecord);
+ JSTokenType lex(JSToken*, unsigned, bool strictMode);
+ bool nextTokenIsColon();
+ int lineNumber() const { return m_lineNumber; }
+ ALWAYS_INLINE int currentOffset() const { return offsetFromSourcePtr(m_code); }
+ ALWAYS_INLINE int currentLineStartOffset() const { return offsetFromSourcePtr(m_lineStart); }
+ ALWAYS_INLINE JSTextPosition currentPosition() const
+ {
+ return JSTextPosition(m_lineNumber, currentOffset(), currentLineStartOffset());
+ }
+ JSTextPosition positionBeforeLastNewline() const { return m_positionBeforeLastNewline; }
+ JSTokenLocation lastTokenLocation() const { return m_lastTockenLocation; }
+ void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
+ int lastLineNumber() const { return m_lastLineNumber; }
+ bool prevTerminator() const { return m_terminator; }
+ bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings };
+ JSTokenType scanTrailingTemplateString(JSToken*, RawStringsBuildMode);
+#endif
+ bool skipRegExp();
+
+ // Functions for use after parsing.
+ bool sawError() const { return m_error; }
+ String getErrorMessage() const { return m_lexErrorMessage; }
+ void clear();
+ void setOffset(int offset, int lineStartOffset)
+ {
+ m_error = 0;
+ m_lexErrorMessage = String();
+
+ m_code = sourcePtrFromOffset(offset);
+ m_lineStart = sourcePtrFromOffset(lineStartOffset);
+ ASSERT(currentOffset() >= currentLineStartOffset());
+
+ m_buffer8.resize(0);
+ m_buffer16.resize(0);
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ else
+ m_current = 0;
+ }
+ void setLineNumber(int line)
+ {
+ m_lineNumber = line;
+ }
+ void setTerminator(bool terminator)
+ {
+ m_terminator = terminator;
+ }
+
+ SourceProvider* sourceProvider() const { return m_source->provider(); }
+
+ JSTokenType lexExpectIdentifier(JSToken*, unsigned, bool strictMode);
+
+private:
+ void record8(int);
+ void append8(const T*, size_t);
+ void record16(int);
+ void record16(T);
+ void recordUnicodeCodePoint(UChar32);
+ void append16(const LChar*, size_t);
+ void append16(const UChar* characters, size_t length) { m_buffer16.append(characters, length); }
+
+ ALWAYS_INLINE void shift();
+ ALWAYS_INLINE bool atEnd() const;
+ ALWAYS_INLINE T peek(int offset) const;
+
+ ParsedUnicodeEscapeValue parseUnicodeEscape();
+ void shiftLineTerminator();
+
+ ALWAYS_INLINE int offsetFromSourcePtr(const T* ptr) const { return ptr - m_codeStart; }
+ ALWAYS_INLINE const T* sourcePtrFromOffset(int offset) const { return m_codeStart + offset; }
+
+ String invalidCharacterMessage() const;
+ ALWAYS_INLINE const T* currentSourcePtr() const;
+ ALWAYS_INLINE void setOffsetFromSourcePtr(const T* sourcePtr, unsigned lineStartOffset) { setOffset(offsetFromSourcePtr(sourcePtr), lineStartOffset); }
+
+ ALWAYS_INLINE void setCodeStart(const StringImpl*);
+
+ ALWAYS_INLINE const Identifier* makeIdentifier(const LChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeLCharIdentifier(const LChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeLCharIdentifier(const UChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeRightSizedIdentifier(const UChar* characters, size_t length, UChar orAllChars);
+ ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(const UChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeEmptyIdentifier();
+
+ ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
+
+ template <int shiftAmount> void internalShift();
+ template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType parseKeyword(JSTokenData*);
+ template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned lexerFlags, bool strictMode);
+ template <bool shouldBuildIdentifiers> NEVER_INLINE JSTokenType parseIdentifierSlowCase(JSTokenData*, unsigned lexerFlags, bool strictMode);
+ enum StringParseResult {
+ StringParsedSuccessfully,
+ StringUnterminated,
+ StringCannotBeParsed
+ };
+ template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseString(JSTokenData*, bool strictMode);
+ template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
+
+ enum class EscapeParseMode { Template, String };
+ template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseComplexEscape(EscapeParseMode, bool strictMode, T stringQuoteCharacter);
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
+#endif
+ ALWAYS_INLINE void parseHex(double& returnValue);
+ ALWAYS_INLINE bool parseBinary(double& returnValue);
+ ALWAYS_INLINE bool parseOctal(double& returnValue);
+ ALWAYS_INLINE bool parseDecimal(double& returnValue);
+ ALWAYS_INLINE void parseNumberAfterDecimalPoint();
+ ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
+ ALWAYS_INLINE bool parseMultilineComment();
+
+ static const size_t initialReadBufferCapacity = 32;
+
+ int m_lineNumber;
+ int m_lastLineNumber;
+
+ Vector<LChar> m_buffer8;
+ Vector<UChar> m_buffer16;
+ Vector<UChar> m_bufferForRawTemplateString16;
+ bool m_terminator;
+ int m_lastToken;
+
+ const SourceCode* m_source;
+ unsigned m_sourceOffset;
+ const T* m_code;
+ const T* m_codeStart;
+ const T* m_codeEnd;
+ const T* m_codeStartPlusOffset;
+ const T* m_lineStart;
+ JSTextPosition m_positionBeforeLastNewline;
+ JSTokenLocation m_lastTockenLocation;
+ bool m_isReparsingFunction;
+ bool m_atLineStart;
+ bool m_error;
+ String m_lexErrorMessage;
+
+ T m_current;
+
+ IdentifierArena* m_arena;
+
+ VM* m_vm;
+ bool m_parsingBuiltinFunction;
+};
+
+template <>
+ALWAYS_INLINE bool Lexer<LChar>::isWhiteSpace(LChar ch)
+{
+ return ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC || ch == 0xA0;
+}
+
+template <>
+ALWAYS_INLINE bool Lexer<UChar>::isWhiteSpace(UChar ch)
+{
+ // 0x180E used to be in Zs category before Unicode 6.3, and EcmaScript says that we should keep treating it as such.
+ return (ch < 256) ? Lexer<LChar>::isWhiteSpace(static_cast<LChar>(ch)) : (u_charType(ch) == U_SPACE_SEPARATOR || ch == 0x180E || ch == 0xFEFF);
+}
+
+template <>
+ALWAYS_INLINE bool Lexer<LChar>::isLineTerminator(LChar ch)
+{
+ return ch == '\r' || ch == '\n';
+}
+
+template <>
+ALWAYS_INLINE bool Lexer<UChar>::isLineTerminator(UChar ch)
+{
+ return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
+}
+
+template <typename T>
+inline unsigned char Lexer<T>::convertHex(int c1, int c2)
+{
+ return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
+}
+
+template <typename T>
+inline UChar Lexer<T>::convertUnicode(int c1, int c2, int c3, int c4)
+{
+ return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const LChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_vm, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_vm, characters, length);
+}
+
+template <>
+ALWAYS_INLINE const Identifier* Lexer<LChar>::makeRightSizedIdentifier(const UChar* characters, size_t length, UChar)
+{
+ return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
+}
+
+template <>
+ALWAYS_INLINE const Identifier* Lexer<UChar>::makeRightSizedIdentifier(const UChar* characters, size_t length, UChar orAllChars)
+{
+ if (!(orAllChars & ~0xff))
+ return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
+
+ return &m_arena->makeIdentifier(m_vm, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeEmptyIdentifier()
+{
+ return &m_arena->makeEmptyIdentifier(m_vm);
+}
+
+template <>
+ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
+{
+ ASSERT(sourceString->is8Bit());
+ m_codeStart = sourceString->characters8();
+}
+
+template <>
+ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringImpl* sourceString)
+{
+ ASSERT(!sourceString->is8Bit());
+ m_codeStart = sourceString->characters16();
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifierLCharFromUChar(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeLCharIdentifier(const LChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_vm, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeLCharIdentifier(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
+}
+
+#if ASSERT_DISABLED
+ALWAYS_INLINE bool isSafeBuiltinIdentifier(VM&, const Identifier*) { return true; }
+#else
+bool isSafeBuiltinIdentifier(VM&, const Identifier*);
+#endif
+
+template <typename T>
+ALWAYS_INLINE JSTokenType Lexer<T>::lexExpectIdentifier(JSToken* tokenRecord, unsigned lexerFlags, bool strictMode)
+{
+ JSTokenData* tokenData = &tokenRecord->m_data;
+ JSTokenLocation* tokenLocation = &tokenRecord->m_location;
+ ASSERT((lexerFlags & LexerFlagsIgnoreReservedWords));
+ const T* start = m_code;
+ const T* ptr = start;
+ const T* end = m_codeEnd;
+ JSTextPosition startPosition = currentPosition();
+ if (ptr >= end) {
+ ASSERT(ptr == end);
+ goto slowCase;
+ }
+ if (!WTF::isASCIIAlpha(*ptr))
+ goto slowCase;
+ ++ptr;
+ while (ptr < end) {
+ if (!WTF::isASCIIAlphanumeric(*ptr))
+ break;
+ ++ptr;
+ }
+
+ // Here's the shift
+ if (ptr < end) {
+ if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
+ goto slowCase;
+ m_current = *ptr;
+ } else
+ m_current = 0;
+
+ m_code = ptr;
+ ASSERT(currentOffset() >= currentLineStartOffset());
+
+ // Create the identifier if needed
+ if (lexerFlags & LexexFlagsDontBuildKeywords
+#if !ASSERT_DISABLED
+ && !m_parsingBuiltinFunction
+#endif
+ )
+ tokenData->ident = 0;
+ else
+ tokenData->ident = makeLCharIdentifier(start, ptr - start);
+
+ tokenLocation->line = m_lineNumber;
+ tokenLocation->lineStartOffset = currentLineStartOffset();
+ tokenLocation->startOffset = offsetFromSourcePtr(start);
+ tokenLocation->endOffset = currentOffset();
+ ASSERT(tokenLocation->startOffset >= tokenLocation->lineStartOffset);
+ tokenRecord->m_startPosition = startPosition;
+ tokenRecord->m_endPosition = currentPosition();
+#if !ASSERT_DISABLED
+ if (m_parsingBuiltinFunction) {
+ if (!isSafeBuiltinIdentifier(*m_vm, tokenData->ident))
+ return ERRORTOK;
+ }
+#endif
+
+ m_lastToken = IDENT;
+ return IDENT;
+
+slowCase:
+ return lex(tokenRecord, lexerFlags, strictMode);
+}
+
+} // namespace JSC
+
+#endif // Lexer_h
diff --git a/Source/JavaScriptCore/parser/ModuleAnalyzer.cpp b/Source/JavaScriptCore/parser/ModuleAnalyzer.cpp
new file mode 100644
index 000000000..b2de960b3
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ModuleAnalyzer.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ModuleAnalyzer.h"
+
+#include "IdentifierInlines.h"
+#include "ModuleRecord.h"
+
+namespace JSC {
+
+
+ModuleAnalyzer::ModuleAnalyzer(VM& vm, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
+ : m_vm(&vm)
+ , m_moduleRecord(ModuleRecord::create())
+ , m_declaredVariables(declaredVariables)
+ , m_lexicalVariables(lexicalVariables)
+{
+}
+
+Identifier ModuleAnalyzer::exportedBinding(const RefPtr<UniquedStringImpl>& ident)
+{
+ const auto iterator = m_aliasMap.find(ident);
+ if (iterator != m_aliasMap.end())
+ return iterator->value;
+ return Identifier::fromUid(&vm(), ident.get());
+}
+
+void ModuleAnalyzer::declareExportAlias(const Identifier& localName, const Identifier& exportName)
+{
+ m_aliasMap.add(localName.impl(), exportName);
+}
+
+void ModuleAnalyzer::exportVariable(const RefPtr<UniquedStringImpl>& localName, const VariableEnvironmentEntry& variable)
+{
+ // In the parser, we already marked the variables as Exported and Imported.
+ // By leveraging this information, we collect the information that is needed
+ // to construct the module environment.
+ //
+ // I E
+ // * = exported module local variable
+ // * = imported binding
+ // = non-exported module local variable
+ // * * = indirect exported binding
+ //
+ // One exception is namespace binding (like import * as ns from "mod").
+ // This is annotated as an imported, but the actual binding is locate in the
+ // current module.
+
+ if (!variable.isExported())
+ return;
+
+ const Identifier exportName = exportedBinding(localName);
+
+ // Exported module local variable.
+ if (!variable.isImported()) {
+ moduleRecord().addExportEntry(ModuleRecord::ExportEntry::createLocal(exportName, Identifier::fromUid(m_vm, localName.get()), variable));
+ return;
+ }
+
+ const auto& importEntry = moduleRecord().lookUpImportEntry(localName);
+ if (importEntry.isNamespace(vm())) {
+ // Exported namespace binding.
+ // import * as namespace from "mod"
+ // export { namespace }
+ moduleRecord().addExportEntry(ModuleRecord::ExportEntry::createNamespace(exportName, importEntry.moduleRequest));
+ return;
+ }
+
+ // Indirectly exported binding.
+ // import a from "mod"
+ // export { a }
+ moduleRecord().addExportEntry(ModuleRecord::ExportEntry::createIndirect(exportName, importEntry.importName, importEntry.moduleRequest));
+}
+
+
+
+Ref<ModuleRecord> ModuleAnalyzer::analyze(ModuleProgramNode& moduleProgramNode)
+{
+ // Traverse the module AST and collect
+ // * Import entries
+ // * Export entries that have FromClause (e.g. export { a } from "mod")
+ // * Export entries that have star (e.g. export * from "mod")
+ // * Aliased export names (e.g. export { a as b })
+ moduleProgramNode.analyzeModule(*this);
+
+ // Based on the collected information, categorize export entries into 3 types.
+ // 1. Local export entries
+ // This references the local variable in the current module.
+ // This variable should be allocated in the current module environment as a heap variable.
+ //
+ // const variable = 20
+ // export { variable }
+ //
+ // 2. Namespace export entries
+ // This references the namespace object imported by some import entries.
+ // This variable itself should be allocated in the current module environment as a heap variable.
+ // But when the other modules attempt to resolve this export name in this module, this module
+ // should tell the link to the original module.
+ //
+ // import * as namespace from "mod"
+ // export { namespace as mod }
+ //
+ // 3. Indirect export entries
+ // This references the imported binding name from the other module.
+ // This module environment itself should hold the pointer to (1) the original module and
+ // (2) the binding in the original module. The variable itself is allocated in the original
+ // module. This indirect binding is resolved when the CodeBlock resolves the references.
+ //
+ // import mod from "mod"
+ // export { mod }
+ //
+ // export { a } from "mod"
+ //
+ // And separeted from the above 3 types, we also collect the star export entries.
+ //
+ // 4. Star export entries
+ // This exports all the names from the specified external module as the current module's name.
+ //
+ // export * from "mod"
+ for (const auto& pair : m_declaredVariables)
+ exportVariable(pair.key, pair.value);
+
+ for (const auto& pair : m_lexicalVariables)
+ exportVariable(pair.key, pair.value);
+
+ if (Options::dumpModuleRecord())
+ m_moduleRecord->dump();
+
+ return *m_moduleRecord;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/ModuleAnalyzer.h b/Source/JavaScriptCore/parser/ModuleAnalyzer.h
new file mode 100644
index 000000000..027648476
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ModuleAnalyzer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ModuleAnalyzer_h
+#define ModuleAnalyzer_h
+
+#include "ModuleRecord.h"
+#include "Nodes.h"
+
+namespace JSC {
+
+class ModuleAnalyzer {
+public:
+ ModuleAnalyzer(VM&, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables);
+
+ Ref<ModuleRecord> analyze(ModuleProgramNode&);
+
+ VM& vm() { return *m_vm; }
+
+ ModuleRecord& moduleRecord() { return *m_moduleRecord; }
+
+ void declareExportAlias(const Identifier& localName, const Identifier& exportName);
+
+private:
+ typedef HashMap<RefPtr<UniquedStringImpl>, Identifier, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> IdentifierAliasMap;
+
+ void exportVariable(const RefPtr<UniquedStringImpl>&, const VariableEnvironmentEntry&);
+
+ Identifier exportedBinding(const RefPtr<UniquedStringImpl>& ident);
+
+ VM* m_vm;
+ RefPtr<ModuleRecord> m_moduleRecord;
+ VariableEnvironment m_declaredVariables;
+ VariableEnvironment m_lexicalVariables;
+ IdentifierAliasMap m_aliasMap;
+};
+
+} // namespace JSC
+
+#endif // ModuleAnalyzer_h
diff --git a/Source/JavaScriptCore/parser/ModuleRecord.cpp b/Source/JavaScriptCore/parser/ModuleRecord.cpp
new file mode 100644
index 000000000..ec973568b
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ModuleRecord.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ModuleRecord.h"
+
+#include "IdentifierInlines.h"
+
+namespace JSC {
+
+
+auto ModuleRecord::ExportEntry::createLocal(const Identifier& exportName, const Identifier& localName, const VariableEnvironmentEntry& variable) -> ExportEntry
+{
+ return ExportEntry { Type::Local, exportName, Identifier(), Identifier(), localName, variable };
+}
+
+auto ModuleRecord::ExportEntry::createNamespace(const Identifier& exportName, const Identifier& moduleName) -> ExportEntry
+{
+ return ExportEntry { Type::Namespace, exportName, moduleName, Identifier(), Identifier(), VariableEnvironmentEntry() };
+}
+
+auto ModuleRecord::ExportEntry::createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName) -> ExportEntry
+{
+ return ExportEntry { Type::Indirect, exportName, moduleName, importName, Identifier(), VariableEnvironmentEntry() };
+}
+
+static String printableName(const RefPtr<UniquedStringImpl>& uid)
+{
+ if (uid->isSymbol())
+ return uid.get();
+ return WTF::makeString("'", String(uid.get()), "'");
+}
+
+static String printableName(const Identifier& ident)
+{
+ return printableName(ident.impl());
+}
+
+
+void ModuleRecord::dump()
+{
+ dataLog("\nAnalyzing ModuleRecord\n");
+
+ dataLog(" Dependencies: ", m_requestedModules.size(), " modules\n");
+ for (const auto& moduleName : m_requestedModules)
+ dataLog(" module(", printableName(moduleName), ")\n");
+
+ dataLog(" Import: ", m_importEntries.size(), " entries\n");
+ for (const auto& pair : m_importEntries)
+ dataLog(" import(", printableName(pair.value.importName), "), local(", printableName(pair.value.localName), "), module(", printableName(pair.value.moduleRequest), ")\n");
+
+ dataLog(" Export: ", m_exportEntries.size(), " entries\n");
+ for (const auto& pair : m_exportEntries) {
+ const ExportEntry& entry = pair.value;
+ switch (entry.type) {
+ case ExportEntry::Type::Local:
+ dataLog(" [Local] ", "export(", printableName(entry.exportName), "), local(", printableName(entry.localName), ")\n");
+ break;
+
+ case ExportEntry::Type::Namespace:
+ dataLog(" [Namespace] ", "export(", printableName(entry.exportName), "), module(", printableName(entry.moduleName), ")\n");
+ break;
+
+ case ExportEntry::Type::Indirect:
+ dataLog(" [Indirect] ", "export(", printableName(entry.exportName), "), import(", printableName(entry.importName), "), module(", printableName(entry.moduleName), ")\n");
+ break;
+ }
+ }
+ for (const auto& moduleName : m_starExportEntries)
+ dataLog(" [Star] module(", printableName(moduleName.get()), ")\n");
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/ModuleRecord.h b/Source/JavaScriptCore/parser/ModuleRecord.h
new file mode 100644
index 000000000..ef081c03b
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ModuleRecord.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ModuleRecord_h
+#define ModuleRecord_h
+
+#include "Nodes.h"
+#include <wtf/HashMap.h>
+#include <wtf/ListHashSet.h>
+
+namespace JSC {
+
+// Based on the Source Text Module Record
+// http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+class ModuleRecord : public RefCounted<ModuleRecord> {
+public:
+ struct ExportEntry {
+ enum class Type {
+ Local,
+ Namespace,
+ Indirect
+ };
+
+ static ExportEntry createLocal(const Identifier& exportName, const Identifier& localName, const VariableEnvironmentEntry&);
+ static ExportEntry createNamespace(const Identifier& exportName, const Identifier& moduleName);
+ static ExportEntry createIndirect(const Identifier& exportName, const Identifier& importName, const Identifier& moduleName);
+
+ Type type;
+ Identifier exportName;
+ Identifier moduleName;
+ Identifier importName;
+ Identifier localName;
+ VariableEnvironmentEntry variable;
+ };
+
+ struct ImportEntry {
+ Identifier moduleRequest;
+ Identifier importName;
+ Identifier localName;
+
+ bool isNamespace(VM& vm) const
+ {
+ return importName == vm.propertyNames->timesIdentifier;
+ }
+ };
+
+ typedef WTF::ListHashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> OrderedIdentifierSet;
+ typedef HashMap<RefPtr<UniquedStringImpl>, ImportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ImportMap;
+ typedef HashMap<RefPtr<UniquedStringImpl>, ExportEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>> ExportMap;
+
+ static Ref<ModuleRecord> create()
+ {
+ return adoptRef(*new ModuleRecord);
+ }
+
+ void appendRequestedModule(const Identifier&);
+ void addStarExportEntry(const Identifier&);
+ void addImportEntry(const ImportEntry&);
+ void addExportEntry(const ExportEntry&);
+
+ const ImportEntry& lookUpImportEntry(const RefPtr<UniquedStringImpl>& localName);
+
+ void dump();
+
+private:
+ // Map localName -> ImportEntry.
+ ImportMap m_importEntries;
+
+ // Map exportName -> ExportEntry.
+ ExportMap m_exportEntries;
+
+ IdentifierSet m_starExportEntries;
+
+ // Save the occurrence order since the module loader loads and runs the modules in this order.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation
+ OrderedIdentifierSet m_requestedModules;
+};
+
+inline void ModuleRecord::appendRequestedModule(const Identifier& moduleName)
+{
+ m_requestedModules.add(moduleName.impl());
+}
+
+inline void ModuleRecord::addImportEntry(const ImportEntry& entry)
+{
+ m_importEntries.add(entry.localName.impl(), entry);
+}
+
+inline void ModuleRecord::addExportEntry(const ExportEntry& entry)
+{
+ m_exportEntries.add(entry.exportName.impl(), entry);
+}
+
+inline void ModuleRecord::addStarExportEntry(const Identifier& moduleName)
+{
+ m_starExportEntries.add(moduleName.impl());
+}
+
+inline auto ModuleRecord::lookUpImportEntry(const RefPtr<UniquedStringImpl>& localName) -> const ImportEntry&
+{
+ return (*m_importEntries.find(localName)).value;
+}
+
+} // namespace JSC
+
+#endif // ModuleRecord_h
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
new file mode 100644
index 000000000..abb72a74e
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -0,0 +1,1018 @@
+/*
+ * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeConstructors_h
+#define NodeConstructors_h
+
+#include "Nodes.h"
+#include "Lexer.h"
+#include "Parser.h"
+
+namespace JSC {
+
+ inline void* ParserArenaFreeable::operator new(size_t size, ParserArena& parserArena)
+ {
+ return parserArena.allocateFreeable(size);
+ }
+
+ inline void* ParserArenaDeletable::operator new(size_t size, ParserArena& parserArena)
+ {
+ return parserArena.allocateDeletable(size);
+ }
+
+ inline ParserArenaRoot::ParserArenaRoot(ParserArena& parserArena)
+ {
+ m_arena.swap(parserArena);
+ }
+
+ inline Node::Node(const JSTokenLocation& location)
+ : m_position(location.line, location.startOffset, location.lineStartOffset)
+ , m_endOffset(-1)
+ {
+ ASSERT(location.startOffset >= location.lineStartOffset);
+ }
+
+ inline ExpressionNode::ExpressionNode(const JSTokenLocation& location, ResultType resultType)
+ : Node(location)
+ , m_resultType(resultType)
+ {
+ }
+
+ inline StatementNode::StatementNode(const JSTokenLocation& location)
+ : Node(location)
+ , m_next(nullptr)
+ , m_lastLine(-1)
+ {
+ }
+
+ inline ConstantNode::ConstantNode(const JSTokenLocation& location, ResultType resultType)
+ : ExpressionNode(location, resultType)
+ {
+ }
+
+ inline NullNode::NullNode(const JSTokenLocation& location)
+ : ConstantNode(location, ResultType::nullType())
+ {
+ }
+
+ inline BooleanNode::BooleanNode(const JSTokenLocation& location, bool value)
+ : ConstantNode(location, ResultType::booleanType())
+ , m_value(value)
+ {
+ }
+
+ inline NumberNode::NumberNode(const JSTokenLocation& location, double value)
+ : ConstantNode(location, JSValue(value).isInt32() ? ResultType::numberTypeIsInt32() : ResultType::numberType())
+ , m_value(value)
+ {
+ }
+
+ inline DoubleNode::DoubleNode(const JSTokenLocation& location, double value)
+ : NumberNode(location, value)
+ {
+ }
+
+ inline IntegerNode::IntegerNode(const JSTokenLocation& location, double value)
+ : DoubleNode(location, value)
+ {
+ }
+
+ inline StringNode::StringNode(const JSTokenLocation& location, const Identifier& value)
+ : ConstantNode(location, ResultType::stringType())
+ , m_value(value)
+ {
+ }
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ inline TemplateExpressionListNode::TemplateExpressionListNode(ExpressionNode* node)
+ : m_node(node)
+ {
+ }
+
+ inline TemplateExpressionListNode::TemplateExpressionListNode(TemplateExpressionListNode* previous, ExpressionNode* node)
+ : m_node(node)
+ {
+ previous->m_next = this;
+ }
+
+ inline TemplateStringNode::TemplateStringNode(const JSTokenLocation& location, const Identifier& cooked, const Identifier& raw)
+ : ExpressionNode(location)
+ , m_cooked(cooked)
+ , m_raw(raw)
+ {
+ }
+
+ inline TemplateStringListNode::TemplateStringListNode(TemplateStringNode* node)
+ : m_node(node)
+ {
+ }
+
+ inline TemplateStringListNode::TemplateStringListNode(TemplateStringListNode* previous, TemplateStringNode* node)
+ : m_node(node)
+ {
+ previous->m_next = this;
+ }
+
+ inline TemplateLiteralNode::TemplateLiteralNode(const JSTokenLocation& location, TemplateStringListNode* templateStrings)
+ : ExpressionNode(location)
+ , m_templateStrings(templateStrings)
+ , m_templateExpressions(nullptr)
+ {
+ }
+
+ inline TemplateLiteralNode::TemplateLiteralNode(const JSTokenLocation& location, TemplateStringListNode* templateStrings, TemplateExpressionListNode* templateExpressions)
+ : ExpressionNode(location)
+ , m_templateStrings(templateStrings)
+ , m_templateExpressions(templateExpressions)
+ {
+ }
+
+ inline TaggedTemplateNode::TaggedTemplateNode(const JSTokenLocation& location, ExpressionNode* tag, TemplateLiteralNode* templateLiteral)
+ : ExpressionNode(location)
+ , m_tag(tag)
+ , m_templateLiteral(templateLiteral)
+ {
+ }
+#endif
+
+ inline RegExpNode::RegExpNode(const JSTokenLocation& location, const Identifier& pattern, const Identifier& flags)
+ : ExpressionNode(location)
+ , m_pattern(pattern)
+ , m_flags(flags)
+ {
+ }
+
+ inline ThisNode::ThisNode(const JSTokenLocation& location, ThisTDZMode thisTDZMode)
+ : ExpressionNode(location)
+ , m_shouldAlwaysEmitTDZCheck(thisTDZMode == ThisTDZMode::AlwaysCheck)
+ {
+ }
+
+ inline SuperNode::SuperNode(const JSTokenLocation& location)
+ : ExpressionNode(location)
+ {
+ }
+
+ inline NewTargetNode::NewTargetNode(const JSTokenLocation& location)
+ : ExpressionNode(location)
+ {
+ }
+
+ inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifier& ident, const JSTextPosition& start)
+ : ExpressionNode(location)
+ , m_ident(ident)
+ , m_start(start)
+ {
+ ASSERT(m_start.offset >= m_start.lineStartOffset);
+ }
+
+ inline ElementNode::ElementNode(int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ }
+
+ inline ElementNode::ElementNode(ElementNode* l, int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ l->m_next = this;
+ }
+
+ inline ArrayNode::ArrayNode(const JSTokenLocation& location, int elision)
+ : ExpressionNode(location)
+ , m_element(0)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(const JSTokenLocation& location, ElementNode* element)
+ : ExpressionNode(location)
+ , m_element(element)
+ , m_elision(0)
+ , m_optional(false)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(const JSTokenLocation& location, int elision, ElementNode* element)
+ : ExpressionNode(location)
+ , m_element(element)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ inline PropertyNode::PropertyNode(const Identifier& name, ExpressionNode* assign, Type type, PutType putType, SuperBinding superBinding = SuperBinding::NotNeeded)
+ : m_name(&name)
+ , m_assign(assign)
+ , m_type(type)
+ , m_needsSuperBinding(superBinding == SuperBinding::Needed)
+ , m_putType(putType)
+ {
+ }
+
+ inline PropertyNode::PropertyNode(ExpressionNode* name, ExpressionNode* assign, Type type, PutType putType)
+ : m_name(0)
+ , m_expression(name)
+ , m_assign(assign)
+ , m_type(type)
+ , m_needsSuperBinding(false)
+ , m_putType(putType)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(const JSTokenLocation& location, PropertyNode* node)
+ : ExpressionNode(location)
+ , m_node(node)
+ , m_next(0)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(const JSTokenLocation& location, PropertyNode* node, PropertyListNode* list)
+ : ExpressionNode(location)
+ , m_node(node)
+ , m_next(0)
+ {
+ list->m_next = this;
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(const JSTokenLocation& location)
+ : ExpressionNode(location)
+ , m_list(0)
+ {
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(const JSTokenLocation& location, PropertyListNode* list)
+ : ExpressionNode(location)
+ , m_list(list)
+ {
+ }
+
+ inline BracketAccessorNode::BracketAccessorNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments)
+ : ExpressionNode(location)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ {
+ }
+
+ inline DotAccessorNode::DotAccessorNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident)
+ : ExpressionNode(location)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+
+ inline SpreadExpressionNode::SpreadExpressionNode(const JSTokenLocation& location, ExpressionNode* expression)
+ : ExpressionNode(location)
+ , m_expression(expression)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(const JSTokenLocation& location, ArgumentListNode* listNode, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ listNode->m_next = this;
+ }
+
+ inline ArgumentsNode::ArgumentsNode()
+ : m_listNode(0)
+ {
+ }
+
+ inline ArgumentsNode::ArgumentsNode(ArgumentListNode* listNode)
+ : m_listNode(listNode)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_expr(expr)
+ , m_args(0)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(const JSTokenLocation& location, ExpressionNode* expr, ArgumentsNode* args)
+ : ExpressionNode(location)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ inline EvalFunctionCallNode::EvalFunctionCallNode(const JSTokenLocation& location, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallValueNode::FunctionCallValueNode(const JSTokenLocation& location, ExpressionNode* expr, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ ASSERT(divot.offset >= divotStart.offset);
+ }
+
+ inline FunctionCallResolveNode::FunctionCallResolveNode(const JSTokenLocation& location, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallBracketNode::FunctionCallBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_args(args)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ {
+ }
+
+ inline FunctionCallDotNode::FunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline BytecodeIntrinsicNode::BytecodeIntrinsicNode(const JSTokenLocation& location, EmitterType emitter, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_emitter(emitter)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline CallFunctionCallDotNode::CallFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
+ {
+ }
+
+ inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
+ {
+ }
+
+ inline PostfixNode::PostfixNode(const JSTokenLocation& location, ExpressionNode* expr, Operator oper, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : PrefixNode(location, expr, oper, divot, divotStart, divotEnd)
+ {
+ }
+
+ inline DeleteResolveNode::DeleteResolveNode(const JSTokenLocation& location, const Identifier& ident, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteBracketNode::DeleteBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ inline DeleteDotNode::DeleteDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteValueNode::DeleteValueNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_expr(expr)
+ {
+ }
+
+ inline VoidNode::VoidNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_expr(expr)
+ {
+ }
+
+ inline TypeOfResolveNode::TypeOfResolveNode(const JSTokenLocation& location, const Identifier& ident)
+ : ExpressionNode(location, ResultType::stringType())
+ , m_ident(ident)
+ {
+ }
+
+ inline TypeOfValueNode::TypeOfValueNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location, ResultType::stringType())
+ , m_expr(expr)
+ {
+ }
+
+ inline PrefixNode::PrefixNode(const JSTokenLocation& location, ExpressionNode* expr, Operator oper, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowablePrefixedSubExpressionData(divot, divotStart, divotEnd)
+ , m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ inline UnaryOpNode::UnaryOpNode(const JSTokenLocation& location, ResultType type, ExpressionNode* expr, OpcodeID opcodeID)
+ : ExpressionNode(location, type)
+ , m_expr(expr)
+ , m_opcodeID(opcodeID)
+ {
+ }
+
+ inline UnaryPlusNode::UnaryPlusNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : UnaryOpNode(location, ResultType::numberType(), expr, op_to_number)
+ {
+ }
+
+ inline NegateNode::NegateNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : UnaryOpNode(location, ResultType::numberType(), expr, op_negate)
+ {
+ }
+
+ inline BitwiseNotNode::BitwiseNotNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location, ResultType::forBitOp())
+ , m_expr(expr)
+ {
+ }
+
+ inline LogicalNotNode::LogicalNotNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : UnaryOpNode(location, ResultType::booleanType(), expr, op_not)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(location)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(const JSTokenLocation& location, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(location, type)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline MultNode::MultNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_mul, rightHasAssignments)
+ {
+ }
+
+ inline DivNode::DivNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_div, rightHasAssignments)
+ {
+ }
+
+
+ inline ModNode::ModNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_mod, rightHasAssignments)
+ {
+ }
+
+ inline AddNode::AddNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_add, rightHasAssignments)
+ {
+ }
+
+ inline SubNode::SubNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_sub, rightHasAssignments)
+ {
+ }
+
+ inline LeftShiftNode::LeftShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forBitOp(), expr1, expr2, op_lshift, rightHasAssignments)
+ {
+ }
+
+ inline RightShiftNode::RightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forBitOp(), expr1, expr2, op_rshift, rightHasAssignments)
+ {
+ }
+
+ inline UnsignedRightShiftNode::UnsignedRightShiftNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::numberType(), expr1, expr2, op_urshift, rightHasAssignments)
+ {
+ }
+
+ inline LessNode::LessNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments)
+ {
+ }
+
+ inline GreaterNode::GreaterNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_greater, rightHasAssignments)
+ {
+ }
+
+ inline LessEqNode::LessEqNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments)
+ {
+ }
+
+ inline GreaterEqNode::GreaterEqNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_greatereq, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(const JSTokenLocation& location, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(location, type, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(location, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline InstanceOfNode::InstanceOfNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_instanceof, rightHasAssignments)
+ {
+ }
+
+ inline InNode::InNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(location, expr1, expr2, op_in, rightHasAssignments)
+ {
+ }
+
+ inline EqualNode::EqualNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_eq, rightHasAssignments)
+ {
+ }
+
+ inline NotEqualNode::NotEqualNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_neq, rightHasAssignments)
+ {
+ }
+
+ inline StrictEqualNode::StrictEqualNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_stricteq, rightHasAssignments)
+ {
+ }
+
+ inline NotStrictEqualNode::NotStrictEqualNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::booleanType(), expr1, expr2, op_nstricteq, rightHasAssignments)
+ {
+ }
+
+ inline BitAndNode::BitAndNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forBitOp(), expr1, expr2, op_bitand, rightHasAssignments)
+ {
+ }
+
+ inline BitOrNode::BitOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forBitOp(), expr1, expr2, op_bitor, rightHasAssignments)
+ {
+ }
+
+ inline BitXOrNode::BitXOrNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(location, ResultType::forBitOp(), expr1, expr2, op_bitxor, rightHasAssignments)
+ {
+ }
+
+ inline LogicalOpNode::LogicalOpNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper)
+ : ExpressionNode(location, ResultType::forLogicalOp(expr1->resultDescriptor(), expr2->resultDescriptor()))
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_operator(oper)
+ {
+ }
+
+ inline ConditionalNode::ConditionalNode(const JSTokenLocation& location, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2)
+ : ExpressionNode(location)
+ , m_logical(logical)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ inline ReadModifyResolveNode::ReadModifyResolveNode(const JSTokenLocation& location, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignResolveNode::AssignResolveNode(const JSTokenLocation& location, const Identifier& ident, ExpressionNode* right, AssignmentContext assignmentContext)
+ : ExpressionNode(location)
+ , m_ident(ident)
+ , m_right(right)
+ , m_assignmentContext(assignmentContext)
+ {
+ }
+
+
+ inline ReadModifyBracketNode::ReadModifyBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_operator(oper)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignBracketNode::AssignBracketNode(const JSTokenLocation& location, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignDotNode::AssignDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReadModifyDotNode::ReadModifyDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableSubExpressionData(divot, divotStart, divotEnd)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignErrorNode::AssignErrorNode(const JSTokenLocation& location, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ExpressionNode(location)
+ , ThrowableExpressionData(divot, divotStart, divotEnd)
+ {
+ }
+
+ inline CommaNode::CommaNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : ExpressionNode(location)
+ , m_expr(expr)
+ , m_next(nullptr)
+ {
+ }
+
+ inline SourceElements::SourceElements()
+ : m_head(nullptr)
+ , m_tail(nullptr)
+ {
+ }
+
+ inline EmptyStatementNode::EmptyStatementNode(const JSTokenLocation& location)
+ : StatementNode(location)
+ {
+ }
+
+ inline DebuggerStatementNode::DebuggerStatementNode(const JSTokenLocation& location)
+ : StatementNode(location)
+ {
+ }
+
+ inline ExprStatementNode::ExprStatementNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : StatementNode(location)
+ , m_expr(expr)
+ {
+ }
+
+ inline DeclarationStatement::DeclarationStatement(const JSTokenLocation& location, ExpressionNode* expr)
+ : StatementNode(location)
+ , m_expr(expr)
+ {
+ }
+
+ inline ModuleDeclarationNode::ModuleDeclarationNode(const JSTokenLocation& location)
+ : StatementNode(location)
+ {
+ }
+
+ inline ModuleNameNode::ModuleNameNode(const JSTokenLocation& location, const Identifier& moduleName)
+ : Node(location)
+ , m_moduleName(moduleName)
+ {
+ }
+
+ inline ImportSpecifierNode::ImportSpecifierNode(const JSTokenLocation& location, const Identifier& importedName, const Identifier& localName)
+ : Node(location)
+ , m_importedName(importedName)
+ , m_localName(localName)
+ {
+ }
+
+ inline ImportDeclarationNode::ImportDeclarationNode(const JSTokenLocation& location, ImportSpecifierListNode* importSpecifierList, ModuleNameNode* moduleName)
+ : ModuleDeclarationNode(location)
+ , m_specifierList(importSpecifierList)
+ , m_moduleName(moduleName)
+ {
+ }
+
+ inline ExportAllDeclarationNode::ExportAllDeclarationNode(const JSTokenLocation& location, ModuleNameNode* moduleName)
+ : ModuleDeclarationNode(location)
+ , m_moduleName(moduleName)
+ {
+ }
+
+ inline ExportDefaultDeclarationNode::ExportDefaultDeclarationNode(const JSTokenLocation& location, StatementNode* declaration, const Identifier& localName)
+ : ModuleDeclarationNode(location)
+ , m_declaration(declaration)
+ , m_localName(localName)
+ {
+ }
+
+ inline ExportLocalDeclarationNode::ExportLocalDeclarationNode(const JSTokenLocation& location, StatementNode* declaration)
+ : ModuleDeclarationNode(location)
+ , m_declaration(declaration)
+ {
+ }
+
+ inline ExportNamedDeclarationNode::ExportNamedDeclarationNode(const JSTokenLocation& location, ExportSpecifierListNode* exportSpecifierList, ModuleNameNode* moduleName)
+ : ModuleDeclarationNode(location)
+ , m_specifierList(exportSpecifierList)
+ , m_moduleName(moduleName)
+ {
+ }
+
+ inline ExportSpecifierNode::ExportSpecifierNode(const JSTokenLocation& location, const Identifier& localName, const Identifier& exportedName)
+ : Node(location)
+ , m_localName(localName)
+ , m_exportedName(exportedName)
+ {
+ }
+
+ inline EmptyVarExpression::EmptyVarExpression(const JSTokenLocation& location, const Identifier& ident)
+ : ExpressionNode(location)
+ , m_ident(ident)
+ {
+ }
+
+ inline EmptyLetExpression::EmptyLetExpression(const JSTokenLocation& location, const Identifier& ident)
+ : ExpressionNode(location)
+ , m_ident(ident)
+ {
+ }
+
+ inline IfElseNode::IfElseNode(const JSTokenLocation& location, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
+ : StatementNode(location)
+ , m_condition(condition)
+ , m_ifBlock(ifBlock)
+ , m_elseBlock(elseBlock)
+ {
+ }
+
+ inline DoWhileNode::DoWhileNode(const JSTokenLocation& location, StatementNode* statement, ExpressionNode* expr)
+ : StatementNode(location)
+ , m_statement(statement)
+ , m_expr(expr)
+ {
+ }
+
+ inline WhileNode::WhileNode(const JSTokenLocation& location, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(location)
+ , m_expr(expr)
+ , m_statement(statement)
+ {
+ }
+
+ inline ForNode::ForNode(const JSTokenLocation& location, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, VariableEnvironment& lexicalVariables)
+ : StatementNode(location)
+ , VariableEnvironmentNode(lexicalVariables)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_expr3(expr3)
+ , m_statement(statement)
+ {
+ ASSERT(statement);
+ }
+
+ inline ContinueNode::ContinueNode(const JSTokenLocation& location, const Identifier& ident)
+ : StatementNode(location)
+ , m_ident(ident)
+ {
+ }
+
+ inline BreakNode::BreakNode(const JSTokenLocation& location, const Identifier& ident)
+ : StatementNode(location)
+ , m_ident(ident)
+ {
+ }
+
+ inline ReturnNode::ReturnNode(const JSTokenLocation& location, ExpressionNode* value)
+ : StatementNode(location)
+ , m_value(value)
+ {
+ }
+
+ inline WithNode::WithNode(const JSTokenLocation& location, ExpressionNode* expr, StatementNode* statement, const JSTextPosition& divot, uint32_t expressionLength)
+ : StatementNode(location)
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_divot(divot)
+ , m_expressionLength(expressionLength)
+ {
+ }
+
+ inline LabelNode::LabelNode(const JSTokenLocation& location, const Identifier& name, StatementNode* statement)
+ : StatementNode(location)
+ , m_name(name)
+ , m_statement(statement)
+ {
+ }
+
+ inline ThrowNode::ThrowNode(const JSTokenLocation& location, ExpressionNode* expr)
+ : StatementNode(location)
+ , m_expr(expr)
+ {
+ }
+
+ inline TryNode::TryNode(const JSTokenLocation& location, StatementNode* tryBlock, const Identifier& thrownValueIdent, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock)
+ : StatementNode(location)
+ , m_tryBlock(tryBlock)
+ , m_thrownValueIdent(thrownValueIdent)
+ , m_catchBlock(catchBlock)
+ , m_finallyBlock(finallyBlock)
+ {
+ m_catchEnvironment.swap(catchEnvironment);
+ }
+
+ inline FunctionParameters::FunctionParameters()
+ {
+ }
+
+ inline FuncExprNode::FuncExprNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+ : ExpressionNode(location)
+ , m_metadata(m_metadata)
+ {
+ m_metadata->finishParsing(source, ident, FunctionExpression);
+ }
+
+ inline FuncDeclNode::FuncDeclNode(const JSTokenLocation& location, const Identifier& ident, FunctionMetadataNode* m_metadata, const SourceCode& source)
+ : StatementNode(location)
+ , m_metadata(m_metadata)
+ {
+ m_metadata->finishParsing(source, ident, FunctionDeclaration);
+ }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ inline ClassDeclNode::ClassDeclNode(const JSTokenLocation& location, ExpressionNode* classDeclaration)
+ : StatementNode(location)
+ , m_classDeclaration(classDeclaration)
+ {
+ }
+
+ inline ClassExprNode::ClassExprNode(const JSTokenLocation& location, const Identifier& name, ExpressionNode* constructorExpression, ExpressionNode* classHeritage, PropertyListNode* instanceMethods, PropertyListNode* staticMethods)
+ : ExpressionNode(location)
+ , m_name(name)
+ , m_constructorExpression(constructorExpression)
+ , m_classHeritage(classHeritage)
+ , m_instanceMethods(instanceMethods)
+ , m_staticMethods(staticMethods)
+ {
+ }
+#endif
+
+ inline CaseClauseNode::CaseClauseNode(ExpressionNode* expr, SourceElements* statements)
+ : m_expr(expr)
+ , m_statements(statements)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(ClauseListNode* clauseList, CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ clauseList->m_next = this;
+ }
+
+ inline CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
+ : m_list1(list1)
+ , m_defaultClause(defaultClause)
+ , m_list2(list2)
+ {
+ }
+
+ inline SwitchNode::SwitchNode(const JSTokenLocation& location, ExpressionNode* expr, CaseBlockNode* block, VariableEnvironment& lexicalVariables)
+ : StatementNode(location)
+ , VariableEnvironmentNode(lexicalVariables)
+ , m_expr(expr)
+ , m_block(block)
+ {
+ }
+
+ inline BlockNode::BlockNode(const JSTokenLocation& location, SourceElements* statements, VariableEnvironment& lexicalVariables)
+ : StatementNode(location)
+ , VariableEnvironmentNode(lexicalVariables)
+ , m_statements(statements)
+ {
+ }
+
+ inline EnumerationNode::EnumerationNode(const JSTokenLocation& location, ExpressionNode* lexpr, ExpressionNode* expr, StatementNode* statement, VariableEnvironment& lexicalVariables)
+ : StatementNode(location)
+ , VariableEnvironmentNode(lexicalVariables)
+ , m_lexpr(lexpr)
+ , m_expr(expr)
+ , m_statement(statement)
+ {
+ ASSERT(lexpr);
+ }
+
+ inline ForInNode::ForInNode(const JSTokenLocation& location, ExpressionNode* lexpr, ExpressionNode* expr, StatementNode* statement, VariableEnvironment& lexicalVariables)
+ : EnumerationNode(location, lexpr, expr, statement, lexicalVariables)
+ {
+ }
+
+ inline ForOfNode::ForOfNode(const JSTokenLocation& location, ExpressionNode* lexpr, ExpressionNode* expr, StatementNode* statement, VariableEnvironment& lexicalVariables)
+ : EnumerationNode(location, lexpr, expr, statement, lexicalVariables)
+ {
+ }
+
+ inline DestructuringPatternNode::DestructuringPatternNode()
+ {
+ }
+
+ inline ArrayPatternNode::ArrayPatternNode()
+ : DestructuringPatternNode()
+ {
+ }
+
+ inline ObjectPatternNode::ObjectPatternNode()
+ : DestructuringPatternNode()
+ {
+ }
+
+ inline BindingNode::BindingNode(const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end, AssignmentContext context)
+ : DestructuringPatternNode()
+ , m_divotStart(start)
+ , m_divotEnd(end)
+ , m_boundProperty(boundProperty)
+ , m_bindingContext(context)
+ {
+ }
+
+ inline DestructuringAssignmentNode::DestructuringAssignmentNode(const JSTokenLocation& location, DestructuringPatternNode* bindings, ExpressionNode* initializer)
+ : ExpressionNode(location)
+ , m_bindings(bindings)
+ , m_initializer(initializer)
+ {
+ }
+
+} // namespace JSC
+
+#endif // NodeConstructors_h
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
new file mode 100644
index 000000000..cf4fe450a
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -0,0 +1,205 @@
+/*
+* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+* Copyright (C) 2001 Peter Kelly (pmk@post.com)
+* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
+* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+* Copyright (C) 2007 Maks Orlovich
+* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public License
+* along with this library; see the file COPYING.LIB. If not, write to
+* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "config.h"
+#include "Nodes.h"
+#include "NodeConstructors.h"
+
+#include "CallFrame.h"
+#include "Debugger.h"
+#include "JIT.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "LabelScope.h"
+#include "Lexer.h"
+#include "JSCInlines.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "RegExpObject.h"
+#include "SamplingTool.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/Threading.h>
+
+using namespace WTF;
+
+namespace JSC {
+
+
+// ------------------------------ StatementNode --------------------------------
+
+void StatementNode::setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
+{
+ m_lastLine = lastLine;
+ m_position = JSTextPosition(firstLine, startOffset, lineStartOffset);
+ ASSERT(m_position.offset >= m_position.lineStartOffset);
+}
+
+// ------------------------------ SourceElements --------------------------------
+
+void SourceElements::append(StatementNode* statement)
+{
+ if (statement->isEmptyStatement())
+ return;
+
+ if (!m_head) {
+ m_head = statement;
+ m_tail = statement;
+ return;
+ }
+
+ m_tail->setNext(statement);
+ m_tail = statement;
+}
+
+StatementNode* SourceElements::singleStatement() const
+{
+ return m_head == m_tail ? m_head : nullptr;
+}
+
+// ------------------------------ ScopeNode -----------------------------
+
+ScopeNode::ScopeNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, bool inStrictContext)
+ : StatementNode(endLocation)
+ , ParserArenaRoot(parserArena)
+ , m_startLineNumber(startLocation.line)
+ , m_startStartOffset(startLocation.startOffset)
+ , m_startLineStartOffset(startLocation.lineStartOffset)
+ , m_features(inStrictContext ? StrictModeFeature : NoFeatures)
+ , m_numConstants(0)
+ , m_statements(0)
+{
+}
+
+ScopeNode::ScopeNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, const SourceCode& source, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack& funcStack, VariableEnvironment& lexicalVariables, CodeFeatures features, int numConstants)
+ : StatementNode(endLocation)
+ , ParserArenaRoot(parserArena)
+ , VariableEnvironmentNode(lexicalVariables)
+ , m_startLineNumber(startLocation.line)
+ , m_startStartOffset(startLocation.startOffset)
+ , m_startLineStartOffset(startLocation.lineStartOffset)
+ , m_features(features)
+ , m_source(source)
+ , m_numConstants(numConstants)
+ , m_statements(children)
+{
+ m_varDeclarations.swap(varEnvironment);
+ m_functionStack.swap(funcStack);
+}
+
+StatementNode* ScopeNode::singleStatement() const
+{
+ return m_statements ? m_statements->singleStatement() : 0;
+}
+
+// ------------------------------ ProgramNode -----------------------------
+
+ProgramNode::ProgramNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack& funcStack, VariableEnvironment& lexicalVariables, FunctionParameters*, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, funcStack, lexicalVariables, features, numConstants)
+ , m_startColumn(startColumn)
+ , m_endColumn(endColumn)
+{
+}
+
+void ProgramNode::setClosedVariables(Vector<RefPtr<UniquedStringImpl>>&& closedVariables)
+{
+ m_closedVariables = WTF::move(closedVariables);
+}
+
+// ------------------------------ ModuleProgramNode -----------------------------
+
+ModuleProgramNode::ModuleProgramNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack& funcStack, VariableEnvironment& lexicalVariables, FunctionParameters*, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, funcStack, lexicalVariables, features, numConstants)
+ , m_startColumn(startColumn)
+ , m_endColumn(endColumn)
+{
+}
+
+// ------------------------------ EvalNode -----------------------------
+
+EvalNode::EvalNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned, unsigned endColumn, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack& funcStack, VariableEnvironment& lexicalVariables, FunctionParameters*, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(parserArena, startLocation, endLocation, source, children, varEnvironment, funcStack, lexicalVariables, features, numConstants)
+ , m_endColumn(endColumn)
+{
+}
+
+// ------------------------------ FunctionMetadataNode -----------------------------
+
+FunctionMetadataNode::FunctionMetadataNode(
+ ParserArena&, const JSTokenLocation& startLocation,
+ const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn,
+ int functionKeywordStart, int functionNameStart, int parametersStart, bool isInStrictContext,
+ ConstructorKind constructorKind, unsigned parameterCount, SourceParseMode mode)
+ : Node(endLocation)
+ , m_startColumn(startColumn)
+ , m_endColumn(endColumn)
+ , m_functionKeywordStart(functionKeywordStart)
+ , m_functionNameStart(functionNameStart)
+ , m_parametersStart(parametersStart)
+ , m_startStartOffset(startLocation.startOffset)
+ , m_parameterCount(parameterCount)
+ , m_parseMode(mode)
+ , m_isInStrictContext(isInStrictContext)
+ , m_constructorKind(static_cast<unsigned>(constructorKind))
+{
+ ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
+}
+
+void FunctionMetadataNode::finishParsing(const SourceCode& source, const Identifier& ident, enum FunctionMode functionMode)
+{
+ m_source = source;
+ m_ident = ident;
+ m_functionMode = functionMode;
+}
+
+void FunctionMetadataNode::setEndPosition(JSTextPosition position)
+{
+ m_lastLine = position.line;
+ m_endColumn = position.offset - position.lineStartOffset;
+}
+
+// ------------------------------ FunctionNode -----------------------------
+
+FunctionNode::FunctionNode(ParserArena& parserArena, const JSTokenLocation& startLocation, const JSTokenLocation& endLocation, unsigned startColumn, unsigned endColumn, SourceElements* children, VariableEnvironment& varEnvironment, FunctionStack& funcStack, VariableEnvironment& lexicalVariables, FunctionParameters* parameters, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+ : ScopeNode(parserArena, startLocation, endLocation, sourceCode, children, varEnvironment, funcStack, lexicalVariables, features, numConstants)
+ , m_parameters(parameters)
+ , m_startColumn(startColumn)
+ , m_endColumn(endColumn)
+{
+}
+
+void FunctionNode::finishParsing(const Identifier& ident, enum FunctionMode functionMode)
+{
+ ASSERT(!source().isNull());
+ m_ident = ident;
+ m_functionMode = functionMode;
+}
+
+VariableEnvironmentNode::VariableEnvironmentNode(VariableEnvironment& lexicalVariables)
+{
+ m_lexicalVariables.swap(lexicalVariables);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
new file mode 100644
index 000000000..1d6b03d77
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -0,0 +1,2127 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Nodes_h
+#define Nodes_h
+
+#include "Error.h"
+#include "JITCode.h"
+#include "Opcode.h"
+#include "ParserArena.h"
+#include "ParserTokens.h"
+#include "ResultType.h"
+#include "SourceCode.h"
+#include "SymbolTable.h"
+#include "VariableEnvironment.h"
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+ class ArgumentListNode;
+ class BytecodeGenerator;
+ class FunctionMetadataNode;
+ class FunctionParameters;
+ class Label;
+ class PropertyListNode;
+ class ReadModifyResolveNode;
+ class RegisterID;
+ class JSScope;
+ class ScopeNode;
+ class ModuleAnalyzer;
+
+ enum Operator {
+ OpEqual,
+ OpPlusEq,
+ OpMinusEq,
+ OpMultEq,
+ OpDivEq,
+ OpPlusPlus,
+ OpMinusMinus,
+ OpAndEq,
+ OpXOrEq,
+ OpOrEq,
+ OpModEq,
+ OpLShift,
+ OpRShift,
+ OpURShift
+ };
+
+ enum LogicalOperator {
+ OpLogicalAnd,
+ OpLogicalOr
+ };
+
+ enum FallThroughMode {
+ FallThroughMeansTrue = 0,
+ FallThroughMeansFalse = 1
+ };
+ inline FallThroughMode invert(FallThroughMode fallThroughMode) { return static_cast<FallThroughMode>(!fallThroughMode); }
+
+ typedef HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> IdentifierSet;
+
+ namespace DeclarationStacks {
+ typedef Vector<FunctionMetadataNode*> FunctionStack;
+ }
+
+ struct SwitchInfo {
+ enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString };
+ uint32_t bytecodeOffset;
+ SwitchType switchType;
+ };
+
+ enum class AssignmentContext {
+ DeclarationStatement,
+ ConstDeclarationStatement,
+ AssignmentExpression
+ };
+
+ class ParserArenaFreeable {
+ public:
+ // ParserArenaFreeable objects are are freed when the arena is deleted.
+ // Destructors are not called. Clients must not call delete on such objects.
+ void* operator new(size_t, ParserArena&);
+ };
+
+ class ParserArenaDeletable {
+ public:
+ virtual ~ParserArenaDeletable() { }
+
+ // ParserArenaDeletable objects are deleted when the arena is deleted.
+ // Clients must not call delete directly on such objects.
+ void* operator new(size_t, ParserArena&);
+ };
+
+ class ParserArenaRoot {
+ WTF_MAKE_FAST_ALLOCATED;
+ protected:
+ ParserArenaRoot(ParserArena&);
+
+ public:
+ ParserArena& parserArena() { return m_arena; }
+ virtual ~ParserArenaRoot() { }
+
+ protected:
+ ParserArena m_arena;
+ };
+
+ class Node : public ParserArenaFreeable {
+ protected:
+ Node(const JSTokenLocation&);
+
+ public:
+ virtual ~Node() { }
+
+ int firstLine() const { return m_position.line; }
+ int startOffset() const { return m_position.offset; }
+ int endOffset() const { return m_endOffset; }
+ int lineStartOffset() const { return m_position.lineStartOffset; }
+ const JSTextPosition& position() const { return m_position; }
+ void setEndOffset(int offset) { m_endOffset = offset; }
+ void setStartOffset(int offset) { m_position.offset = offset; }
+
+ protected:
+ JSTextPosition m_position;
+ int m_endOffset;
+ };
+
+ class ExpressionNode : public Node {
+ protected:
+ ExpressionNode(const JSTokenLocation&, ResultType = ResultType::unknownType());
+
+ public:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0;
+
+ virtual bool isNumber() const { return false; }
+ virtual bool isString() const { return false; }
+ virtual bool isNull() const { return false; }
+ virtual bool isPure(BytecodeGenerator&) const { return false; }
+ virtual bool isConstant() const { return false; }
+ virtual bool isLocation() const { return false; }
+ virtual bool isAssignmentLocation() const { return isLocation(); }
+ virtual bool isResolveNode() const { return false; }
+ virtual bool isBracketAccessorNode() const { return false; }
+ virtual bool isDotAccessorNode() const { return false; }
+ virtual bool isDestructuringNode() const { return false; }
+ virtual bool isFuncExprNode() const { return false; }
+ virtual bool isCommaNode() const { return false; }
+ virtual bool isSimpleArray() const { return false; }
+ virtual bool isAdd() const { return false; }
+ virtual bool isSubtract() const { return false; }
+ virtual bool isBoolean() const { return false; }
+ virtual bool isSpreadExpression() const { return false; }
+ virtual bool isSuperNode() const { return false; }
+
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, FallThroughMode);
+
+ virtual ExpressionNode* stripUnaryPlus() { return this; }
+
+ ResultType resultDescriptor() const { return m_resultType; }
+
+ private:
+ ResultType m_resultType;
+ };
+
+ class StatementNode : public Node {
+ protected:
+ StatementNode(const JSTokenLocation&);
+
+ public:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0;
+
+ void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset);
+ unsigned lastLine() const { return m_lastLine; }
+
+ StatementNode* next() { return m_next; }
+ void setNext(StatementNode* next) { m_next = next; }
+
+ virtual bool isEmptyStatement() const { return false; }
+ virtual bool isReturnNode() const { return false; }
+ virtual bool isExprStatement() const { return false; }
+ virtual bool isBreak() const { return false; }
+ virtual bool isContinue() const { return false; }
+ virtual bool isBlock() const { return false; }
+ virtual bool isFuncDeclNode() const { return false; }
+ virtual bool isModuleDeclarationNode() const { return false; }
+
+ protected:
+ StatementNode* m_next;
+ int m_lastLine;
+ };
+
+ class VariableEnvironmentNode {
+ public:
+ VariableEnvironmentNode()
+ {
+ }
+
+ VariableEnvironmentNode(VariableEnvironment& lexicalDeclaredVariables);
+
+ VariableEnvironment& lexicalVariables() { return m_lexicalVariables; }
+
+ protected:
+ VariableEnvironment m_lexicalVariables;
+ };
+
+ class ConstantNode : public ExpressionNode {
+ public:
+ ConstantNode(const JSTokenLocation&, ResultType);
+ virtual bool isPure(BytecodeGenerator&) const override { return true; }
+ virtual bool isConstant() const override { return true; }
+ virtual JSValue jsValue(BytecodeGenerator&) const = 0;
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override;
+ };
+
+ class NullNode : public ConstantNode {
+ public:
+ NullNode(const JSTokenLocation&);
+
+ private:
+ virtual bool isNull() const override { return true; }
+ virtual JSValue jsValue(BytecodeGenerator&) const override { return jsNull(); }
+ };
+
+ class BooleanNode : public ConstantNode {
+ public:
+ BooleanNode(const JSTokenLocation&, bool value);
+ bool value() { return m_value; }
+
+ private:
+ virtual bool isBoolean() const override { return true; }
+ virtual JSValue jsValue(BytecodeGenerator&) const override { return jsBoolean(m_value); }
+
+ bool m_value;
+ };
+
+ class NumberNode : public ConstantNode {
+ public:
+ NumberNode(const JSTokenLocation&, double value);
+ double value() const { return m_value; }
+ virtual bool isIntegerNode() const = 0;
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override final;
+
+ private:
+ virtual bool isNumber() const override final { return true; }
+ virtual JSValue jsValue(BytecodeGenerator&) const override { return jsNumber(m_value); }
+
+ double m_value;
+ };
+
+ class DoubleNode : public NumberNode {
+ public:
+ DoubleNode(const JSTokenLocation&, double value);
+
+ private:
+ virtual bool isIntegerNode() const override { return false; }
+ };
+
+ // An integer node represent a number represented as an integer (e.g. 42 instead of 42., 42.0, 42e0)
+ class IntegerNode : public DoubleNode {
+ public:
+ IntegerNode(const JSTokenLocation&, double value);
+ virtual bool isIntegerNode() const override final { return true; }
+ };
+
+ class StringNode : public ConstantNode {
+ public:
+ StringNode(const JSTokenLocation&, const Identifier&);
+ const Identifier& value() { return m_value; }
+
+ private:
+ virtual bool isString() const override { return true; }
+ virtual JSValue jsValue(BytecodeGenerator&) const override;
+
+ const Identifier& m_value;
+ };
+
+ class ThrowableExpressionData {
+ public:
+ ThrowableExpressionData()
+ : m_divot(-1, -1, -1)
+ , m_divotStart(-1, -1, -1)
+ , m_divotEnd(-1, -1, -1)
+ {
+ }
+
+ ThrowableExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+ : m_divot(divot)
+ , m_divotStart(start)
+ , m_divotEnd(end)
+ {
+ ASSERT(m_divot.offset >= m_divot.lineStartOffset);
+ ASSERT(m_divotStart.offset >= m_divotStart.lineStartOffset);
+ ASSERT(m_divotEnd.offset >= m_divotEnd.lineStartOffset);
+ }
+
+ void setExceptionSourceCode(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ {
+ ASSERT(divot.offset >= divot.lineStartOffset);
+ ASSERT(divotStart.offset >= divotStart.lineStartOffset);
+ ASSERT(divotEnd.offset >= divotEnd.lineStartOffset);
+ m_divot = divot;
+ m_divotStart = divotStart;
+ m_divotEnd = divotEnd;
+ }
+
+ const JSTextPosition& divot() const { return m_divot; }
+ const JSTextPosition& divotStart() const { return m_divotStart; }
+ const JSTextPosition& divotEnd() const { return m_divotEnd; }
+
+ protected:
+ RegisterID* emitThrowReferenceError(BytecodeGenerator&, const String& message);
+
+ private:
+ JSTextPosition m_divot;
+ JSTextPosition m_divotStart;
+ JSTextPosition m_divotEnd;
+ };
+
+ class ThrowableSubExpressionData : public ThrowableExpressionData {
+ public:
+ ThrowableSubExpressionData()
+ : m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
+ , m_subexpressionLineOffset(0)
+ , m_subexpressionLineStartOffset(0)
+ {
+ }
+
+ ThrowableSubExpressionData(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
+ : ThrowableExpressionData(divot, divotStart, divotEnd)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
+ , m_subexpressionLineOffset(0)
+ , m_subexpressionLineStartOffset(0)
+ {
+ }
+
+ void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset)
+ {
+ ASSERT(subexpressionDivot.offset <= divot().offset);
+ // Overflow means we can't do this safely, so just point at the primary divot,
+ // divotLine, or divotLineStart.
+ if ((divot() - subexpressionDivot.offset) & ~0xFFFF)
+ return;
+ if ((divot().line - subexpressionDivot.line) & ~0xFFFF)
+ return;
+ if ((divot().lineStartOffset - subexpressionDivot.lineStartOffset) & ~0xFFFF)
+ return;
+ if ((divotEnd() - subexpressionOffset) & ~0xFFFF)
+ return;
+ m_subexpressionDivotOffset = divot() - subexpressionDivot.offset;
+ m_subexpressionEndOffset = divotEnd() - subexpressionOffset;
+ m_subexpressionLineOffset = divot().line - subexpressionDivot.line;
+ m_subexpressionLineStartOffset = divot().lineStartOffset - subexpressionDivot.lineStartOffset;
+ }
+
+ JSTextPosition subexpressionDivot()
+ {
+ int newLine = divot().line - m_subexpressionLineOffset;
+ int newOffset = divot().offset - m_subexpressionDivotOffset;
+ int newLineStartOffset = divot().lineStartOffset - m_subexpressionLineStartOffset;
+ return JSTextPosition(newLine, newOffset, newLineStartOffset);
+ }
+ JSTextPosition subexpressionStart() { return divotStart(); }
+ JSTextPosition subexpressionEnd() { return divotEnd() - static_cast<int>(m_subexpressionEndOffset); }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionEndOffset;
+ uint16_t m_subexpressionLineOffset;
+ uint16_t m_subexpressionLineStartOffset;
+ };
+
+ class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData {
+ public:
+ ThrowablePrefixedSubExpressionData()
+ : m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
+ , m_subexpressionLineOffset(0)
+ , m_subexpressionLineStartOffset(0)
+ {
+ }
+
+ ThrowablePrefixedSubExpressionData(const JSTextPosition& divot, const JSTextPosition& start, const JSTextPosition& end)
+ : ThrowableExpressionData(divot, start, end)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
+ , m_subexpressionLineOffset(0)
+ , m_subexpressionLineStartOffset(0)
+ {
+ }
+
+ void setSubexpressionInfo(const JSTextPosition& subexpressionDivot, int subexpressionOffset)
+ {
+ ASSERT(subexpressionDivot.offset >= divot().offset);
+ // Overflow means we can't do this safely, so just point at the primary divot,
+ // divotLine, or divotLineStart.
+ if ((subexpressionDivot.offset - divot()) & ~0xFFFF)
+ return;
+ if ((subexpressionDivot.line - divot().line) & ~0xFFFF)
+ return;
+ if ((subexpressionDivot.lineStartOffset - divot().lineStartOffset) & ~0xFFFF)
+ return;
+ if ((subexpressionOffset - divotStart()) & ~0xFFFF)
+ return;
+ m_subexpressionDivotOffset = subexpressionDivot.offset - divot();
+ m_subexpressionStartOffset = subexpressionOffset - divotStart();
+ m_subexpressionLineOffset = subexpressionDivot.line - divot().line;
+ m_subexpressionLineStartOffset = subexpressionDivot.lineStartOffset - divot().lineStartOffset;
+ }
+
+ JSTextPosition subexpressionDivot()
+ {
+ int newLine = divot().line + m_subexpressionLineOffset;
+ int newOffset = divot().offset + m_subexpressionDivotOffset;
+ int newLineStartOffset = divot().lineStartOffset + m_subexpressionLineStartOffset;
+ return JSTextPosition(newLine, newOffset, newLineStartOffset);
+ }
+ JSTextPosition subexpressionStart() { return divotStart() + static_cast<int>(m_subexpressionStartOffset); }
+ JSTextPosition subexpressionEnd() { return divotEnd(); }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionStartOffset;
+ uint16_t m_subexpressionLineOffset;
+ uint16_t m_subexpressionLineStartOffset;
+ };
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ class TemplateExpressionListNode : public ParserArenaFreeable {
+ public:
+ TemplateExpressionListNode(ExpressionNode*);
+ TemplateExpressionListNode(TemplateExpressionListNode*, ExpressionNode*);
+
+ ExpressionNode* value() { return m_node; }
+ TemplateExpressionListNode* next() { return m_next; }
+
+ private:
+ TemplateExpressionListNode* m_next { nullptr };
+ ExpressionNode* m_node { nullptr };
+ };
+
+ class TemplateStringNode : public ExpressionNode {
+ public:
+ TemplateStringNode(const JSTokenLocation&, const Identifier& cooked, const Identifier& raw);
+
+ const Identifier& cooked() { return m_cooked; }
+ const Identifier& raw() { return m_raw; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_cooked;
+ const Identifier& m_raw;
+ };
+
+ class TemplateStringListNode : public ParserArenaFreeable {
+ public:
+ TemplateStringListNode(TemplateStringNode*);
+ TemplateStringListNode(TemplateStringListNode*, TemplateStringNode*);
+
+ TemplateStringNode* value() { return m_node; }
+ TemplateStringListNode* next() { return m_next; }
+
+ private:
+ TemplateStringListNode* m_next { nullptr };
+ TemplateStringNode* m_node { nullptr };
+ };
+
+ class TemplateLiteralNode : public ExpressionNode {
+ public:
+ TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*);
+ TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*, TemplateExpressionListNode*);
+
+ TemplateStringListNode* templateStrings() const { return m_templateStrings; }
+ TemplateExpressionListNode* templateExpressions() const { return m_templateExpressions; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ TemplateStringListNode* m_templateStrings;
+ TemplateExpressionListNode* m_templateExpressions;
+ };
+
+ class TaggedTemplateNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ TaggedTemplateNode(const JSTokenLocation&, ExpressionNode*, TemplateLiteralNode*);
+
+ TemplateLiteralNode* templateLiteral() const { return m_templateLiteral; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_tag;
+ TemplateLiteralNode* m_templateLiteral;
+ };
+#endif
+
+ class RegExpNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ RegExpNode(const JSTokenLocation&, const Identifier& pattern, const Identifier& flags);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_pattern;
+ const Identifier& m_flags;
+ };
+
+ class ThisNode : public ExpressionNode {
+ public:
+ ThisNode(const JSTokenLocation&, ThisTDZMode);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ bool m_shouldAlwaysEmitTDZCheck;
+ };
+
+ class SuperNode final : public ExpressionNode {
+ public:
+ SuperNode(const JSTokenLocation&);
+
+ private:
+ virtual bool isSuperNode() const override { return true; }
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class NewTargetNode final : public ExpressionNode {
+ public:
+ NewTargetNode(const JSTokenLocation&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ResolveNode : public ExpressionNode {
+ public:
+ ResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& start);
+
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isPure(BytecodeGenerator&) const override;
+ virtual bool isLocation() const override { return true; }
+ virtual bool isResolveNode() const override { return true; }
+
+ const Identifier& m_ident;
+ JSTextPosition m_start;
+ };
+
+ class ElementNode : public ParserArenaFreeable {
+ public:
+ ElementNode(int elision, ExpressionNode*);
+ ElementNode(ElementNode*, int elision, ExpressionNode*);
+
+ int elision() const { return m_elision; }
+ ExpressionNode* value() { return m_node; }
+ ElementNode* next() { return m_next; }
+
+ private:
+ ElementNode* m_next;
+ int m_elision;
+ ExpressionNode* m_node;
+ };
+
+ class ArrayNode : public ExpressionNode {
+ public:
+ ArrayNode(const JSTokenLocation&, int elision);
+ ArrayNode(const JSTokenLocation&, ElementNode*);
+ ArrayNode(const JSTokenLocation&, int elision, ElementNode*);
+
+ ArgumentListNode* toArgumentList(ParserArena&, int, int) const;
+
+ ElementNode* elements() const { ASSERT(isSimpleArray()); return m_element; }
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isSimpleArray() const override;
+
+ ElementNode* m_element;
+ int m_elision;
+ bool m_optional;
+ };
+
+ class PropertyNode : public ParserArenaFreeable {
+ public:
+ enum Type { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16 };
+ enum PutType { Unknown, KnownDirect };
+
+ PropertyNode(const Identifier&, ExpressionNode*, Type, PutType, SuperBinding);
+ PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, PutType);
+
+ ExpressionNode* expressionName() const { return m_expression; }
+ const Identifier* name() const { return m_name; }
+
+ Type type() const { return static_cast<Type>(m_type); }
+ bool needsSuperBinding() const { return m_needsSuperBinding; }
+ PutType putType() const { return static_cast<PutType>(m_putType); }
+
+ private:
+ friend class PropertyListNode;
+ const Identifier* m_name;
+ ExpressionNode* m_expression;
+ ExpressionNode* m_assign;
+ unsigned m_type : 5;
+ unsigned m_needsSuperBinding : 1;
+ unsigned m_putType : 1;
+ };
+
+ class PropertyListNode : public ExpressionNode {
+ public:
+ PropertyListNode(const JSTokenLocation&, PropertyNode*);
+ PropertyListNode(const JSTokenLocation&, PropertyNode*, PropertyListNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&);
+
+ PropertyNode* m_node;
+ PropertyListNode* m_next;
+ };
+
+ class ObjectLiteralNode : public ExpressionNode {
+ public:
+ ObjectLiteralNode(const JSTokenLocation&);
+ ObjectLiteralNode(const JSTokenLocation&, PropertyListNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ PropertyListNode* m_list;
+ };
+
+ class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ BracketAccessorNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments);
+
+ ExpressionNode* base() const { return m_base; }
+ ExpressionNode* subscript() const { return m_subscript; }
+
+ bool subscriptHasAssignments() const { return m_subscriptHasAssignments; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isLocation() const override { return true; }
+ virtual bool isBracketAccessorNode() const override { return true; }
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ bool m_subscriptHasAssignments;
+ };
+
+ class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DotAccessorNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&);
+
+ ExpressionNode* base() const { return m_base; }
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isLocation() const override { return true; }
+ virtual bool isDotAccessorNode() const override { return true; }
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ };
+
+ class SpreadExpressionNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ SpreadExpressionNode(const JSTokenLocation&, ExpressionNode*);
+
+ ExpressionNode* expression() const { return m_expression; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isSpreadExpression() const override { return true; }
+ ExpressionNode* m_expression;
+ };
+
+ class ArgumentListNode : public ExpressionNode {
+ public:
+ ArgumentListNode(const JSTokenLocation&, ExpressionNode*);
+ ArgumentListNode(const JSTokenLocation&, ArgumentListNode*, ExpressionNode*);
+
+ ArgumentListNode* m_next;
+ ExpressionNode* m_expr;
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ArgumentsNode : public ParserArenaFreeable {
+ public:
+ ArgumentsNode();
+ ArgumentsNode(ArgumentListNode*);
+
+ ArgumentListNode* m_listNode;
+ };
+
+ class NewExprNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ NewExprNode(const JSTokenLocation&, ExpressionNode*);
+ NewExprNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ ArgumentsNode* m_args;
+ };
+
+ class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ EvalFunctionCallNode(const JSTokenLocation&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ FunctionCallValueNode(const JSTokenLocation&, ExpressionNode*, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ FunctionCallResolveNode(const JSTokenLocation&, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ FunctionCallBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ArgumentsNode* m_args;
+ bool m_subscriptHasAssignments;
+ };
+
+ class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ FunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ protected:
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ArgumentsNode* m_args;
+ };
+
+ class BytecodeIntrinsicNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ typedef RegisterID* (BytecodeIntrinsicNode::* EmitterType)(BytecodeGenerator&, RegisterID*);
+
+ BytecodeIntrinsicNode(const JSTokenLocation&, EmitterType, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ const Identifier& identifier() const { return m_ident; }
+
+#define JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS(name) RegisterID* emit_intrinsic_##name(BytecodeGenerator&, RegisterID*);
+ JSC_COMMON_BYTECODE_INTRINSICS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS)
+#undef JSC_DECLARE_BYTECODE_INTRINSIC_FUNCTIONS
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ EmitterType m_emitter;
+ const Identifier& m_ident;
+ ArgumentsNode* m_args;
+ };
+
+ class CallFunctionCallDotNode : public FunctionCallDotNode {
+ public:
+ CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ApplyFunctionCallDotNode : public FunctionCallDotNode {
+ public:
+ ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ };
+
+ class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ };
+
+ class DeleteValueNode : public ExpressionNode {
+ public:
+ DeleteValueNode(const JSTokenLocation&, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class VoidNode : public ExpressionNode {
+ public:
+ VoidNode(const JSTokenLocation&, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class TypeOfResolveNode : public ExpressionNode {
+ public:
+ TypeOfResolveNode(const JSTokenLocation&, const Identifier&);
+
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class TypeOfValueNode : public ExpressionNode {
+ public:
+ TypeOfValueNode(const JSTokenLocation&, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class PrefixNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
+ public:
+ PrefixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ protected:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = 0);
+ virtual RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = 0);
+ virtual RegisterID* emitDot(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ Operator m_operator;
+ };
+
+ class PostfixNode : public PrefixNode {
+ public:
+ PostfixNode(const JSTokenLocation&, ExpressionNode*, Operator, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual RegisterID* emitResolve(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual RegisterID* emitBracket(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual RegisterID* emitDot(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class UnaryOpNode : public ExpressionNode {
+ public:
+ UnaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode*, OpcodeID);
+
+ protected:
+ ExpressionNode* expr() { return m_expr; }
+ const ExpressionNode* expr() const { return m_expr; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ OpcodeID opcodeID() const { return m_opcodeID; }
+
+ ExpressionNode* m_expr;
+ OpcodeID m_opcodeID;
+ };
+
+ class UnaryPlusNode : public UnaryOpNode {
+ public:
+ UnaryPlusNode(const JSTokenLocation&, ExpressionNode*);
+
+ private:
+ virtual ExpressionNode* stripUnaryPlus() override { return expr(); }
+ };
+
+ class NegateNode : public UnaryOpNode {
+ public:
+ NegateNode(const JSTokenLocation&, ExpressionNode*);
+ };
+
+ class BitwiseNotNode : public ExpressionNode {
+ public:
+ BitwiseNotNode(const JSTokenLocation&, ExpressionNode*);
+
+ protected:
+ ExpressionNode* expr() { return m_expr; }
+ const ExpressionNode* expr() const { return m_expr; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class LogicalNotNode : public UnaryOpNode {
+ public:
+ LogicalNotNode(const JSTokenLocation&, ExpressionNode*);
+ private:
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override;
+ };
+
+ class BinaryOpNode : public ExpressionNode {
+ public:
+ BinaryOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ BinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0);
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override;
+
+ ExpressionNode* lhs() { return m_expr1; };
+ ExpressionNode* rhs() { return m_expr2; };
+
+ private:
+ void tryFoldToBranch(BytecodeGenerator&, TriState& branchCondition, ExpressionNode*& branchExpression);
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ protected:
+ OpcodeID opcodeID() const { return m_opcodeID; }
+
+ protected:
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ private:
+ OpcodeID m_opcodeID;
+ protected:
+ bool m_rightHasAssignments;
+ };
+
+ class MultNode : public BinaryOpNode {
+ public:
+ MultNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class DivNode : public BinaryOpNode {
+ public:
+ DivNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ModNode : public BinaryOpNode {
+ public:
+ ModNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class AddNode : public BinaryOpNode {
+ public:
+ AddNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isAdd() const override { return true; }
+ };
+
+ class SubNode : public BinaryOpNode {
+ public:
+ SubNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isSubtract() const override { return true; }
+ };
+
+ class LeftShiftNode : public BinaryOpNode {
+ public:
+ LeftShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class RightShiftNode : public BinaryOpNode {
+ public:
+ RightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class UnsignedRightShiftNode : public BinaryOpNode {
+ public:
+ UnsignedRightShiftNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessNode : public BinaryOpNode {
+ public:
+ LessNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterNode : public BinaryOpNode {
+ public:
+ GreaterNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessEqNode : public BinaryOpNode {
+ public:
+ LessEqNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterEqNode : public BinaryOpNode {
+ public:
+ GreaterEqNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
+ public:
+ ThrowableBinaryOpNode(const JSTokenLocation&, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ ThrowableBinaryOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class InstanceOfNode : public ThrowableBinaryOpNode {
+ public:
+ InstanceOfNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class InNode : public ThrowableBinaryOpNode {
+ public:
+ InNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class EqualNode : public BinaryOpNode {
+ public:
+ EqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class NotEqualNode : public BinaryOpNode {
+ public:
+ NotEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class StrictEqualNode : public BinaryOpNode {
+ public:
+ StrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class NotStrictEqualNode : public BinaryOpNode {
+ public:
+ NotStrictEqualNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitAndNode : public BinaryOpNode {
+ public:
+ BitAndNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitOrNode : public BinaryOpNode {
+ public:
+ BitOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitXOrNode : public BinaryOpNode {
+ public:
+ BitXOrNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ // m_expr1 && m_expr2, m_expr1 || m_expr2
+ class LogicalOpNode : public ExpressionNode {
+ public:
+ LogicalOpNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, FallThroughMode) override;
+
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ LogicalOperator m_operator;
+ };
+
+ // The ternary operator, "m_logical ? m_expr1 : m_expr2"
+ class ConditionalNode : public ExpressionNode {
+ public:
+ ConditionalNode(const JSTokenLocation&, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_logical;
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ };
+
+ class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ ReadModifyResolveNode(const JSTokenLocation&, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ Operator m_operator;
+ bool m_rightHasAssignments;
+ };
+
+ class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignResolveNode(const JSTokenLocation&, const Identifier&, ExpressionNode* right, AssignmentContext);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ AssignmentContext m_assignmentContext;
+ };
+
+ class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ReadModifyBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ExpressionNode* m_right;
+ unsigned m_operator : 30;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignBracketNode(const JSTokenLocation&, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ExpressionNode* m_right;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignDotNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ bool m_rightHasAssignments;
+ };
+
+ class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ unsigned m_operator : 31;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignErrorNode(const JSTokenLocation&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class CommaNode final : public ExpressionNode {
+ public:
+ CommaNode(const JSTokenLocation&, ExpressionNode*);
+
+ void setNext(CommaNode* next) { m_next = next; }
+ CommaNode* next() { return m_next; }
+
+ private:
+ virtual bool isCommaNode() const override { return true; }
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ CommaNode* m_next;
+ };
+
+ class SourceElements final : public ParserArenaFreeable {
+ public:
+ SourceElements();
+
+ void append(StatementNode*);
+
+ StatementNode* singleStatement() const;
+ StatementNode* lastStatement() const;
+
+ void emitBytecode(BytecodeGenerator&, RegisterID* destination);
+ void analyzeModule(ModuleAnalyzer&);
+
+ private:
+ StatementNode* m_head;
+ StatementNode* m_tail;
+ };
+
+ class BlockNode : public StatementNode, public VariableEnvironmentNode {
+ public:
+ BlockNode(const JSTokenLocation&, SourceElements*, VariableEnvironment&);
+
+ StatementNode* singleStatement() const;
+ StatementNode* lastStatement() const;
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isBlock() const override { return true; }
+
+ SourceElements* m_statements;
+ };
+
+ class EmptyStatementNode : public StatementNode {
+ public:
+ EmptyStatementNode(const JSTokenLocation&);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isEmptyStatement() const override { return true; }
+ };
+
+ class DebuggerStatementNode : public StatementNode {
+ public:
+ DebuggerStatementNode(const JSTokenLocation&);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ExprStatementNode : public StatementNode {
+ public:
+ ExprStatementNode(const JSTokenLocation&, ExpressionNode*);
+
+ ExpressionNode* expr() const { return m_expr; }
+
+ private:
+ virtual bool isExprStatement() const override { return true; }
+
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class DeclarationStatement : public StatementNode {
+ public:
+ DeclarationStatement(const JSTokenLocation&, ExpressionNode*);
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class EmptyVarExpression : public ExpressionNode {
+ public:
+ EmptyVarExpression(const JSTokenLocation&, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class EmptyLetExpression : public ExpressionNode {
+ public:
+ EmptyLetExpression(const JSTokenLocation&, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class IfElseNode : public StatementNode {
+ public:
+ IfElseNode(const JSTokenLocation&, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ bool tryFoldBreakAndContinue(BytecodeGenerator&, StatementNode* ifBlock,
+ Label*& trueTarget, FallThroughMode&);
+
+ ExpressionNode* m_condition;
+ StatementNode* m_ifBlock;
+ StatementNode* m_elseBlock;
+ };
+
+ class DoWhileNode : public StatementNode {
+ public:
+ DoWhileNode(const JSTokenLocation&, StatementNode*, ExpressionNode*);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ StatementNode* m_statement;
+ ExpressionNode* m_expr;
+ };
+
+ class WhileNode : public StatementNode {
+ public:
+ WhileNode(const JSTokenLocation&, ExpressionNode*, StatementNode*);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ };
+
+ class ForNode : public StatementNode, public VariableEnvironmentNode {
+ public:
+ ForNode(const JSTokenLocation&, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode*, VariableEnvironment&);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ ExpressionNode* m_expr3;
+ StatementNode* m_statement;
+ };
+
+ class DestructuringPatternNode;
+
+ class EnumerationNode : public StatementNode, public ThrowableExpressionData, public VariableEnvironmentNode {
+ public:
+ EnumerationNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&);
+
+ protected:
+ ExpressionNode* m_lexpr;
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ };
+
+ class ForInNode : public EnumerationNode {
+ public:
+ ForInNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&);
+
+ private:
+ RegisterID* tryGetBoundLocal(BytecodeGenerator&);
+ void emitLoopHeader(BytecodeGenerator&, RegisterID* propertyName);
+ void emitMultiLoopBytecode(BytecodeGenerator&, RegisterID* dst);
+
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ForOfNode : public EnumerationNode {
+ public:
+ ForOfNode(const JSTokenLocation&, ExpressionNode*, ExpressionNode*, StatementNode*, VariableEnvironment&);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ };
+
+ class ContinueNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ContinueNode(const JSTokenLocation&, const Identifier&);
+ Label* trivialTarget(BytecodeGenerator&);
+
+ private:
+ virtual bool isContinue() const override { return true; }
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class BreakNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ BreakNode(const JSTokenLocation&, const Identifier&);
+ Label* trivialTarget(BytecodeGenerator&);
+
+ private:
+ virtual bool isBreak() const override { return true; }
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_ident;
+ };
+
+ class ReturnNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ReturnNode(const JSTokenLocation&, ExpressionNode* value);
+
+ ExpressionNode* value() { return m_value; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isReturnNode() const override { return true; }
+
+ ExpressionNode* m_value;
+ };
+
+ class WithNode : public StatementNode {
+ public:
+ WithNode(const JSTokenLocation&, ExpressionNode*, StatementNode*, const JSTextPosition& divot, uint32_t expressionLength);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ JSTextPosition m_divot;
+ uint32_t m_expressionLength;
+ };
+
+ class LabelNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ LabelNode(const JSTokenLocation&, const Identifier& name, StatementNode*);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_name;
+ StatementNode* m_statement;
+ };
+
+ class ThrowNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ThrowNode(const JSTokenLocation&, ExpressionNode*);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ };
+
+ class TryNode : public StatementNode {
+ public:
+ TryNode(const JSTokenLocation&, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, VariableEnvironment& catchEnvironment, StatementNode* finallyBlock);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ StatementNode* m_tryBlock;
+ const Identifier& m_thrownValueIdent;
+ StatementNode* m_catchBlock;
+ StatementNode* m_finallyBlock;
+ VariableEnvironment m_catchEnvironment;
+ };
+
+ class ScopeNode : public StatementNode, public ParserArenaRoot, public VariableEnvironmentNode {
+ public:
+ typedef DeclarationStacks::FunctionStack FunctionStack;
+
+ ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, bool inStrictContext);
+ ScopeNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, const SourceCode&, SourceElements*, VariableEnvironment&, FunctionStack&, VariableEnvironment&, CodeFeatures, int numConstants);
+
+ using ParserArenaRoot::operator new;
+
+ const SourceCode& source() const { return m_source; }
+ const String& sourceURL() const { return m_source.provider()->url(); }
+ intptr_t sourceID() const { return m_source.providerID(); }
+
+ int startLine() const { return m_startLineNumber; }
+ int startStartOffset() const { return m_startStartOffset; }
+ int startLineStartOffset() const { return m_startLineStartOffset; }
+
+ void setFeatures(CodeFeatures features) { m_features = features; }
+ CodeFeatures features() { return m_features; }
+
+ bool usesEval() const { return m_features & EvalFeature; }
+ bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); }
+ bool modifiesParameter() const { return m_features & ModifiedParameterFeature; }
+ bool modifiesArguments() const { return m_features & (EvalFeature | ModifiedArgumentsFeature); }
+ bool isStrictMode() const { return m_features & StrictModeFeature; }
+ void setUsesArguments() { m_features |= ArgumentsFeature; }
+ bool usesThis() const { return m_features & ThisFeature; }
+ bool needsActivationForMoreThanVariables() const { return m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool needsActivation() const { return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); }
+ bool hasCapturedVariables() const { return m_varDeclarations.hasCapturedVariables(); }
+ bool captures(UniquedStringImpl* uid) { return m_varDeclarations.captures(uid); }
+ bool captures(const Identifier& ident) { return captures(ident.impl()); }
+
+ VariableEnvironment& varDeclarations() { return m_varDeclarations; }
+ FunctionStack& functionStack() { return m_functionStack; }
+
+ int neededConstants()
+ {
+ // We may need 2 more constants than the count given by the parser,
+ // because of the various uses of jsUndefined() and jsNull().
+ return m_numConstants + 2;
+ }
+
+ StatementNode* singleStatement() const;
+
+ void emitStatementsBytecode(BytecodeGenerator&, RegisterID* destination);
+
+ void setClosedVariables(Vector<RefPtr<UniquedStringImpl>>&&) { }
+
+ void analyzeModule(ModuleAnalyzer&);
+
+ protected:
+ int m_startLineNumber;
+ unsigned m_startStartOffset;
+ unsigned m_startLineStartOffset;
+
+ private:
+ CodeFeatures m_features;
+ SourceCode m_source;
+ VariableEnvironment m_varDeclarations;
+ FunctionStack m_functionStack;
+ int m_numConstants;
+ SourceElements* m_statements;
+ };
+
+ class ProgramNode : public ScopeNode {
+ public:
+ ProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&, VariableEnvironment&, FunctionParameters*, const SourceCode&, CodeFeatures, int numConstants);
+
+ unsigned startColumn() const { return m_startColumn; }
+ unsigned endColumn() const { return m_endColumn; }
+
+ static const bool scopeIsFunction = false;
+
+ void setClosedVariables(Vector<RefPtr<UniquedStringImpl>>&&);
+ const Vector<RefPtr<UniquedStringImpl>>& closedVariables() const { return m_closedVariables; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ Vector<RefPtr<UniquedStringImpl>> m_closedVariables;
+ unsigned m_startColumn;
+ unsigned m_endColumn;
+ };
+
+ class EvalNode : public ScopeNode {
+ public:
+ EvalNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&, VariableEnvironment&, FunctionParameters*, const SourceCode&, CodeFeatures, int numConstants);
+
+ ALWAYS_INLINE unsigned startColumn() const { return 0; }
+ unsigned endColumn() const { return m_endColumn; }
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ unsigned m_endColumn;
+ };
+
+ class ModuleProgramNode : public ScopeNode {
+ public:
+ ModuleProgramNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&, VariableEnvironment&, FunctionParameters*, const SourceCode&, CodeFeatures, int numConstants);
+
+ unsigned startColumn() const { return m_startColumn; }
+ unsigned endColumn() const { return m_endColumn; }
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ unsigned m_startColumn;
+ unsigned m_endColumn;
+ };
+
+ class ModuleNameNode : public Node {
+ public:
+ ModuleNameNode(const JSTokenLocation&, const Identifier& moduleName);
+
+ const Identifier& moduleName() { return m_moduleName; }
+
+ private:
+ const Identifier& m_moduleName;
+ };
+
+ class ImportSpecifierNode : public Node {
+ public:
+ ImportSpecifierNode(const JSTokenLocation&, const Identifier& importedName, const Identifier& localName);
+
+ const Identifier& importedName() { return m_importedName; }
+ const Identifier& localName() { return m_localName; }
+
+ private:
+ const Identifier& m_importedName;
+ const Identifier& m_localName;
+ };
+
+ class ImportSpecifierListNode : public ParserArenaDeletable {
+ public:
+ typedef Vector<ImportSpecifierNode*, 3> Specifiers;
+
+ const Specifiers& specifiers() const { return m_specifiers; }
+ void append(ImportSpecifierNode* specifier)
+ {
+ m_specifiers.append(specifier);
+ }
+
+ private:
+ Specifiers m_specifiers;
+ };
+
+ class ModuleDeclarationNode : public StatementNode {
+ public:
+ virtual void analyzeModule(ModuleAnalyzer&) = 0;
+ virtual bool isModuleDeclarationNode() const { return true; }
+
+ protected:
+ ModuleDeclarationNode(const JSTokenLocation&);
+ };
+
+ class ImportDeclarationNode : public ModuleDeclarationNode {
+ public:
+ ImportDeclarationNode(const JSTokenLocation&, ImportSpecifierListNode*, ModuleNameNode*);
+
+ ImportSpecifierListNode* specifierList() const { return m_specifierList; }
+ ModuleNameNode* moduleName() const { return m_moduleName; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void analyzeModule(ModuleAnalyzer&) override;
+
+ ImportSpecifierListNode* m_specifierList;
+ ModuleNameNode* m_moduleName;
+ };
+
+ class ExportAllDeclarationNode : public ModuleDeclarationNode {
+ public:
+ ExportAllDeclarationNode(const JSTokenLocation&, ModuleNameNode*);
+
+ ModuleNameNode* moduleName() const { return m_moduleName; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void analyzeModule(ModuleAnalyzer&) override;
+
+ ModuleNameNode* m_moduleName;
+ };
+
+ class ExportDefaultDeclarationNode : public ModuleDeclarationNode {
+ public:
+ ExportDefaultDeclarationNode(const JSTokenLocation&, StatementNode*, const Identifier& localName);
+
+ const StatementNode& declaration() const { return *m_declaration; }
+ const Identifier& localName() const { return m_localName; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void analyzeModule(ModuleAnalyzer&) override;
+ StatementNode* m_declaration;
+ const Identifier& m_localName;
+ };
+
+ class ExportLocalDeclarationNode : public ModuleDeclarationNode {
+ public:
+ ExportLocalDeclarationNode(const JSTokenLocation&, StatementNode*);
+
+ const StatementNode& declaration() const { return *m_declaration; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void analyzeModule(ModuleAnalyzer&) override;
+ StatementNode* m_declaration;
+ };
+
+ class ExportSpecifierNode : public Node {
+ public:
+ ExportSpecifierNode(const JSTokenLocation&, const Identifier& localName, const Identifier& exportedName);
+
+ const Identifier& exportedName() { return m_exportedName; }
+ const Identifier& localName() { return m_localName; }
+
+ private:
+ const Identifier& m_localName;
+ const Identifier& m_exportedName;
+ };
+
+ class ExportSpecifierListNode : public ParserArenaDeletable {
+ public:
+ typedef Vector<ExportSpecifierNode*, 3> Specifiers;
+
+ const Specifiers& specifiers() const { return m_specifiers; }
+ void append(ExportSpecifierNode* specifier)
+ {
+ m_specifiers.append(specifier);
+ }
+
+ private:
+ Specifiers m_specifiers;
+ };
+
+ class ExportNamedDeclarationNode : public ModuleDeclarationNode {
+ public:
+ ExportNamedDeclarationNode(const JSTokenLocation&, ExportSpecifierListNode*, ModuleNameNode*);
+
+ ExportSpecifierListNode* specifierList() const { return m_specifierList; }
+ ModuleNameNode* moduleName() const { return m_moduleName; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+ virtual void analyzeModule(ModuleAnalyzer&) override;
+ ExportSpecifierListNode* m_specifierList;
+ ModuleNameNode* m_moduleName { nullptr };
+ };
+
+ class FunctionParameters : public ParserArenaDeletable {
+ public:
+ FunctionParameters();
+ ALWAYS_INLINE unsigned size() const { return m_patterns.size(); }
+ ALWAYS_INLINE std::pair<DestructuringPatternNode*, ExpressionNode*> at(unsigned index) { return m_patterns[index]; }
+ bool hasDefaultParameterValues() const { return m_hasDefaultParameterValues; }
+ ALWAYS_INLINE void append(DestructuringPatternNode* pattern, ExpressionNode* defaultValue)
+ {
+ ASSERT(pattern);
+ m_patterns.append(std::make_pair(pattern, defaultValue));
+ if (defaultValue)
+ m_hasDefaultParameterValues = true;
+ }
+
+ private:
+
+ Vector<std::pair<DestructuringPatternNode*, ExpressionNode*>, 3> m_patterns;
+ bool m_hasDefaultParameterValues { false };
+ };
+
+ class FunctionMetadataNode final : public Node, public ParserArenaDeletable {
+ public:
+ using ParserArenaDeletable::operator new;
+
+ FunctionMetadataNode(
+ ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end,
+ unsigned startColumn, unsigned endColumn, int functionKeywordStart,
+ int functionNameStart, int parametersStart, bool isInStrictContext,
+ ConstructorKind, unsigned, SourceParseMode);
+
+ void finishParsing(const SourceCode&, const Identifier&, FunctionMode);
+
+ void overrideName(const Identifier& ident) { m_ident = ident; }
+ const Identifier& ident() { return m_ident; }
+ void setInferredName(const Identifier& inferredName) { ASSERT(!inferredName.isNull()); m_inferredName = inferredName; }
+ const Identifier& inferredName() { return m_inferredName.isEmpty() ? m_ident : m_inferredName; }
+
+ FunctionMode functionMode() { return m_functionMode; }
+
+ int functionNameStart() const { return m_functionNameStart; }
+ int functionKeywordStart() const { return m_functionKeywordStart; }
+ int parametersStart() const { return m_parametersStart; }
+ unsigned startColumn() const { return m_startColumn; }
+ unsigned endColumn() const { return m_endColumn; }
+ unsigned parameterCount() const { return m_parameterCount; }
+ SourceParseMode parseMode() const { return m_parseMode; }
+
+ void setEndPosition(JSTextPosition);
+
+ const SourceCode& source() const { return m_source; }
+
+ int startStartOffset() const { return m_startStartOffset; }
+ bool isInStrictContext() const { return m_isInStrictContext; }
+ ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
+
+ void setLoc(unsigned firstLine, unsigned lastLine, int startOffset, int lineStartOffset)
+ {
+ m_lastLine = lastLine;
+ m_position = JSTextPosition(firstLine, startOffset, lineStartOffset);
+ ASSERT(m_position.offset >= m_position.lineStartOffset);
+ }
+ unsigned lastLine() const { return m_lastLine; }
+
+ protected:
+ Identifier m_ident;
+ Identifier m_inferredName;
+ FunctionMode m_functionMode;
+ unsigned m_startColumn;
+ unsigned m_endColumn;
+ int m_functionKeywordStart;
+ int m_functionNameStart;
+ int m_parametersStart;
+ SourceCode m_source;
+ int m_startStartOffset;
+ unsigned m_parameterCount;
+ int m_lastLine;
+ SourceParseMode m_parseMode;
+ unsigned m_isInStrictContext : 1;
+ unsigned m_constructorKind : 2;
+ };
+
+ class FunctionNode final : public ScopeNode {
+ public:
+ FunctionNode(ParserArena&, const JSTokenLocation& start, const JSTokenLocation& end, unsigned startColumn, unsigned endColumn, SourceElements*, VariableEnvironment&, FunctionStack&, VariableEnvironment&, FunctionParameters*, const SourceCode&, CodeFeatures, int numConstants);
+
+ FunctionParameters* parameters() const { return m_parameters; }
+
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ void finishParsing(const Identifier&, FunctionMode);
+
+ const Identifier& ident() { return m_ident; }
+
+ FunctionMode functionMode() { return m_functionMode; }
+
+ unsigned startColumn() const { return m_startColumn; }
+ unsigned endColumn() const { return m_endColumn; }
+
+ static const bool scopeIsFunction = true;
+
+ private:
+ Identifier m_ident;
+ FunctionMode m_functionMode;
+ FunctionParameters* m_parameters;
+ unsigned m_startColumn;
+ unsigned m_endColumn;
+ };
+
+ class FuncExprNode : public ExpressionNode {
+ public:
+ FuncExprNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
+
+ FunctionMetadataNode* metadata() { return m_metadata; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ virtual bool isFuncExprNode() const override { return true; }
+
+ FunctionMetadataNode* m_metadata;
+ };
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ class ClassExprNode final : public ExpressionNode {
+ public:
+ ClassExprNode(const JSTokenLocation&, const Identifier&, ExpressionNode* constructorExpresssion,
+ ExpressionNode* parentClass, PropertyListNode* instanceMethods, PropertyListNode* staticMethods);
+
+ const Identifier& name() { return m_name; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ const Identifier& m_name;
+ ExpressionNode* m_constructorExpression;
+ ExpressionNode* m_classHeritage;
+ PropertyListNode* m_instanceMethods;
+ PropertyListNode* m_staticMethods;
+ };
+#endif
+
+ class DestructuringPatternNode : public ParserArenaFreeable {
+ public:
+ virtual ~DestructuringPatternNode() { }
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const = 0;
+ virtual void bindValue(BytecodeGenerator&, RegisterID* source) const = 0;
+ virtual void toString(StringBuilder&) const = 0;
+
+ virtual bool isBindingNode() const { return false; }
+ virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID*, ExpressionNode*) { return 0; }
+
+ protected:
+ DestructuringPatternNode();
+ };
+
+ class ArrayPatternNode : public DestructuringPatternNode, public ThrowableExpressionData, public ParserArenaDeletable {
+ public:
+ using ParserArenaDeletable::operator new;
+
+ ArrayPatternNode();
+ enum class BindingType {
+ Elision,
+ Element,
+ RestElement
+ };
+
+ void appendIndex(BindingType bindingType, const JSTokenLocation&, DestructuringPatternNode* node, ExpressionNode* defaultValue)
+ {
+ m_targetPatterns.append({ bindingType, node, defaultValue });
+ }
+
+ private:
+ struct Entry {
+ BindingType bindingType;
+ DestructuringPatternNode* pattern;
+ ExpressionNode* defaultValue;
+ };
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
+ virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
+ virtual RegisterID* emitDirectBinding(BytecodeGenerator&, RegisterID* dst, ExpressionNode*) override;
+ virtual void toString(StringBuilder&) const override;
+
+ Vector<Entry> m_targetPatterns;
+ };
+
+ class ObjectPatternNode : public DestructuringPatternNode, public ParserArenaDeletable {
+ public:
+ using ParserArenaDeletable::operator new;
+
+ ObjectPatternNode();
+ void appendEntry(const JSTokenLocation&, const Identifier& identifier, bool wasString, DestructuringPatternNode* pattern, ExpressionNode* defaultValue)
+ {
+ m_targetPatterns.append(Entry{ identifier, wasString, pattern, defaultValue });
+ }
+
+ private:
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
+ virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
+ virtual void toString(StringBuilder&) const override;
+ struct Entry {
+ const Identifier& propertyName;
+ bool wasString;
+ DestructuringPatternNode* pattern;
+ ExpressionNode* defaultValue;
+ };
+ Vector<Entry> m_targetPatterns;
+ };
+
+ class BindingNode : public DestructuringPatternNode {
+ public:
+ BindingNode(const Identifier& boundProperty, const JSTextPosition& start, const JSTextPosition& end, AssignmentContext);
+ const Identifier& boundProperty() const { return m_boundProperty; }
+
+ const JSTextPosition& divotStart() const { return m_divotStart; }
+ const JSTextPosition& divotEnd() const { return m_divotEnd; }
+
+ private:
+ virtual void collectBoundIdentifiers(Vector<Identifier>&) const override;
+ virtual void bindValue(BytecodeGenerator&, RegisterID*) const override;
+ virtual void toString(StringBuilder&) const override;
+
+ virtual bool isBindingNode() const override { return true; }
+
+ JSTextPosition m_divotStart;
+ JSTextPosition m_divotEnd;
+ const Identifier& m_boundProperty;
+ AssignmentContext m_bindingContext;
+ };
+
+ class DestructuringAssignmentNode : public ExpressionNode {
+ public:
+ DestructuringAssignmentNode(const JSTokenLocation&, DestructuringPatternNode*, ExpressionNode*);
+ DestructuringPatternNode* bindings() { return m_bindings; }
+
+ private:
+ virtual bool isAssignmentLocation() const override { return true; }
+ virtual bool isDestructuringNode() const override { return true; }
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ DestructuringPatternNode* m_bindings;
+ ExpressionNode* m_initializer;
+ };
+
+ class FuncDeclNode : public StatementNode {
+ public:
+ FuncDeclNode(const JSTokenLocation&, const Identifier&, FunctionMetadataNode*, const SourceCode&);
+
+ virtual bool isFuncDeclNode() const override { return true; }
+ FunctionMetadataNode* metadata() { return m_metadata; }
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ FunctionMetadataNode* m_metadata;
+ };
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ class ClassDeclNode final : public StatementNode {
+ public:
+ ClassDeclNode(const JSTokenLocation&, ExpressionNode* classExpression);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_classDeclaration;
+ };
+#endif
+
+ class CaseClauseNode : public ParserArenaFreeable {
+ public:
+ CaseClauseNode(ExpressionNode*, SourceElements* = 0);
+
+ ExpressionNode* expr() const { return m_expr; }
+
+ void emitBytecode(BytecodeGenerator&, RegisterID* destination);
+ void setStartOffset(int offset) { m_startOffset = offset; }
+
+ private:
+ ExpressionNode* m_expr;
+ SourceElements* m_statements;
+ int m_startOffset;
+ };
+
+ class ClauseListNode : public ParserArenaFreeable {
+ public:
+ ClauseListNode(CaseClauseNode*);
+ ClauseListNode(ClauseListNode*, CaseClauseNode*);
+
+ CaseClauseNode* getClause() const { return m_clause; }
+ ClauseListNode* getNext() const { return m_next; }
+
+ private:
+ CaseClauseNode* m_clause;
+ ClauseListNode* m_next;
+ };
+
+ class CaseBlockNode : public ParserArenaFreeable {
+ public:
+ CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2);
+
+ void emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* destination);
+
+ private:
+ SwitchInfo::SwitchType tryTableSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num);
+ static const size_t s_tableSwitchMinimum = 3;
+ ClauseListNode* m_list1;
+ CaseClauseNode* m_defaultClause;
+ ClauseListNode* m_list2;
+ };
+
+ class SwitchNode : public StatementNode, public VariableEnvironmentNode {
+ public:
+ SwitchNode(const JSTokenLocation&, ExpressionNode*, CaseBlockNode*, VariableEnvironment&);
+
+ private:
+ virtual void emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_expr;
+ CaseBlockNode* m_block;
+ };
+
+ struct ElementList {
+ ElementNode* head;
+ ElementNode* tail;
+ };
+
+ struct PropertyList {
+ PropertyListNode* head;
+ PropertyListNode* tail;
+ };
+
+ struct ArgumentList {
+ ArgumentListNode* head;
+ ArgumentListNode* tail;
+ };
+
+ struct ClauseList {
+ ClauseListNode* head;
+ ClauseListNode* tail;
+ };
+
+} // namespace JSC
+
+#endif // Nodes_h
diff --git a/Source/JavaScriptCore/parser/NodesAnalyzeModule.cpp b/Source/JavaScriptCore/parser/NodesAnalyzeModule.cpp
new file mode 100644
index 000000000..633deaece
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodesAnalyzeModule.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Nodes.h"
+#include "NodeConstructors.h"
+
+#include "ModuleAnalyzer.h"
+#include "ModuleRecord.h"
+
+namespace JSC {
+
+void ScopeNode::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ m_statements->analyzeModule(analyzer);
+}
+
+void SourceElements::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ // In the module analyzer phase, only module declarations are included in the top-level SourceElements.
+ for (StatementNode* statement = m_head; statement; statement = statement->next()) {
+ ASSERT(statement->isModuleDeclarationNode());
+ static_cast<ModuleDeclarationNode*>(statement)->analyzeModule(analyzer);
+ }
+}
+
+void ImportDeclarationNode::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ analyzer.moduleRecord().appendRequestedModule(m_moduleName->moduleName());
+ for (auto* specifier : m_specifierList->specifiers()) {
+ analyzer.moduleRecord().addImportEntry(ModuleRecord::ImportEntry {
+ m_moduleName->moduleName(),
+ specifier->importedName(),
+ specifier->localName()
+ });
+ }
+}
+
+void ExportAllDeclarationNode::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ analyzer.moduleRecord().appendRequestedModule(m_moduleName->moduleName());
+ analyzer.moduleRecord().addStarExportEntry(m_moduleName->moduleName());
+}
+
+void ExportDefaultDeclarationNode::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ analyzer.declareExportAlias(m_localName, analyzer.vm().propertyNames->defaultKeyword);
+}
+
+void ExportLocalDeclarationNode::analyzeModule(ModuleAnalyzer&)
+{
+}
+
+void ExportNamedDeclarationNode::analyzeModule(ModuleAnalyzer& analyzer)
+{
+ if (m_moduleName)
+ analyzer.moduleRecord().appendRequestedModule(m_moduleName->moduleName());
+
+ for (auto* specifier : m_specifierList->specifiers()) {
+ if (m_moduleName) {
+ // export { v } from "mod"
+ //
+ // In this case, no local variable names are imported into the current module.
+ // "v" indirectly points the binding in "mod".
+ analyzer.moduleRecord().addExportEntry(ModuleRecord::ExportEntry::createIndirect(specifier->exportedName(), specifier->localName(), m_moduleName->moduleName()));
+ continue;
+ }
+
+ if (specifier->localName() != specifier->exportedName())
+ analyzer.declareExportAlias(specifier->localName(), specifier->exportedName());
+ }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
new file mode 100644
index 000000000..aee70b6a7
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -0,0 +1,3700 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Parser.h"
+
+#include "ASTBuilder.h"
+#include "CodeBlock.h"
+#include "Debugger.h"
+#include "JSCJSValueInlines.h"
+#include "Lexer.h"
+#include "JSCInlines.h"
+#include "SourceProvider.h"
+#include "VM.h"
+#include <utility>
+#include <wtf/HashFunctions.h>
+#include <wtf/StringPrintStream.h>
+#include <wtf/WTFThreadData.h>
+
+
+#define updateErrorMessage(shouldPrintToken, ...) do {\
+ propagateError(); \
+ logError(shouldPrintToken, __VA_ARGS__); \
+} while (0)
+
+#define propagateError() do { if (hasError()) return 0; } while (0)
+#define internalFailWithMessage(shouldPrintToken, ...) do { updateErrorMessage(shouldPrintToken, __VA_ARGS__); return 0; } while (0)
+#define handleErrorToken() do { if (m_token.m_type == EOFTOK || m_token.m_type & ErrorTokenFlag) { failDueToUnexpectedToken(); } } while (0)
+#define failWithMessage(...) do { { handleErrorToken(); updateErrorMessage(true, __VA_ARGS__); } return 0; } while (0)
+#define failWithStackOverflow() do { updateErrorMessage(false, "Stack exhausted"); m_hasStackOverflow = true; return 0; } while (0)
+#define failIfFalse(cond, ...) do { if (!(cond)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
+#define failIfTrue(cond, ...) do { if (cond) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
+#define failIfTrueIfStrict(cond, ...) do { if ((cond) && strictMode()) internalFailWithMessage(false, __VA_ARGS__); } while (0)
+#define failIfFalseIfStrict(cond, ...) do { if ((!(cond)) && strictMode()) internalFailWithMessage(false, __VA_ARGS__); } while (0)
+#define consumeOrFail(tokenType, ...) do { if (!consume(tokenType)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
+#define consumeOrFailWithFlags(tokenType, flags, ...) do { if (!consume(tokenType, flags)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
+#define matchOrFail(tokenType, ...) do { if (!match(tokenType)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
+#define failIfStackOverflow() do { if (!canRecurse()) failWithStackOverflow(); } while (0)
+#define semanticFail(...) do { internalFailWithMessage(false, __VA_ARGS__); } while (0)
+#define semanticFailIfTrue(cond, ...) do { if (cond) internalFailWithMessage(false, __VA_ARGS__); } while (0)
+#define semanticFailIfFalse(cond, ...) do { if (!(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0)
+#define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0)
+#define failDueToUnexpectedToken() do {\
+ logError(true);\
+ return 0;\
+} while (0)
+
+#define handleProductionOrFail(token, tokenString, operation, production) do {\
+ consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " a ", production);\
+} while (0)
+
+#define semanticFailureDueToKeyword(...) do { \
+ if (strictMode() && m_token.m_type == RESERVED_IF_STRICT) \
+ semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__, " in strict mode"); \
+ if (m_token.m_type == RESERVED || m_token.m_type == RESERVED_IF_STRICT) \
+ semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__); \
+ if (m_token.m_type & KeywordTokenFlag) \
+ semanticFail("Cannot use the keyword '", getToken(), "' as a ", __VA_ARGS__); \
+} while (0)
+
+using namespace std;
+
+namespace JSC {
+
+template <typename LexerType>
+void Parser<LexerType>::logError(bool)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ printUnexpectedTokenText(stream);
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B, typename C>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, value3, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B, typename C, typename D>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, value3, value4, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, value3, value4, value5, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E, typename F>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5, const F& value6)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, value3, value4, value5, value6, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E, typename F, typename G>
+void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5, const F& value6, const G& value7)
+{
+ if (hasError())
+ return;
+ StringPrintStream stream;
+ if (shouldPrintToken) {
+ printUnexpectedTokenText(stream);
+ stream.print(". ");
+ }
+ stream.print(value1, value2, value3, value4, value5, value6, value7, ".");
+ setErrorMessage(stream.toString());
+}
+
+template <typename LexerType>
+Parser<LexerType>::Parser(
+ VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode,
+ JSParserStrictMode strictMode, SourceParseMode parseMode,
+ ConstructorKind defaultConstructorKind, ThisTDZMode thisTDZMode)
+ : m_vm(vm)
+ , m_source(&source)
+ , m_hasStackOverflow(false)
+ , m_allowsIn(true)
+ , m_assignmentCount(0)
+ , m_nonLHSCount(0)
+ , m_syntaxAlreadyValidated(source.provider()->isValid())
+ , m_statementDepth(0)
+ , m_nonTrivialExpressionCount(0)
+ , m_lastIdentifier(0)
+ , m_lastFunctionName(nullptr)
+ , m_sourceElements(0)
+ , m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
+ , m_defaultConstructorKind(defaultConstructorKind)
+ , m_thisTDZMode(thisTDZMode)
+{
+ m_lexer = std::make_unique<LexerType>(vm, builtinMode);
+ m_lexer->setCode(source, &m_parserArena);
+ m_token.m_location.line = source.firstLine();
+ m_token.m_location.startOffset = source.startOffset();
+ m_token.m_location.endOffset = source.startOffset();
+ m_token.m_location.lineStartOffset = source.startOffset();
+ m_functionCache = vm->addSourceProviderCache(source.provider());
+ ScopeRef scope = pushScope();
+ if (isFunctionParseMode(parseMode))
+ scope->setIsFunction();
+ if (isModuleParseMode(parseMode))
+ scope->setIsModule();
+ if (strictMode == JSParserStrictMode::Strict)
+ scope->setStrictMode();
+
+ next();
+}
+
+template <typename LexerType>
+Parser<LexerType>::~Parser()
+{
+}
+
+template <typename LexerType>
+String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode)
+{
+ String parseError = String();
+
+ ASTBuilder context(const_cast<VM*>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source));
+ ScopeRef scope = currentScope();
+ scope->setIsLexicalScope();
+
+ bool isArrowFunctionBodyExpression = false;
+ if (m_lexer->isReparsingFunction()) {
+ ParserFunctionInfo<ASTBuilder> functionInfo;
+ parseFunctionParameters(context, parseMode, functionInfo);
+ m_parameters = functionInfo.parameters;
+
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ if (parseMode == SourceParseMode::ArrowFunctionMode && !hasError()) {
+ // The only way we could have an error wile reparsing is if we run out of stack space.
+ RELEASE_ASSERT(match(ARROWFUNCTION));
+ next();
+ isArrowFunctionBodyExpression = !match(OPENBRACE);
+ }
+#endif
+ }
+
+ if (!calleeName.isNull())
+ scope->declareCallee(&calleeName);
+
+ if (m_lexer->isReparsingFunction())
+ m_statementDepth--;
+
+ SourceElements* sourceElements = nullptr;
+ // The only way we can error this early is if we reparse a function and we run out of stack space.
+ if (!hasError()) {
+ if (isArrowFunctionBodyExpression)
+ sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
+#if ENABLE(ES6_MODULES)
+ else if (isModuleParseMode(parseMode))
+ sourceElements = parseModuleSourceElements(context, parseMode);
+#endif
+ else
+ sourceElements = parseSourceElements(context, CheckForStrictMode);
+ }
+
+ bool validEnding;
+ if (isArrowFunctionBodyExpression) {
+ ASSERT(m_lexer->isReparsingFunction());
+ // When we reparse and stack overflow, we're not guaranteed a valid ending. If we don't run out of stack space,
+ // then of course this will always be valid because we already parsed for syntax errors. But we must
+ // be cautious in case we run out of stack space.
+ validEnding = isEndOfArrowFunction();
+ } else
+ validEnding = consume(EOFTOK);
+
+ if (!sourceElements || !validEnding) {
+ if (hasError())
+ parseError = m_errorMessage;
+ else
+ parseError = ASCIILiteral("Parser error");
+ }
+
+ IdentifierSet capturedVariables;
+ bool modifiedParameter = false;
+ bool modifiedArguments = false;
+ scope->getCapturedVars(capturedVariables, modifiedParameter, modifiedArguments);
+ VariableEnvironment& varDeclarations = scope->declaredVariables();
+ for (auto& entry : capturedVariables)
+ varDeclarations.markVariableAsCaptured(entry);
+
+ CodeFeatures features = context.features();
+ if (scope->strictMode())
+ features |= StrictModeFeature;
+ if (scope->shadowsArguments())
+ features |= ShadowsArgumentsFeature;
+ if (modifiedParameter)
+ features |= ModifiedParameterFeature;
+ if (modifiedArguments)
+ features |= ModifiedArgumentsFeature;
+ Vector<RefPtr<UniquedStringImpl>> closedVariables;
+ if (m_parsingBuiltin) {
+ IdentifierSet usedVariables;
+ scope->getUsedVariables(usedVariables);
+ // FIXME: This needs to be changed if we want to allow builtins to use lexical declarations.
+ for (const auto& variable : usedVariables) {
+ Identifier identifier = Identifier::fromUid(m_vm, variable.get());
+ if (scope->hasDeclaredVariable(identifier))
+ continue;
+
+ if (scope->hasDeclaredParameter(identifier))
+ continue;
+
+ if (variable == m_vm->propertyNames->arguments.impl())
+ continue;
+
+ closedVariables.append(variable);
+ }
+
+ if (!capturedVariables.isEmpty()) {
+ for (const auto& capturedVariable : capturedVariables) {
+ if (scope->hasDeclaredVariable(capturedVariable))
+ continue;
+
+ if (scope->hasDeclaredParameter(capturedVariable))
+ continue;
+
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ }
+ }
+ didFinishParsing(sourceElements, context.funcDeclarations(), varDeclarations, features, context.numConstants(), WTF::move(closedVariables));
+
+ return parseError;
+}
+
+template <typename LexerType>
+void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::FunctionStack& funcStack,
+ VariableEnvironment& varDeclarations, CodeFeatures features, int numConstants, const Vector<RefPtr<UniquedStringImpl>>&& closedVariables)
+{
+ m_sourceElements = sourceElements;
+ m_funcDeclarations.swap(funcStack);
+ m_varDeclarations.swap(varDeclarations);
+ m_closedVariables = closedVariables;
+ m_features = features;
+ m_numConstants = numConstants;
+}
+
+template <typename LexerType>
+bool Parser<LexerType>::allowAutomaticSemicolon()
+{
+ return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context, SourceElementsMode mode)
+{
+ const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length
+ TreeSourceElements sourceElements = context.createSourceElements();
+ bool seenNonDirective = false;
+ const Identifier* directive = 0;
+ unsigned directiveLiteralLength = 0;
+ auto savePoint = createSavePoint();
+ bool hasSetStrict = false;
+
+ while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
+ if (mode == CheckForStrictMode && !seenNonDirective) {
+ if (directive) {
+ // "use strict" must be the exact literal without escape sequences or line continuation.
+ if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) {
+ setStrictMode();
+ hasSetStrict = true;
+ if (!isValidStrictMode()) {
+ if (m_lastFunctionName) {
+ if (m_vm->propertyNames->arguments == *m_lastFunctionName)
+ semanticFail("Cannot name a function 'arguments' in strict mode");
+ if (m_vm->propertyNames->eval == *m_lastFunctionName)
+ semanticFail("Cannot name a function 'eval' in strict mode");
+ }
+ if (hasDeclaredVariable(m_vm->propertyNames->arguments))
+ semanticFail("Cannot declare a variable named 'arguments' in strict mode");
+ if (hasDeclaredVariable(m_vm->propertyNames->eval))
+ semanticFail("Cannot declare a variable named 'eval' in strict mode");
+ semanticFailIfFalse(isValidStrictMode(), "Invalid parameters or function name in strict mode");
+ }
+ restoreSavePoint(savePoint);
+ propagateError();
+ continue;
+ }
+ } else
+ seenNonDirective = true;
+ }
+ context.appendStatement(sourceElements, statement);
+ }
+
+ propagateError();
+ return sourceElements;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSourceElements(TreeBuilder& context, SourceParseMode parseMode)
+{
+ TreeSourceElements sourceElements = context.createSourceElements();
+ SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
+
+ while (true) {
+ TreeStatement statement = 0;
+ if (match(IMPORT))
+ statement = parseImportDeclaration(context);
+ else if (match(EXPORT))
+ statement = parseExportDeclaration(context);
+ else {
+ const Identifier* directive = 0;
+ unsigned directiveLiteralLength = 0;
+ if (parseMode == SourceParseMode::ModuleAnalyzeMode) {
+ if (!parseStatementListItem(syntaxChecker, directive, &directiveLiteralLength))
+ break;
+ continue;
+ }
+ statement = parseStatementListItem(context, directive, &directiveLiteralLength);
+ }
+
+ if (!statement)
+ break;
+ context.appendStatement(sourceElements, statement);
+ }
+
+ propagateError();
+
+ for (const auto& uid : currentScope()->moduleScopeData().exportedBindings()) {
+ if (currentScope()->hasDeclaredVariable(uid)) {
+ currentScope()->declaredVariables().markVariableAsExported(uid);
+ continue;
+ }
+
+ if (currentScope()->hasLexicallyDeclaredVariable(uid)) {
+ currentScope()->lexicalVariables().markVariableAsExported(uid);
+ continue;
+ }
+
+ semanticFail("Exported binding '", uid.get(), "' needs to refer to a top-level declared variable");
+ }
+
+ return sourceElements;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
+{
+ // The grammar is documented here:
+ // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth++;
+ TreeStatement result = 0;
+ bool shouldSetEndOffset = true;
+ switch (m_token.m_type) {
+ case CONSTTOKEN:
+ result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration);
+ break;
+ case LET: {
+ bool shouldParseVariableDeclaration = true;
+ if (!strictMode()) {
+ SavePoint savePoint = createSavePoint();
+ next();
+ if (!match(IDENT) && !match(OPENBRACE) && !match(OPENBRACKET))
+ shouldParseVariableDeclaration = false;
+ restoreSavePoint(savePoint);
+ }
+ if (shouldParseVariableDeclaration)
+ result = parseVariableDeclaration(context, DeclarationType::LetDeclaration);
+ else
+ result = parseExpressionOrLabelStatement(context); // Treat this as an IDENT. This is how ::parseStatement() handles IDENT.
+
+ break;
+ }
+#if ENABLE(ES6_CLASS_SYNTAX)
+ case CLASSTOKEN:
+ result = parseClassDeclaration(context);
+ break;
+#endif
+ default:
+ m_statementDepth--; // parseStatement() increments the depth.
+ result = parseStatement(context, directive, directiveLiteralLength);
+ shouldSetEndOffset = false;
+ break;
+ }
+
+ if (result && shouldSetEndOffset)
+ context.setEndOffset(result, m_lastTokenEndPosition.offset);
+
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVariableDeclaration(TreeBuilder& context, DeclarationType declarationType, ExportType exportType)
+{
+ ASSERT(match(VAR) || match(LET) || match(CONSTTOKEN));
+ JSTokenLocation location(tokenLocation());
+ int start = tokenLine();
+ int end = 0;
+ int scratch;
+ TreeDestructuringPattern scratch1 = 0;
+ TreeExpression scratch2 = 0;
+ JSTextPosition scratch3;
+ bool scratchBool;
+ TreeExpression variableDecls = parseVariableDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext, declarationType, exportType, scratchBool);
+ propagateError();
+ failIfFalse(autoSemiColon(), "Expected ';' after variable declaration");
+
+ return context.createDeclarationStatement(location, variableDecls, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDoWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(DO));
+ int startLine = tokenLine();
+ next();
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement, "Expected a statement following 'do'");
+ int endLine = tokenLine();
+ JSTokenLocation location(tokenLocation());
+ handleProductionOrFail(WHILE, "while", "end", "do-while loop");
+ handleProductionOrFail(OPENPAREN, "(", "start", "do-while loop condition");
+ semanticFailIfTrue(match(CLOSEPAREN), "Must provide an expression as a do-while loop condition");
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Unable to parse do-while loop condition");
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "do-while loop condition");
+ if (match(SEMICOLON))
+ next(); // Always performs automatic semicolon insertion.
+ return context.createDoWhileStatement(location, statement, expr, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(WHILE));
+ JSTokenLocation location(tokenLocation());
+ int startLine = tokenLine();
+ next();
+
+ handleProductionOrFail(OPENPAREN, "(", "start", "while loop condition");
+ semanticFailIfTrue(match(CLOSEPAREN), "Must provide an expression as a while loop condition");
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Unable to parse while loop condition");
+ int endLine = tokenLine();
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "while loop condition");
+
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement, "Expected a statement as the body of a while loop");
+ return context.createWhileStatement(location, expr, statement, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext, DeclarationType declarationType, ExportType exportType, bool& forLoopConstDoesNotHaveInitializer)
+{
+ ASSERT(declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::VarDeclaration || declarationType == DeclarationType::ConstDeclaration);
+ TreeExpression head = 0;
+ TreeExpression tail = 0;
+ const Identifier* lastIdent;
+ JSToken lastIdentToken;
+ AssignmentContext assignmentContext = assignmentContextFromDeclarationType(declarationType);
+ do {
+ lastIdent = 0;
+ lastPattern = TreeDestructuringPattern(0);
+ JSTokenLocation location(tokenLocation());
+ next();
+ TreeExpression node = 0;
+ declarations++;
+ bool hasInitializer = false;
+ if (match(IDENT) || isLETMaskedAsIDENT()) {
+ failIfTrue(match(LET) && (declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::ConstDeclaration),
+ "Can't use 'let' as an identifier name for a LexicalDeclaration");
+ JSTextPosition varStart = tokenStartPosition();
+ JSTokenLocation varStartLocation(tokenLocation());
+ identStart = varStart;
+ const Identifier* name = m_token.m_data.ident;
+ lastIdent = name;
+ lastIdentToken = m_token;
+ next();
+ hasInitializer = match(EQUAL);
+ DeclarationResultMask declarationResult = declareVariable(name, declarationType);
+ if (declarationResult != DeclarationResult::Valid) {
+ failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named ", name->impl(), " in strict mode");
+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
+ if (declarationType == DeclarationType::LetDeclaration)
+ internalFailWithMessage(false, "Cannot declare a let variable twice: '", name->impl(), "'");
+ if (declarationType == DeclarationType::ConstDeclaration)
+ internalFailWithMessage(false, "Cannot declare a const variable twice: '", name->impl(), "'");
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+ }
+ if (exportType == ExportType::Exported) {
+ semanticFailIfFalse(exportName(*name), "Cannot export a duplicate name '", name->impl(), "'");
+ currentScope()->moduleScopeData().exportBinding(*name);
+ }
+
+ if (hasInitializer) {
+ JSTextPosition varDivot = tokenStartPosition() + 1;
+ initStart = tokenStartPosition();
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ TreeExpression initializer = parseAssignmentExpression(context);
+ initEnd = lastTokenEndPosition();
+ lastInitializer = initializer;
+ failIfFalse(initializer, "Expected expression as the intializer for the variable '", name->impl(), "'");
+
+ node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition(), assignmentContext);
+ } else {
+ if (declarationListContext == ForLoopContext && declarationType == DeclarationType::ConstDeclaration)
+ forLoopConstDoesNotHaveInitializer = true;
+ failIfTrue(declarationListContext != ForLoopContext && declarationType == DeclarationType::ConstDeclaration, "const declared variable '", name->impl(), "'", " must have an initializer");
+ if (declarationType == DeclarationType::VarDeclaration)
+ node = context.createEmptyVarExpression(varStartLocation, *name);
+ else
+ node = context.createEmptyLetExpression(varStartLocation, *name);
+ }
+ } else {
+ lastIdent = 0;
+ auto pattern = parseDestructuringPattern(context, destructuringKindFromDeclarationType(declarationType), exportType, nullptr, nullptr, assignmentContext);
+ failIfFalse(pattern, "Cannot parse this destructuring pattern");
+ hasInitializer = match(EQUAL);
+ failIfTrue(declarationListContext == VarDeclarationContext && !hasInitializer, "Expected an initializer in destructuring variable declaration");
+ lastPattern = pattern;
+ if (hasInitializer) {
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ TreeExpression rhs = parseAssignmentExpression(context);
+ node = context.createDestructuringAssignment(location, pattern, rhs);
+ lastInitializer = rhs;
+ }
+ }
+
+ if (!head)
+ head = node;
+ else if (!tail) {
+ head = context.createCommaExpr(location, head);
+ tail = context.appendToCommaExpr(location, head, head, node);
+ } else
+ tail = context.appendToCommaExpr(location, head, tail, node);
+ } while (match(COMMA));
+ if (lastIdent)
+ lastPattern = context.createBindingLocation(lastIdentToken.m_location, *lastIdent, lastIdentToken.m_startPosition, lastIdentToken.m_endPosition, assignmentContext);
+
+ return head;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier& name, int depth, JSToken token, AssignmentContext bindingContext, const Identifier** duplicateIdentifier)
+{
+ ASSERT(!name.isNull());
+
+ ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol());
+
+ if (kind == DestructureToVariables)
+ failIfTrueIfStrict(declareVariable(&name) & DeclarationResult::InvalidStrictMode, "Cannot declare a variable named '", name.impl(), "' in strict mode");
+ else if (kind == DestructureToLet || kind == DestructureToConst) {
+ DeclarationResultMask declarationResult = declareVariable(&name, kind == DestructureToLet ? DeclarationType::LetDeclaration : DeclarationType::ConstDeclaration);
+ if (declarationResult != DeclarationResult::Valid) {
+ failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot destructure to a variable named '", name.impl(), "' in strict mode");
+ failIfTrue(declarationResult & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare a lexical variable twice: '", name.impl(), "'");
+ }
+ } else if (kind == DestructureToParameters) {
+ if (depth) {
+ auto bindingResult = declareBoundParameter(&name);
+ if (bindingResult == Scope::StrictBindingFailed && strictMode()) {
+ semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
+ if (m_lastFunctionName && name == *m_lastFunctionName)
+ semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function");
+ semanticFailureDueToKeyword("bound parameter name");
+ if (hasDeclaredParameter(name))
+ semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared");
+ semanticFail("Cannot bind to a parameter named '", name.impl(), "' in strict mode");
+ }
+ if (bindingResult == Scope::BindingFailed) {
+ semanticFailureDueToKeyword("bound parameter name");
+ if (hasDeclaredParameter(name))
+ semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared");
+ semanticFail("Cannot destructure to a parameter named '", name.impl(), "'");
+ }
+ } else {
+ DeclarationResultMask declarationResult = declareParameter(&name);
+ if ((declarationResult & DeclarationResult::InvalidStrictMode) && strictMode()) {
+ semanticFailIfTrue(isEvalOrArguments(&name), "Cannot destructure to a parameter name '", name.impl(), "' in strict mode");
+ if (m_lastFunctionName && name == *m_lastFunctionName)
+ semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function");
+ semanticFailureDueToKeyword("parameter name");
+ if (hasDeclaredParameter(name))
+ semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared");
+ semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode");
+ }
+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration) {
+ // It's not always an error to define a duplicate parameter.
+ // It's only an error when there are default parameter values or destructuring parameters.
+ // We note this value now so we can check it later.
+ if (duplicateIdentifier)
+ *duplicateIdentifier = &name;
+ }
+ }
+ }
+
+ if (exportType == ExportType::Exported) {
+ semanticFailIfFalse(exportName(name), "Cannot export a duplicate name '", name.impl(), "'");
+ currentScope()->moduleScopeData().exportBinding(name);
+ }
+ return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition, bindingContext);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder& context)
+{
+ ASSERT(!match(OPENBRACE));
+
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+
+ failIfStackOverflow();
+ TreeExpression expr = parseAssignmentExpression(context);
+ failIfFalse(expr, "Cannot parse the arrow function expression");
+
+ context.setEndOffset(expr, m_lastTokenEndPosition.offset);
+
+ failIfFalse(isEndOfArrowFunction(), "Expected a ';', ']', '}', ')', ',', line terminator or EOF following a arrow function statement");
+
+ JSTextPosition end = tokenEndPosition();
+
+ if (!m_lexer->prevTerminator())
+ setEndOfStatement();
+
+ TreeSourceElements sourceElements = context.createSourceElements();
+ TreeStatement body = context.createReturnStatement(location, expr, start, end);
+ context.setEndOffset(body, m_lastTokenEndPosition.offset);
+ context.appendStatement(sourceElements, body);
+
+ return sourceElements;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context, AssignmentContext bindingContext)
+{
+ return parseDestructuringPattern(context, DestructureToExpressions, ExportType::NotExported, nullptr, nullptr, bindingContext);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, ExportType exportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth)
+{
+ failIfStackOverflow();
+ int nonLHSCount = m_nonLHSCount;
+ TreeDestructuringPattern pattern;
+ switch (m_token.m_type) {
+ case OPENBRACKET: {
+ JSTextPosition divotStart = tokenStartPosition();
+ auto arrayPattern = context.createArrayPattern(m_token.m_location);
+ next();
+
+ if (hasDestructuringPattern)
+ *hasDestructuringPattern = true;
+
+ bool restElementWasFound = false;
+
+ do {
+ while (match(COMMA)) {
+ context.appendArrayPatternSkipEntry(arrayPattern, m_token.m_location);
+ next();
+ }
+ propagateError();
+
+ if (match(CLOSEBRACKET))
+ break;
+
+ if (UNLIKELY(match(DOTDOTDOT))) {
+ JSTokenLocation location = m_token.m_location;
+ next();
+ auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
+ if (kind == DestructureToExpressions && !innerPattern)
+ return 0;
+ failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
+
+ failIfTrue(kind != DestructureToExpressions && !context.isBindingNode(innerPattern), "Expected identifier for a rest element destructuring pattern");
+
+ context.appendArrayPatternRestEntry(arrayPattern, location, innerPattern);
+ restElementWasFound = true;
+ break;
+ }
+
+ JSTokenLocation location = m_token.m_location;
+ auto innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
+ if (kind == DestructureToExpressions && !innerPattern)
+ return 0;
+ failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
+ TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
+ context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue);
+ } while (consume(COMMA));
+
+ if (kind == DestructureToExpressions && !match(CLOSEBRACKET))
+ return 0;
+ consumeOrFail(CLOSEBRACKET, restElementWasFound ? "Expected a closing ']' following a rest element destructuring pattern" : "Expected either a closing ']' or a ',' following an element destructuring pattern");
+ context.finishArrayPattern(arrayPattern, divotStart, divotStart, lastTokenEndPosition());
+ pattern = arrayPattern;
+ break;
+ }
+ case OPENBRACE: {
+ auto objectPattern = context.createObjectPattern(m_token.m_location);
+ next();
+
+ if (hasDestructuringPattern)
+ *hasDestructuringPattern = true;
+
+ do {
+ bool wasString = false;
+
+ if (match(CLOSEBRACE))
+ break;
+
+ const Identifier* propertyName = nullptr;
+ TreeDestructuringPattern innerPattern = 0;
+ JSTokenLocation location = m_token.m_location;
+ if (match(IDENT) || isLETMaskedAsIDENT()) {
+ failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
+ propertyName = m_token.m_data.ident;
+ JSToken identifierToken = m_token;
+ next();
+ if (consume(COLON))
+ innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
+ else
+ innerPattern = createBindingPattern(context, kind, exportType, *propertyName, depth + 1, identifierToken, bindingContext, duplicateIdentifier);
+ } else {
+ JSTokenType tokenType = m_token.m_type;
+ switch (m_token.m_type) {
+ case DOUBLE:
+ case INTEGER:
+ propertyName = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), m_token.m_data.doubleValue);
+ break;
+ case STRING:
+ propertyName = m_token.m_data.ident;
+ wasString = true;
+ break;
+ default:
+ if (m_token.m_type != RESERVED && m_token.m_type != RESERVED_IF_STRICT && !(m_token.m_type & KeywordTokenFlag)) {
+ if (kind == DestructureToExpressions)
+ return 0;
+ failWithMessage("Expected a property name");
+ }
+ propertyName = m_token.m_data.ident;
+ break;
+ }
+ next();
+ if (!consume(COLON)) {
+ if (kind == DestructureToExpressions)
+ return 0;
+ semanticFailIfTrue(tokenType == RESERVED, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName->impl(), "'");
+ semanticFailIfTrue(tokenType == RESERVED_IF_STRICT, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName->impl(), "' in strict mode");
+ semanticFailIfTrue(tokenType & KeywordTokenFlag, "Cannot use abbreviated destructuring syntax for keyword '", propertyName->impl(), "'");
+
+ failWithMessage("Expected a ':' prior to a named destructuring property");
+ }
+ innerPattern = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth + 1);
+ }
+ if (kind == DestructureToExpressions && !innerPattern)
+ return 0;
+ failIfFalse(innerPattern, "Cannot parse this destructuring pattern");
+ TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context);
+ ASSERT(propertyName);
+ context.appendObjectPatternEntry(objectPattern, location, wasString, *propertyName, innerPattern, defaultValue);
+ } while (consume(COMMA));
+
+ if (kind == DestructureToExpressions && !match(CLOSEBRACE))
+ return 0;
+ consumeOrFail(CLOSEBRACE, "Expected either a closing '}' or an ',' after a property destructuring pattern");
+ pattern = objectPattern;
+ break;
+ }
+
+ default: {
+ if (!match(IDENT) && !isLETMaskedAsIDENT()) {
+ if (kind == DestructureToExpressions)
+ return 0;
+ semanticFailureDueToKeyword("variable name");
+ failWithMessage("Expected a parameter pattern or a ')' in parameter list");
+ }
+ failIfTrue(match(LET) && (kind == DestructureToLet || kind == DestructureToConst), "Can't use 'let' as an identifier name for a LexicalDeclaration");
+ pattern = createBindingPattern(context, kind, exportType, *m_token.m_data.ident, depth, m_token, bindingContext, duplicateIdentifier);
+ next();
+ break;
+ }
+ }
+ m_nonLHSCount = nonLHSCount;
+ return pattern;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseDefaultValueForDestructuringPattern(TreeBuilder& context)
+{
+ if (!match(EQUAL))
+ return 0;
+
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ return parseAssignmentExpression(context);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(TreeBuilder& context)
+{
+ ASSERT(match(FOR));
+ JSTokenLocation location(tokenLocation());
+ int startLine = tokenLine();
+ next();
+ handleProductionOrFail(OPENPAREN, "(", "start", "for-loop header");
+ int nonLHSCount = m_nonLHSCount;
+ int declarations = 0;
+ JSTextPosition declsStart;
+ JSTextPosition declsEnd;
+ TreeExpression decls = 0;
+ TreeDestructuringPattern pattern = 0;
+ bool isVarDeclaraton = match(VAR);
+ bool isLetDeclaration = match(LET);
+ bool isConstDeclaration = match(CONSTTOKEN);
+ bool forLoopConstDoesNotHaveInitializer = false;
+
+ VariableEnvironment dummySet;
+ VariableEnvironment* lexicalVariables = nullptr;
+ AutoCleanupLexicalScope lexicalScope;
+
+ auto gatherLexicalVariablesIfNecessary = [&] {
+ if (isLetDeclaration || isConstDeclaration) {
+ ScopeRef scope = lexicalScope.scope();
+ lexicalVariables = &scope->finalizeLexicalEnvironment();
+ } else
+ lexicalVariables = &dummySet;
+ };
+
+ auto popLexicalScopeIfNecessary = [&] {
+ if (isLetDeclaration || isConstDeclaration)
+ popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
+ };
+
+ if (isVarDeclaraton || isLetDeclaration || isConstDeclaration) {
+ /*
+ for (var/let/const IDENT in/of expression) statement
+ for (var/let/const varDeclarationList; expressionOpt; expressionOpt)
+ */
+ if (isLetDeclaration || isConstDeclaration) {
+ ScopeRef newScope = pushScope();
+ newScope->setIsLexicalScope();
+ newScope->preventVarDeclarations();
+ lexicalScope.setIsValid(newScope, this);
+ }
+
+ TreeDestructuringPattern forInTarget = 0;
+ TreeExpression forInInitializer = 0;
+ m_allowsIn = false;
+ JSTextPosition initStart;
+ JSTextPosition initEnd;
+ DeclarationType declarationType;
+ if (isVarDeclaraton)
+ declarationType = DeclarationType::VarDeclaration;
+ else if (isLetDeclaration)
+ declarationType = DeclarationType::LetDeclaration;
+ else if (isConstDeclaration)
+ declarationType = DeclarationType::ConstDeclaration;
+ else
+ RELEASE_ASSERT_NOT_REACHED();
+ decls = parseVariableDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext, declarationType, ExportType::NotExported, forLoopConstDoesNotHaveInitializer);
+ m_allowsIn = true;
+ propagateError();
+
+ // Remainder of a standard for loop is handled identically
+ if (match(SEMICOLON))
+ goto standardForLoop;
+
+ failIfFalse(declarations == 1, "can only declare a single variable in an enumeration");
+ failIfTrueIfStrict(forInInitializer, "Cannot use initialiser syntax in a strict mode enumeration");
+
+ if (forInInitializer)
+ failIfFalse(context.isBindingNode(forInTarget), "Cannot use initialiser syntax when binding to a pattern during enumeration");
+
+ // Handle for-in with var declaration
+ JSTextPosition inLocation = tokenStartPosition();
+ bool isOfEnumeration = false;
+ if (!consume(INTOKEN)) {
+ failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+ isOfEnumeration = true;
+ failIfTrue(forInInitializer, "Cannot use initialiser syntax in a for-of enumeration");
+ next();
+ }
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Expected expression to enumerate");
+ JSTextPosition exprEnd = lastTokenEndPosition();
+
+ int endLine = tokenLine();
+
+ handleProductionOrFail(CLOSEPAREN, ")", "end", (isOfEnumeration ? "for-of header" : "for-in header"));
+
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement, "Expected statement as body of for-", isOfEnumeration ? "of" : "in", " statement");
+ gatherLexicalVariablesIfNecessary();
+ TreeStatement result;
+ if (isOfEnumeration)
+ result = context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
+ else
+ result = context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine, *lexicalVariables);
+ popLexicalScopeIfNecessary();
+ return result;
+ }
+
+ if (!match(SEMICOLON)) {
+ if (match(OPENBRACE) || match(OPENBRACKET)) {
+ SavePoint savePoint = createSavePoint();
+ declsStart = tokenStartPosition();
+ pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::DeclarationStatement);
+ declsEnd = lastTokenEndPosition();
+ if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of)))
+ goto enumerationLoop;
+ pattern = TreeDestructuringPattern(0);
+ restoreSavePoint(savePoint);
+ }
+ m_allowsIn = false;
+ declsStart = tokenStartPosition();
+ decls = parseExpression(context);
+ declsEnd = lastTokenEndPosition();
+ m_allowsIn = true;
+ failIfFalse(decls, "Cannot parse for loop declarations");
+ }
+
+ if (match(SEMICOLON)) {
+ standardForLoop:
+ // Standard for loop
+ next();
+ TreeExpression condition = 0;
+ failIfTrue(forLoopConstDoesNotHaveInitializer && isConstDeclaration, "const variables in for loops must have initializers");
+
+ if (!match(SEMICOLON)) {
+ condition = parseExpression(context);
+ failIfFalse(condition, "Cannot parse for loop condition expression");
+ }
+ consumeOrFail(SEMICOLON, "Expected a ';' after the for loop condition expression");
+
+ TreeExpression increment = 0;
+ if (!match(CLOSEPAREN)) {
+ increment = parseExpression(context);
+ failIfFalse(increment, "Cannot parse for loop iteration expression");
+ }
+ int endLine = tokenLine();
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "for-loop header");
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement, "Expected a statement as the body of a for loop");
+ gatherLexicalVariablesIfNecessary();
+ TreeStatement result = context.createForLoop(location, decls, condition, increment, statement, startLine, endLine, *lexicalVariables);
+ popLexicalScopeIfNecessary();
+ return result;
+ }
+
+ // For-in and For-of loop
+enumerationLoop:
+ failIfFalse(nonLHSCount == m_nonLHSCount, "Expected a reference on the left hand side of an enumeration statement");
+ bool isOfEnumeration = false;
+ if (!consume(INTOKEN)) {
+ failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+ isOfEnumeration = true;
+ next();
+ }
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Cannot parse subject for-", isOfEnumeration ? "of" : "in", " statement");
+ JSTextPosition exprEnd = lastTokenEndPosition();
+ int endLine = tokenLine();
+
+ handleProductionOrFail(CLOSEPAREN, ")", "end", (isOfEnumeration ? "for-of header" : "for-in header"));
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement, "Expected a statement as the body of a for-", isOfEnumeration ? "of" : "in", "loop");
+ gatherLexicalVariablesIfNecessary();
+ TreeStatement result;
+ if (pattern) {
+ ASSERT(!decls);
+ if (isOfEnumeration)
+ result = context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+ else
+ result = context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+
+ popLexicalScopeIfNecessary();
+ return result;
+ }
+ if (isOfEnumeration)
+ result = context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+ else
+ result = context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, *lexicalVariables);
+ popLexicalScopeIfNecessary();
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBreakStatement(TreeBuilder& context)
+{
+ ASSERT(match(BREAK));
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+ JSTextPosition end = tokenEndPosition();
+ next();
+
+ if (autoSemiColon()) {
+ semanticFailIfFalse(breakIsValid(), "'break' is only valid inside a switch or loop statement");
+ return context.createBreakStatement(location, &m_vm->propertyNames->nullIdentifier, start, end);
+ }
+ failIfFalse(match(IDENT) || isLETMaskedAsIDENT(), "Expected an identifier as the target for a break statement");
+ const Identifier* ident = m_token.m_data.ident;
+ semanticFailIfFalse(getLabel(ident), "Cannot use the undeclared label '", ident->impl(), "'");
+ end = tokenEndPosition();
+ next();
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted break statement");
+ return context.createBreakStatement(location, ident, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseContinueStatement(TreeBuilder& context)
+{
+ ASSERT(match(CONTINUE));
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+ JSTextPosition end = tokenEndPosition();
+ next();
+
+ if (autoSemiColon()) {
+ semanticFailIfFalse(continueIsValid(), "'continue' is only valid inside a loop statement");
+ return context.createContinueStatement(location, &m_vm->propertyNames->nullIdentifier, start, end);
+ }
+ failIfFalse(match(IDENT) || isLETMaskedAsIDENT(), "Expected an identifier as the target for a continue statement");
+ const Identifier* ident = m_token.m_data.ident;
+ ScopeLabelInfo* label = getLabel(ident);
+ semanticFailIfFalse(label, "Cannot use the undeclared label '", ident->impl(), "'");
+ semanticFailIfFalse(label->isLoop, "Cannot continue to the label '", ident->impl(), "' as it is not targeting a loop");
+ end = tokenEndPosition();
+ next();
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted continue statement");
+ return context.createContinueStatement(location, ident, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseReturnStatement(TreeBuilder& context)
+{
+ ASSERT(match(RETURN));
+ JSTokenLocation location(tokenLocation());
+ semanticFailIfFalse(currentScope()->isFunction(), "Return statements are only valid inside functions");
+ JSTextPosition start = tokenStartPosition();
+ JSTextPosition end = tokenEndPosition();
+ next();
+ // We do the auto semicolon check before attempting to parse expression
+ // as we need to ensure the a line break after the return correctly terminates
+ // the statement
+ if (match(SEMICOLON))
+ end = tokenEndPosition();
+
+ if (autoSemiColon())
+ return context.createReturnStatement(location, 0, start, end);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Cannot parse the return expression");
+ end = lastTokenEndPosition();
+ if (match(SEMICOLON))
+ end = tokenEndPosition();
+ if (!autoSemiColon())
+ failWithMessage("Expected a ';' following a return statement");
+ return context.createReturnStatement(location, expr, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseThrowStatement(TreeBuilder& context)
+{
+ ASSERT(match(THROW));
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+ next();
+ failIfTrue(match(SEMICOLON), "Expected expression after 'throw'");
+ semanticFailIfTrue(autoSemiColon(), "Cannot have a newline after 'throw'");
+
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Cannot parse expression for throw statement");
+ JSTextPosition end = lastTokenEndPosition();
+ failIfFalse(autoSemiColon(), "Expected a ';' after a throw statement");
+
+ return context.createThrowStatement(location, expr, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement(TreeBuilder& context)
+{
+ ASSERT(match(WITH));
+ JSTokenLocation location(tokenLocation());
+ semanticFailIfTrue(strictMode(), "'with' statements are not valid in strict mode");
+ currentScope()->setNeedsFullActivation();
+ int startLine = tokenLine();
+ next();
+
+ handleProductionOrFail(OPENPAREN, "(", "start", "subject of a 'with' statement");
+ int start = tokenStart();
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Cannot parse 'with' subject expression");
+ JSTextPosition end = lastTokenEndPosition();
+ int endLine = tokenLine();
+ handleProductionOrFail(CLOSEPAREN, ")", "start", "subject of a 'with' statement");
+ const Identifier* unused = 0;
+ TreeStatement statement = parseStatement(context, unused);
+ failIfFalse(statement, "A 'with' statement must have a body");
+
+ return context.createWithStatement(location, expr, statement, start, end, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseSwitchStatement(TreeBuilder& context)
+{
+ ASSERT(match(SWITCH));
+ JSTokenLocation location(tokenLocation());
+ int startLine = tokenLine();
+ next();
+ handleProductionOrFail(OPENPAREN, "(", "start", "subject of a 'switch'");
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr, "Cannot parse switch subject expression");
+ int endLine = tokenLine();
+
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "subject of a 'switch'");
+ handleProductionOrFail(OPENBRACE, "{", "start", "body of a 'switch'");
+ AutoPopScopeRef lexicalScope(this, pushScope());
+ lexicalScope->setIsLexicalScope();
+ lexicalScope->preventVarDeclarations();
+ startSwitch();
+ TreeClauseList firstClauses = parseSwitchClauses(context);
+ propagateError();
+
+ TreeClause defaultClause = parseSwitchDefaultClause(context);
+ propagateError();
+
+ TreeClauseList secondClauses = parseSwitchClauses(context);
+ propagateError();
+ endSwitch();
+ handleProductionOrFail(CLOSEBRACE, "}", "end", "body of a 'switch'");
+
+ TreeStatement result = context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine, lexicalScope->finalizeLexicalEnvironment());
+ popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeClauseList Parser<LexerType>::parseSwitchClauses(TreeBuilder& context)
+{
+ if (!match(CASE))
+ return 0;
+ unsigned startOffset = tokenStart();
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition, "Cannot parse switch clause");
+ consumeOrFail(COLON, "Expected a ':' after switch clause expression");
+ TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode);
+ failIfFalse(statements, "Cannot parse the body of a switch clause");
+ TreeClause clause = context.createClause(condition, statements);
+ context.setStartOffset(clause, startOffset);
+ TreeClauseList clauseList = context.createClauseList(clause);
+ TreeClauseList tail = clauseList;
+
+ while (match(CASE)) {
+ startOffset = tokenStart();
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition, "Cannot parse switch case expression");
+ consumeOrFail(COLON, "Expected a ':' after switch clause expression");
+ TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode);
+ failIfFalse(statements, "Cannot parse the body of a switch clause");
+ clause = context.createClause(condition, statements);
+ context.setStartOffset(clause, startOffset);
+ tail = context.createClauseList(tail, clause);
+ }
+ return clauseList;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeClause Parser<LexerType>::parseSwitchDefaultClause(TreeBuilder& context)
+{
+ if (!match(DEFAULT))
+ return 0;
+ unsigned startOffset = tokenStart();
+ next();
+ consumeOrFail(COLON, "Expected a ':' after switch default clause");
+ TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode);
+ failIfFalse(statements, "Cannot parse the body of a switch default clause");
+ TreeClause result = context.createClause(0, statements);
+ context.setStartOffset(result, startOffset);
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement(TreeBuilder& context)
+{
+ ASSERT(match(TRY));
+ JSTokenLocation location(tokenLocation());
+ TreeStatement tryBlock = 0;
+ const Identifier* ident = &m_vm->propertyNames->nullIdentifier;
+ TreeStatement catchBlock = 0;
+ TreeStatement finallyBlock = 0;
+ int firstLine = tokenLine();
+ next();
+ matchOrFail(OPENBRACE, "Expected a block statement as body of a try statement");
+
+ tryBlock = parseBlockStatement(context);
+ failIfFalse(tryBlock, "Cannot parse the body of try block");
+ int lastLine = m_lastTokenEndPosition.line;
+ VariableEnvironment catchEnvironment;
+ if (match(CATCH)) {
+ next();
+
+ handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target");
+ if (!(match(IDENT) || isLETMaskedAsIDENT())) {
+ semanticFailureDueToKeyword("catch variable name");
+ failWithMessage("Expected identifier name as catch target");
+ }
+ ident = m_token.m_data.ident;
+ next();
+ AutoPopScopeRef catchScope(this, pushScope());
+ catchScope->setIsLexicalScope();
+ catchScope->preventVarDeclarations();
+ failIfTrueIfStrict(catchScope->declareLexicalVariable(ident, false) & DeclarationResult::InvalidStrictMode, "Cannot declare a catch variable named '", ident->impl(), "' in strict mode");
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
+ matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
+ catchBlock = parseBlockStatement(context);
+ failIfFalse(catchBlock, "Unable to parse 'catch' block");
+ catchEnvironment = catchScope->finalizeLexicalEnvironment();
+ RELEASE_ASSERT(catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl()));
+ popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
+ }
+
+ if (match(FINALLY)) {
+ next();
+ matchOrFail(OPENBRACE, "Expected block statement for finally body");
+ finallyBlock = parseBlockStatement(context);
+ failIfFalse(finallyBlock, "Cannot parse finally body");
+ }
+ failIfFalse(catchBlock || finallyBlock, "Try statements must have at least a catch or finally block");
+ return context.createTryStatement(location, tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine, catchEnvironment);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDebuggerStatement(TreeBuilder& context)
+{
+ ASSERT(match(DEBUGGER));
+ JSTokenLocation location(tokenLocation());
+ int startLine = tokenLine();
+ int endLine = startLine;
+ next();
+ if (match(SEMICOLON))
+ startLine = tokenLine();
+ failIfFalse(autoSemiColon(), "Debugger keyword must be followed by a ';'");
+ return context.createDebugger(location, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context)
+{
+ ASSERT(match(OPENBRACE));
+
+ // We should treat the first block statement of the function (the body of the function) as the lexical
+ // scope of the function itself, and not the lexical scope of a 'block' statement within the function.
+ AutoCleanupLexicalScope lexicalScope;
+ bool shouldPushLexicalScope = m_statementDepth > 0;
+ if (shouldPushLexicalScope) {
+ ScopeRef newScope = pushScope();
+ newScope->setIsLexicalScope();
+ newScope->preventVarDeclarations();
+ lexicalScope.setIsValid(newScope, this);
+ }
+ JSTokenLocation location(tokenLocation());
+ int startOffset = m_token.m_data.offset;
+ int start = tokenLine();
+ VariableEnvironment emptyEnvironment;
+ next();
+ if (match(CLOSEBRACE)) {
+ int endOffset = m_token.m_data.offset;
+ next();
+ TreeStatement result = context.createBlockStatement(location, 0, start, m_lastTokenEndPosition.line, shouldPushLexicalScope ? currentScope()->finalizeLexicalEnvironment() : emptyEnvironment);
+ context.setStartOffset(result, startOffset);
+ context.setEndOffset(result, endOffset);
+ if (shouldPushLexicalScope)
+ popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
+ return result;
+ }
+ TreeSourceElements subtree = parseSourceElements(context, DontCheckForStrictMode);
+ failIfFalse(subtree, "Cannot parse the body of the block statement");
+ matchOrFail(CLOSEBRACE, "Expected a closing '}' at the end of a block statement");
+ int endOffset = m_token.m_data.offset;
+ next();
+ TreeStatement result = context.createBlockStatement(location, subtree, start, m_lastTokenEndPosition.line, shouldPushLexicalScope ? currentScope()->finalizeLexicalEnvironment() : emptyEnvironment);
+ context.setStartOffset(result, startOffset);
+ context.setEndOffset(result, endOffset);
+ if (shouldPushLexicalScope)
+ popScope(lexicalScope, TreeBuilder::NeedsFreeVariableInfo);
+
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
+{
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth++;
+ directive = 0;
+ int nonTrivialExpressionCount = 0;
+ failIfStackOverflow();
+ TreeStatement result = 0;
+ bool shouldSetEndOffset = true;
+
+ switch (m_token.m_type) {
+ case OPENBRACE:
+ result = parseBlockStatement(context);
+ shouldSetEndOffset = false;
+ break;
+ case VAR:
+ result = parseVariableDeclaration(context, DeclarationType::VarDeclaration);
+ break;
+ case FUNCTION:
+ failIfFalseIfStrict(m_statementDepth == 1, "Strict mode does not allow function declarations in a lexically nested statement");
+ result = parseFunctionDeclaration(context);
+ break;
+ case SEMICOLON: {
+ JSTokenLocation location(tokenLocation());
+ next();
+ result = context.createEmptyStatement(location);
+ break;
+ }
+ case IF:
+ result = parseIfStatement(context);
+ break;
+ case DO:
+ result = parseDoWhileStatement(context);
+ break;
+ case WHILE:
+ result = parseWhileStatement(context);
+ break;
+ case FOR:
+ result = parseForStatement(context);
+ break;
+ case CONTINUE:
+ result = parseContinueStatement(context);
+ break;
+ case BREAK:
+ result = parseBreakStatement(context);
+ break;
+ case RETURN:
+ result = parseReturnStatement(context);
+ break;
+ case WITH:
+ result = parseWithStatement(context);
+ break;
+ case SWITCH:
+ result = parseSwitchStatement(context);
+ break;
+ case THROW:
+ result = parseThrowStatement(context);
+ break;
+ case TRY:
+ result = parseTryStatement(context);
+ break;
+ case DEBUGGER:
+ result = parseDebuggerStatement(context);
+ break;
+ case EOFTOK:
+ case CASE:
+ case CLOSEBRACE:
+ case DEFAULT:
+ // These tokens imply the end of a set of source elements
+ return 0;
+ case IDENT:
+ result = parseExpressionOrLabelStatement(context);
+ break;
+ case STRING:
+ directive = m_token.m_data.ident;
+ if (directiveLiteralLength)
+ *directiveLiteralLength = m_token.m_location.endOffset - m_token.m_location.startOffset;
+ nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ FALLTHROUGH;
+ default:
+ TreeStatement exprStatement = parseExpressionStatement(context);
+ if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+ directive = 0;
+ result = exprStatement;
+ break;
+ }
+
+ if (result && shouldSetEndOffset)
+ context.setEndOffset(result, m_lastTokenEndPosition.offset);
+ return result;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> bool Parser<LexerType>::parseFormalParameters(TreeBuilder& context, TreeFormalParameterList list, unsigned& parameterCount)
+{
+#define failFromDuplicate() \
+ if (duplicateParameter) {\
+ semanticFailIfTrue(defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");\
+ semanticFailIfTrue(hasDestructuringPattern, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with destructuring parameters");\
+ }
+
+ const Identifier* duplicateParameter = nullptr;
+ bool hasDestructuringPattern = false;
+ auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
+ failIfFalse(parameter, "Cannot parse parameter pattern");
+ auto defaultValue = parseDefaultValueForDestructuringPattern(context);
+ propagateError();
+ failFromDuplicate();
+ context.appendParameter(list, parameter, defaultValue);
+ parameterCount++;
+ while (consume(COMMA)) {
+ parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter, &hasDestructuringPattern);
+ failIfFalse(parameter, "Cannot parse parameter pattern");
+ defaultValue = parseDefaultValueForDestructuringPattern(context);
+ propagateError();
+ failFromDuplicate();
+ context.appendParameter(list, parameter, defaultValue);
+ parameterCount++;
+ }
+ return true;
+#undef failFromDuplicate
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(
+ TreeBuilder& context, const JSTokenLocation& startLocation, int startColumn, int functionKeywordStart, int functionNameStart, int parametersStart,
+ ConstructorKind constructorKind, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
+{
+ if (bodyType == StandardFunctionBodyBlock || bodyType == ArrowFunctionBodyBlock) {
+ next();
+ if (match(CLOSEBRACE)) {
+ unsigned endColumn = tokenColumn();
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode);
+ }
+ }
+
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth = 0;
+ SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
+ if (bodyType == ArrowFunctionBodyExpression)
+ failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(syntaxChecker), "Cannot parse body of this arrow function");
+ else
+ failIfFalse(parseSourceElements(syntaxChecker, CheckForStrictMode), bodyType == StandardFunctionBodyBlock ? "Cannot parse body of this function" : "Cannot parse body of this arrow function");
+ unsigned endColumn = tokenColumn();
+ return context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind, parameterCount, parseMode);
+}
+
+static const char* stringForFunctionMode(SourceParseMode mode)
+{
+ switch (mode) {
+ case SourceParseMode::GetterMode:
+ return "getter";
+ case SourceParseMode::SetterMode:
+ return "setter";
+ case SourceParseMode::NormalFunctionMode:
+ return "function";
+ case SourceParseMode::MethodMode:
+ return "method";
+ case SourceParseMode::ArrowFunctionMode:
+ return "arrow function";
+ case SourceParseMode::ProgramMode:
+ case SourceParseMode::ModuleAnalyzeMode:
+ case SourceParseMode::ModuleEvaluateMode:
+ RELEASE_ASSERT_NOT_REACHED();
+ return "";
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return nullptr;
+}
+
+template <typename LexerType> template <class TreeBuilder> int Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, SourceParseMode mode, ParserFunctionInfo<TreeBuilder>& functionInfo)
+{
+ RELEASE_ASSERT(mode != SourceParseMode::ProgramMode && mode != SourceParseMode::ModuleAnalyzeMode && mode != SourceParseMode::ModuleEvaluateMode);
+ int parametersStart = m_token.m_location.startOffset;
+ TreeFormalParameterList parameterList = context.createFormalParameterList();
+ functionInfo.parameters = parameterList;
+ functionInfo.startOffset = parametersStart;
+
+ if (mode == SourceParseMode::ArrowFunctionMode) {
+ if (!match(IDENT) && !match(OPENPAREN)) {
+ semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
+ failWithMessage("Expected an arrow function input parameter");
+ } else {
+ if (match(OPENPAREN)) {
+ next();
+
+ if (match(CLOSEPAREN))
+ functionInfo.parameterCount = 0;
+ else
+ failIfFalse(parseFormalParameters(context, parameterList, functionInfo.parameterCount), "Cannot parse parameters for this ", stringForFunctionMode(mode));
+
+ consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration");
+ } else {
+ functionInfo.parameterCount = 1;
+ auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported);
+ failIfFalse(parameter, "Cannot parse parameter pattern");
+ context.appendParameter(parameterList, parameter, 0);
+ }
+ }
+
+ return parametersStart;
+ }
+
+ if (!consume(OPENPAREN)) {
+ semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
+ failWithMessage("Expected an opening '(' before a ", stringForFunctionMode(mode), "'s parameter list");
+ }
+
+ if (mode == SourceParseMode::GetterMode) {
+ consumeOrFail(CLOSEPAREN, "getter functions must have no parameters");
+ functionInfo.parameterCount = 0;
+ } else if (mode == SourceParseMode::SetterMode) {
+ failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter");
+ const Identifier* duplicateParameter = nullptr;
+ auto parameter = parseDestructuringPattern(context, DestructureToParameters, ExportType::NotExported, &duplicateParameter);
+ failIfFalse(parameter, "setter functions must have one parameter");
+ auto defaultValue = parseDefaultValueForDestructuringPattern(context);
+ propagateError();
+ semanticFailIfTrue(duplicateParameter && defaultValue, "Duplicate parameter '", duplicateParameter->impl(), "' not allowed in function with default parameter values");
+ context.appendParameter(parameterList, parameter, defaultValue);
+ functionInfo.parameterCount = 1;
+ failIfTrue(match(COMMA), "setter functions must have one parameter");
+ consumeOrFail(CLOSEPAREN, "Expected a ')' after a parameter declaration");
+ } else {
+ if (match(CLOSEPAREN))
+ functionInfo.parameterCount = 0;
+ else
+ failIfFalse(parseFormalParameters(context, parameterList, functionInfo.parameterCount), "Cannot parse parameters for this ", stringForFunctionMode(mode));
+ consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration");
+ }
+
+ return parametersStart;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, SourceParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& functionInfo, FunctionParseType parseType)
+{
+ RELEASE_ASSERT(isFunctionParseMode(mode));
+
+ AutoPopScopeRef functionScope(this, pushScope());
+ functionScope->setIsFunction();
+ int functionNameStart = m_token.m_location.startOffset;
+ const Identifier* lastFunctionName = m_lastFunctionName;
+ m_lastFunctionName = nullptr;
+ int parametersStart;
+ JSTokenLocation startLocation;
+ int startColumn;
+ FunctionBodyType functionBodyType;
+
+ switch (parseType) {
+ case StandardFunctionParseType: {
+ RELEASE_ASSERT(mode != SourceParseMode::ArrowFunctionMode);
+ if (match(IDENT) || isLETMaskedAsIDENT()) {
+ functionInfo.name = m_token.m_data.ident;
+ m_lastFunctionName = functionInfo.name;
+ next();
+ if (!nameIsInContainingScope)
+ failIfTrueIfStrict(functionScope->declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "'", functionInfo.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode");
+ } else if (requirements == FunctionNeedsName) {
+ if (match(OPENPAREN) && mode == SourceParseMode::NormalFunctionMode)
+ semanticFail("Function statements must have a name");
+ semanticFailureDueToKeyword(stringForFunctionMode(mode), " name");
+ failDueToUnexpectedToken();
+ return false;
+ }
+
+ startLocation = tokenLocation();
+ functionInfo.startLine = tokenLine();
+ startColumn = tokenColumn();
+
+ parametersStart = parseFunctionParameters(context, mode, functionInfo);
+ propagateError();
+
+ matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
+
+ // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed.
+ // Set ConstructorKind to None for non-constructor methods of classes.
+
+ if (m_defaultConstructorKind != ConstructorKind::None) {
+ constructorKind = m_defaultConstructorKind;
+ expectedSuperBinding = m_defaultConstructorKind == ConstructorKind::Derived ? SuperBinding::Needed : SuperBinding::NotNeeded;
+ }
+
+ functionBodyType = StandardFunctionBodyBlock;
+
+ break;
+ }
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ case ArrowFunctionParseType: {
+ RELEASE_ASSERT(mode == SourceParseMode::ArrowFunctionMode);
+
+ startLocation = tokenLocation();
+ functionInfo.startLine = tokenLine();
+ startColumn = tokenColumn();
+
+ parametersStart = parseFunctionParameters(context, mode, functionInfo);
+ propagateError();
+
+ matchOrFail(ARROWFUNCTION, "Expected a '=>' after arrow function parameter declaration");
+
+ if (m_lexer->prevTerminator())
+ failDueToUnexpectedToken();
+
+ ASSERT(constructorKind == ConstructorKind::None);
+
+ // Check if arrow body start with {. If it true it mean that arrow function is Fat arrow function
+ // and we need use common approach to parse function body
+ next();
+ functionBodyType = match(OPENBRACE) ? ArrowFunctionBodyBlock : ArrowFunctionBodyExpression;
+
+ break;
+ }
+#else
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+#endif
+ }
+
+ bool isClassConstructor = constructorKind != ConstructorKind::None;
+
+ functionInfo.bodyStartColumn = startColumn;
+
+ // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
+ if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(functionInfo.startOffset) : 0) {
+ // If we're in a strict context, the cached function info must say it was strict too.
+ ASSERT(!strictMode() || cachedInfo->strictMode);
+ JSTokenLocation endLocation;
+
+ endLocation.line = cachedInfo->lastTockenLine;
+ endLocation.startOffset = cachedInfo->lastTockenStartOffset;
+ endLocation.lineStartOffset = cachedInfo->lastTockenLineStartOffset;
+
+ bool endColumnIsOnStartLine = (endLocation.line == functionInfo.startLine);
+ ASSERT(endLocation.startOffset >= endLocation.lineStartOffset);
+ unsigned bodyEndColumn = endColumnIsOnStartLine ?
+ endLocation.startOffset - m_token.m_data.lineStartOffset :
+ endLocation.startOffset - endLocation.lineStartOffset;
+ unsigned currentLineStartOffset = m_token.m_location.lineStartOffset;
+
+ functionInfo.body = context.createFunctionMetadata(
+ startLocation, endLocation, functionInfo.bodyStartColumn, bodyEndColumn,
+ functionKeywordStart, functionNameStart, parametersStart,
+ cachedInfo->strictMode, constructorKind, cachedInfo->parameterCount, mode);
+
+ functionScope->restoreFromSourceProviderCache(cachedInfo);
+ popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
+
+ m_token = cachedInfo->endFunctionToken();
+
+ if (endColumnIsOnStartLine)
+ m_token.m_location.lineStartOffset = currentLineStartOffset;
+
+ m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset);
+ m_lexer->setLineNumber(m_token.m_location.line);
+ functionInfo.endOffset = cachedInfo->endFunctionOffset;
+
+ if (parseType == ArrowFunctionParseType)
+ functionBodyType = cachedInfo->isBodyArrowExpression ? ArrowFunctionBodyExpression : ArrowFunctionBodyBlock;
+ else
+ functionBodyType = StandardFunctionBodyBlock;
+
+ switch (functionBodyType) {
+ case ArrowFunctionBodyExpression:
+ next();
+ context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
+ break;
+ case ArrowFunctionBodyBlock:
+ case StandardFunctionBodyBlock:
+ context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
+ next();
+ break;
+ }
+ functionInfo.endLine = m_lastTokenEndPosition.line;
+ return true;
+ }
+
+ m_lastFunctionName = lastFunctionName;
+ ParserState oldState = saveState();
+
+ functionInfo.body = parseFunctionBody(context, startLocation, startColumn, functionKeywordStart, functionNameStart, parametersStart, constructorKind, functionBodyType, functionInfo.parameterCount, mode);
+
+ restoreState(oldState);
+ failIfFalse(functionInfo.body, "Cannot parse the body of this ", stringForFunctionMode(mode));
+ context.setEndOffset(functionInfo.body, m_lexer->currentOffset());
+ if (functionScope->strictMode() && functionInfo.name) {
+ RELEASE_ASSERT(mode == SourceParseMode::NormalFunctionMode || mode == SourceParseMode::MethodMode || mode == SourceParseMode::ArrowFunctionMode);
+ semanticFailIfTrue(m_vm->propertyNames->arguments == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
+ semanticFailIfTrue(m_vm->propertyNames->eval == *functionInfo.name, "'", functionInfo.name->impl(), "' is not a valid function name in strict mode");
+ }
+ if (functionScope->hasDirectSuper()) {
+ semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor");
+ semanticFailIfTrue(constructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
+ }
+ if (functionScope->needsSuperBinding())
+ semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class");
+
+ JSTokenLocation location = JSTokenLocation(m_token.m_location);
+ functionInfo.endOffset = m_token.m_data.offset;
+
+ if (functionBodyType == ArrowFunctionBodyExpression) {
+ location = locationBeforeLastToken();
+ functionInfo.endOffset = location.endOffset;
+ }
+
+ // Cache the tokenizer state and the function scope the first time the function is parsed.
+ // Any future reparsing can then skip the function.
+ static const int minimumFunctionLengthToCache = 16;
+ std::unique_ptr<SourceProviderCacheItem> newInfo;
+ int functionLength = functionInfo.endOffset - functionInfo.startOffset;
+ if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
+ SourceProviderCacheItemCreationParameters parameters;
+ parameters.endFunctionOffset = functionInfo.endOffset;
+ parameters.functionNameStart = functionNameStart;
+ parameters.lastTockenLine = location.line;
+ parameters.lastTockenStartOffset = location.startOffset;
+ parameters.lastTockenEndOffset = location.endOffset;
+ parameters.lastTockenLineStartOffset = location.lineStartOffset;
+ parameters.parameterCount = functionInfo.parameterCount;
+ if (functionBodyType == ArrowFunctionBodyExpression) {
+ parameters.isBodyArrowExpression = true;
+ parameters.tokenType = m_token.m_type;
+ }
+ functionScope->fillParametersForSourceProviderCache(parameters);
+ newInfo = SourceProviderCacheItem::create(parameters);
+ }
+
+ popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
+
+ if (functionBodyType == ArrowFunctionBodyExpression)
+ failIfFalse(isEndOfArrowFunction(), "Expected the closing ';' ',' ']' ')' '}', line terminator or EOF after arrow function");
+ else {
+ matchOrFail(CLOSEBRACE, "Expected a closing '}' after a ", stringForFunctionMode(mode), " body");
+ next();
+ }
+
+ if (newInfo)
+ m_functionCache->add(functionInfo.startOffset, WTF::move(newInfo));
+
+ functionInfo.endLine = m_lastTokenEndPosition.line;
+ return true;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context, ExportType exportType)
+{
+ ASSERT(match(FUNCTION));
+ JSTokenLocation location(tokenLocation());
+ unsigned functionKeywordStart = tokenStart();
+ next();
+ ParserFunctionInfo<TreeBuilder> functionInfo;
+ failIfFalse((parseFunctionInfo(context, FunctionNeedsName, SourceParseMode::NormalFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded,
+ functionKeywordStart, functionInfo, StandardFunctionParseType)), "Cannot parse this function");
+ failIfFalse(functionInfo.name, "Function statements must have a name");
+ failIfTrueIfStrict(declareVariable(functionInfo.name) & DeclarationResult::InvalidStrictMode, "Cannot declare a function named '", functionInfo.name->impl(), "' in strict mode");
+ if (exportType == ExportType::Exported) {
+ semanticFailIfFalse(exportName(*functionInfo.name), "Cannot export a duplicate function name: '", functionInfo.name->impl(), "'");
+ currentScope()->moduleScopeData().exportBinding(*functionInfo.name);
+ }
+ return context.createFuncDeclStatement(location, functionInfo);
+}
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context, ExportType exportType)
+{
+ ASSERT(match(CLASSTOKEN));
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition classStart = tokenStartPosition();
+ unsigned classStartLine = tokenLine();
+
+ ParserClassInfo<TreeBuilder> info;
+ TreeClassExpression classExpr = parseClass(context, FunctionNeedsName, info);
+ failIfFalse(classExpr, "Failed to parse class");
+
+ DeclarationResultMask declarationResult = declareVariable(info.className, DeclarationType::LetDeclaration);
+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
+ internalFailWithMessage(false, "Cannot declare a class twice: '", info.className->impl(), "'");
+ if (exportType == ExportType::Exported) {
+ semanticFailIfFalse(exportName(*info.className), "Cannot export a duplicate class name: '", info.className->impl(), "'");
+ currentScope()->moduleScopeData().exportBinding(*info.className);
+ }
+
+ JSTextPosition classEnd = lastTokenEndPosition();
+ unsigned classEndLine = tokenLine();
+
+ return context.createClassDeclStatement(location, classExpr, classStart, classEnd, classStartLine, classEndLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionRequirements requirements, ParserClassInfo<TreeBuilder>& info)
+{
+ ASSERT(match(CLASSTOKEN));
+ JSTokenLocation location(tokenLocation());
+ next();
+
+ AutoPopScopeRef classScope(this, pushScope());
+ classScope->setStrictMode();
+
+ const Identifier* className = nullptr;
+ if (match(IDENT)) {
+ className = m_token.m_data.ident;
+ info.className = className;
+ next();
+ failIfTrue(classScope->declareVariable(className) & DeclarationResult::InvalidStrictMode, "'", className->impl(), "' is not a valid class name");
+ } else if (requirements == FunctionNeedsName) {
+ if (match(OPENBRACE))
+ semanticFail("Class statements must have a name");
+ semanticFailureDueToKeyword("class name");
+ failDueToUnexpectedToken();
+ } else
+ className = &m_vm->propertyNames->nullIdentifier;
+ ASSERT(className);
+
+ TreeExpression parentClass = 0;
+ if (consume(EXTENDS)) {
+ parentClass = parseMemberExpression(context);
+ failIfFalse(parentClass, "Cannot parse the parent class name");
+ }
+ const ConstructorKind constructorKind = parentClass ? ConstructorKind::Derived : ConstructorKind::Base;
+
+ consumeOrFail(OPENBRACE, "Expected opening '{' at the start of a class body");
+
+ TreeExpression constructor = 0;
+ TreePropertyList staticMethods = 0;
+ TreePropertyList instanceMethods = 0;
+ TreePropertyList instanceMethodsTail = 0;
+ TreePropertyList staticMethodsTail = 0;
+ while (!match(CLOSEBRACE)) {
+ if (match(SEMICOLON)) {
+ next();
+ continue;
+ }
+
+ JSTokenLocation methodLocation(tokenLocation());
+ unsigned methodStart = tokenStart();
+
+ // For backwards compatibility, "static" is a non-reserved keyword in non-strict mode.
+ bool isStaticMethod = match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm->propertyNames->staticKeyword;
+ if (isStaticMethod)
+ next();
+
+ // FIXME: Figure out a way to share more code with parseProperty.
+ const CommonIdentifiers& propertyNames = *m_vm->propertyNames;
+ const Identifier* ident = nullptr;
+ bool isGetter = false;
+ bool isSetter = false;
+ switch (m_token.m_type) {
+ case STRING:
+ ident = m_token.m_data.ident;
+ ASSERT(ident);
+ next();
+ break;
+ case IDENT:
+ ident = m_token.m_data.ident;
+ ASSERT(ident);
+ next();
+ if (match(IDENT) || match(STRING) || match(DOUBLE) || match(INTEGER)) {
+ isGetter = *ident == propertyNames.get;
+ isSetter = *ident == propertyNames.set;
+ }
+ break;
+ case DOUBLE:
+ case INTEGER:
+ ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), m_token.m_data.doubleValue);
+ ASSERT(ident);
+ next();
+ break;
+ default:
+ failDueToUnexpectedToken();
+ }
+
+ TreeProperty property;
+ const bool alwaysStrictInsideClass = true;
+ if (isGetter || isSetter) {
+ property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart,
+ ConstructorKind::None, SuperBinding::Needed);
+ failIfFalse(property, "Cannot parse this method");
+ } else {
+ ParserFunctionInfo<TreeBuilder> methodInfo;
+ bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor;
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
+ failIfTrue(!ident || (declareVariable(ident) & DeclarationResult::InvalidStrictMode), "Cannot declare a method named '", methodInfo.name->impl(), "'");
+ methodInfo.name = isConstructor ? className : ident;
+
+ TreeExpression method = context.createFunctionExpr(methodLocation, methodInfo);
+ if (isConstructor) {
+ semanticFailIfTrue(constructor, "Cannot declare multiple constructors in a single class");
+ constructor = method;
+ continue;
+ }
+
+ // FIXME: Syntax error when super() is called
+ semanticFailIfTrue(isStaticMethod && methodInfo.name && *methodInfo.name == propertyNames.prototype,
+ "Cannot declare a static method named 'prototype'");
+ property = context.createProperty(methodInfo.name, method, PropertyNode::Constant, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed);
+ }
+
+ TreePropertyList& tail = isStaticMethod ? staticMethodsTail : instanceMethodsTail;
+ if (tail)
+ tail = context.createPropertyList(methodLocation, property, tail);
+ else {
+ tail = context.createPropertyList(methodLocation, property);
+ if (isStaticMethod)
+ staticMethods = tail;
+ else
+ instanceMethods = tail;
+ }
+ }
+
+ popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
+ consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
+
+ return context.createClassExpr(location, *className, constructor, parentClass, instanceMethods, staticMethods);
+}
+#endif
+
+struct LabelInfo {
+ LabelInfo(const Identifier* ident, const JSTextPosition& start, const JSTextPosition& end)
+ : m_ident(ident)
+ , m_start(start)
+ , m_end(end)
+ {
+ }
+
+ const Identifier* m_ident;
+ JSTextPosition m_start;
+ JSTextPosition m_end;
+};
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrLabelStatement(TreeBuilder& context)
+{
+
+ /* Expression and Label statements are ambiguous at LL(1), so we have a
+ * special case that looks for a colon as the next character in the input.
+ */
+ Vector<LabelInfo> labels;
+ JSTokenLocation location;
+ do {
+ JSTextPosition start = tokenStartPosition();
+ location = tokenLocation();
+ if (!nextTokenIsColon()) {
+ // If we hit this path we're making a expression statement, which
+ // by definition can't make use of continue/break so we can just
+ // ignore any labels we might have accumulated.
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression, "Cannot parse expression statement");
+ if (!autoSemiColon())
+ failDueToUnexpectedToken();
+ return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line);
+ }
+ const Identifier* ident = m_token.m_data.ident;
+ JSTextPosition end = tokenEndPosition();
+ next();
+ consumeOrFail(COLON, "Labels must be followed by a ':'");
+ if (!m_syntaxAlreadyValidated) {
+ // This is O(N^2) over the current list of consecutive labels, but I
+ // have never seen more than one label in a row in the real world.
+ for (size_t i = 0; i < labels.size(); i++)
+ failIfTrue(ident->impl() == labels[i].m_ident->impl(), "Attempted to redeclare the label '", ident->impl(), "'");
+ failIfTrue(getLabel(ident), "Cannot find scope for the label '", ident->impl(), "'");
+ labels.append(LabelInfo(ident, start, end));
+ }
+ } while (match(IDENT) || isLETMaskedAsIDENT());
+ bool isLoop = false;
+ switch (m_token.m_type) {
+ case FOR:
+ case WHILE:
+ case DO:
+ isLoop = true;
+ break;
+
+ default:
+ break;
+ }
+ const Identifier* unused = 0;
+ ScopeRef labelScope = currentScope();
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ pushLabel(labels[i].m_ident, isLoop);
+ }
+ TreeStatement statement = parseStatement(context, unused);
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ popLabel(labelScope);
+ }
+ failIfFalse(statement, "Cannot parse statement");
+ for (size_t i = 0; i < labels.size(); i++) {
+ const LabelInfo& info = labels[labels.size() - i - 1];
+ statement = context.createLabelStatement(location, info.m_ident, statement, info.m_start, info.m_end);
+ }
+ return statement;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionStatement(TreeBuilder& context)
+{
+ switch (m_token.m_type) {
+ // Consult: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-expression-statement
+ // The ES6 spec mandates that we should fail from FUNCTION token here. We handle this case
+ // in parseStatement() which is the only caller of parseExpressionStatement().
+ // We actually allow FUNCTION in situations where it should not be allowed unless we're in strict mode.
+ case CLASSTOKEN:
+ failWithMessage("'class' declaration is not directly within a block statement");
+ break;
+ default:
+ // FIXME: when implementing 'let' we should fail when we see the token sequence "let [".
+ // https://bugs.webkit.org/show_bug.cgi?id=142944
+ break;
+ }
+ JSTextPosition start = tokenStartPosition();
+ JSTokenLocation location(tokenLocation());
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression, "Cannot parse expression statement");
+ failIfFalse(autoSemiColon(), "Parse error");
+ return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseIfStatement(TreeBuilder& context)
+{
+ ASSERT(match(IF));
+ JSTokenLocation ifLocation(tokenLocation());
+ int start = tokenLine();
+ next();
+ handleProductionOrFail(OPENPAREN, "(", "start", "'if' condition");
+
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition, "Expected a expression as the condition for an if statement");
+ int end = tokenLine();
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "'if' condition");
+
+ const Identifier* unused = 0;
+ TreeStatement trueBlock = parseStatement(context, unused);
+ failIfFalse(trueBlock, "Expected a statement as the body of an if block");
+
+ if (!match(ELSE))
+ return context.createIfStatement(ifLocation, condition, trueBlock, 0, start, end);
+
+ Vector<TreeExpression> exprStack;
+ Vector<std::pair<int, int>> posStack;
+ Vector<JSTokenLocation> tokenLocationStack;
+ Vector<TreeStatement> statementStack;
+ bool trailingElse = false;
+ do {
+ JSTokenLocation tempLocation = tokenLocation();
+ next();
+ if (!match(IF)) {
+ const Identifier* unused = 0;
+ TreeStatement block = parseStatement(context, unused);
+ failIfFalse(block, "Expected a statement as the body of an else block");
+ statementStack.append(block);
+ trailingElse = true;
+ break;
+ }
+ int innerStart = tokenLine();
+ next();
+
+ handleProductionOrFail(OPENPAREN, "(", "start", "'if' condition");
+
+ TreeExpression innerCondition = parseExpression(context);
+ failIfFalse(innerCondition, "Expected a expression as the condition for an if statement");
+ int innerEnd = tokenLine();
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "'if' condition");
+ const Identifier* unused = 0;
+ TreeStatement innerTrueBlock = parseStatement(context, unused);
+ failIfFalse(innerTrueBlock, "Expected a statement as the body of an if block");
+ tokenLocationStack.append(tempLocation);
+ exprStack.append(innerCondition);
+ posStack.append(std::make_pair(innerStart, innerEnd));
+ statementStack.append(innerTrueBlock);
+ } while (match(ELSE));
+
+ if (!trailingElse) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ std::pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ JSTokenLocation elseLocation = tokenLocationStack.last();
+ tokenLocationStack.removeLast();
+ TreeStatement ifStatement = context.createIfStatement(elseLocation, condition, trueBlock, 0, pos.first, pos.second);
+ context.setEndOffset(ifStatement, context.endOffset(trueBlock));
+ statementStack.append(ifStatement);
+ }
+
+ while (!exprStack.isEmpty()) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement falseBlock = statementStack.last();
+ statementStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ std::pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ JSTokenLocation elseLocation = tokenLocationStack.last();
+ tokenLocationStack.removeLast();
+ TreeStatement ifStatement = context.createIfStatement(elseLocation, condition, trueBlock, falseBlock, pos.first, pos.second);
+ context.setEndOffset(ifStatement, context.endOffset(falseBlock));
+ statementStack.append(ifStatement);
+ }
+
+ return context.createIfStatement(ifLocation, condition, trueBlock, statementStack.last(), start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::ModuleName Parser<LexerType>::parseModuleName(TreeBuilder& context)
+{
+ // ModuleName (ModuleSpecifier in the spec) represents the module name imported by the script.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
+ JSTokenLocation specifierLocation(tokenLocation());
+ failIfFalse(match(STRING), "Imported modules names must be string literals");
+ const Identifier* moduleName = m_token.m_data.ident;
+ next();
+ return context.createModuleName(specifierLocation, *moduleName);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerType>::parseImportClauseItem(TreeBuilder& context, ImportSpecifierType specifierType)
+{
+ // Produced node is the item of the ImportClause.
+ // That is the ImportSpecifier, ImportedDefaultBinding or NameSpaceImport.
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
+ JSTokenLocation specifierLocation(tokenLocation());
+ JSToken localNameToken;
+ const Identifier* importedName = nullptr;
+ const Identifier* localName = nullptr;
+
+ switch (specifierType) {
+ case ImportSpecifierType::NamespaceImport: {
+ // NameSpaceImport :
+ // * as ImportedBinding
+ // e.g.
+ // * as namespace
+ ASSERT(match(TIMES));
+ importedName = &m_vm->propertyNames->timesIdentifier;
+ next();
+
+ failIfFalse(matchContextualKeyword(m_vm->propertyNames->as), "Expected 'as' before imported binding name");
+ next();
+
+ matchOrFail(IDENT, "Expected a variable name for the import declaration");
+ localNameToken = m_token;
+ localName = m_token.m_data.ident;
+ next();
+ break;
+ }
+
+ case ImportSpecifierType::NamedImport: {
+ // ImportSpecifier :
+ // ImportedBinding
+ // IdentifierName as ImportedBinding
+ // e.g.
+ // A
+ // A as B
+ ASSERT(matchIdentifierOrKeyword());
+ localNameToken = m_token;
+ localName = m_token.m_data.ident;
+ importedName = localName;
+ next();
+
+ if (matchContextualKeyword(m_vm->propertyNames->as)) {
+ next();
+ matchOrFail(IDENT, "Expected a variable name for the import declaration");
+ localNameToken = m_token;
+ localName = m_token.m_data.ident;
+ next();
+ }
+ break;
+ }
+
+ case ImportSpecifierType::DefaultImport: {
+ // ImportedDefaultBinding :
+ // ImportedBinding
+ ASSERT(match(IDENT));
+ localNameToken = m_token;
+ localName = m_token.m_data.ident;
+ importedName = &m_vm->propertyNames->defaultKeyword;
+ next();
+ break;
+ }
+ }
+
+ semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
+ DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, DeclarationImportType::Imported);
+ if (declarationResult != DeclarationResult::Valid) {
+ failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an imported binding named ", localName->impl(), " in strict mode");
+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
+ internalFailWithMessage(false, "Cannot declare an imported binding name twice: '", localName->impl(), "'");
+ }
+
+ return context.createImportSpecifier(specifierLocation, *importedName, *localName);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseImportDeclaration(TreeBuilder& context)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-imports
+ ASSERT(match(IMPORT));
+ JSTokenLocation importLocation(tokenLocation());
+ next();
+
+ auto specifierList = context.createImportSpecifierList();
+
+ if (match(STRING)) {
+ // import ModuleSpecifier ;
+ auto moduleName = parseModuleName(context);
+ failIfFalse(moduleName, "Cannot parse the module name");
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted import declaration");
+ return context.createImportDeclaration(importLocation, specifierList, moduleName);
+ }
+
+ bool isFinishedParsingImport = false;
+ if (match(IDENT)) {
+ // ImportedDefaultBinding :
+ // ImportedBinding
+ auto specifier = parseImportClauseItem(context, ImportSpecifierType::DefaultImport);
+ failIfFalse(specifier, "Cannot parse the default import");
+ context.appendImportSpecifier(specifierList, specifier);
+ if (match(COMMA))
+ next();
+ else
+ isFinishedParsingImport = true;
+ }
+
+ if (!isFinishedParsingImport) {
+ if (match(TIMES)) {
+ // import NameSpaceImport FromClause ;
+ auto specifier = parseImportClauseItem(context, ImportSpecifierType::NamespaceImport);
+ failIfFalse(specifier, "Cannot parse the namespace import");
+ context.appendImportSpecifier(specifierList, specifier);
+ } else if (match(OPENBRACE)) {
+ // NamedImports :
+ // { }
+ // { ImportsList }
+ // { ImportsList , }
+ next();
+
+ while (!match(CLOSEBRACE)) {
+ failIfFalse(matchIdentifierOrKeyword(), "Expected an imported name for the import declaration");
+ auto specifier = parseImportClauseItem(context, ImportSpecifierType::NamedImport);
+ failIfFalse(specifier, "Cannot parse the named import");
+ context.appendImportSpecifier(specifierList, specifier);
+ if (!consume(COMMA))
+ break;
+ }
+ handleProductionOrFail(CLOSEBRACE, "}", "end", "import list");
+ } else
+ failWithMessage("Expected namespace import or import list");
+ }
+
+ // FromClause :
+ // from ModuleSpecifier
+
+ failIfFalse(matchContextualKeyword(m_vm->propertyNames->from), "Expected 'from' before imported module name");
+ next();
+
+ auto moduleName = parseModuleName(context);
+ failIfFalse(moduleName, "Cannot parse the module name");
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted import declaration");
+
+ return context.createImportDeclaration(importLocation, specifierList, moduleName);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::ExportSpecifier Parser<LexerType>::parseExportSpecifier(TreeBuilder& context, Vector<const Identifier*>& maybeLocalNames, bool& hasKeywordForLocalBindings)
+{
+ // ExportSpecifier :
+ // IdentifierName
+ // IdentifierName as IdentifierName
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
+ ASSERT(matchIdentifierOrKeyword());
+ JSTokenLocation specifierLocation(tokenLocation());
+ if (m_token.m_type & KeywordTokenFlag)
+ hasKeywordForLocalBindings = true;
+ const Identifier* localName = m_token.m_data.ident;
+ const Identifier* exportedName = localName;
+ next();
+
+ if (matchContextualKeyword(m_vm->propertyNames->as)) {
+ next();
+ failIfFalse(matchIdentifierOrKeyword(), "Expected an exported name for the export declaration");
+ exportedName = m_token.m_data.ident;
+ next();
+ }
+
+ semanticFailIfFalse(exportName(*exportedName), "Cannot export a duplicate name '", exportedName->impl(), "'");
+ maybeLocalNames.append(localName);
+ return context.createExportSpecifier(specifierLocation, *localName, *exportedName);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclaration(TreeBuilder& context)
+{
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-exports
+ ASSERT(match(EXPORT));
+ JSTokenLocation exportLocation(tokenLocation());
+ next();
+
+ switch (m_token.m_type) {
+ case TIMES: {
+ // export * FromClause ;
+ next();
+
+ failIfFalse(matchContextualKeyword(m_vm->propertyNames->from), "Expected 'from' before exported module name");
+ next();
+ auto moduleName = parseModuleName(context);
+ failIfFalse(moduleName, "Cannot parse the 'from' clause");
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
+
+ return context.createExportAllDeclaration(exportLocation, moduleName);
+ }
+
+ case DEFAULT: {
+ // export default HoistableDeclaration[Default]
+ // export default ClassDeclaration[Default]
+ // export default [lookahead not-in {function, class}] AssignmentExpression[In] ;
+
+ next();
+
+ TreeStatement result = 0;
+ bool isFunctionOrClassDeclaration = false;
+ const Identifier* localName = nullptr;
+ SavePoint savePoint = createSavePoint();
+ if (match(FUNCTION)
+#if ENABLE(ES6_CLASS_SYNTAX)
+ || match(CLASSTOKEN)
+#endif
+ ) {
+ isFunctionOrClassDeclaration = true;
+ next();
+ // FIXME: When landing ES6 generators, we need to take care of that '*' comes.
+ if (match(IDENT))
+ localName = m_token.m_data.ident;
+ restoreSavePoint(savePoint);
+ }
+
+ if (localName) {
+ if (match(FUNCTION))
+ result = parseFunctionDeclaration(context);
+#if ENABLE(ES6_CLASS_SYNTAX)
+ else {
+ ASSERT(match(CLASSTOKEN));
+ result = parseClassDeclaration(context);
+ }
+#endif
+ } else {
+ // export default expr;
+ //
+ // It should be treated as the same to the following.
+ //
+ // const *default* = expr;
+ // export { *default* as default }
+ //
+ // In the above example, *default* is the invisible variable to the users.
+ // We use the private symbol to represent the name of this variable.
+ JSTokenLocation location(tokenLocation());
+ JSTextPosition start = tokenStartPosition();
+ TreeExpression expression = parseAssignmentExpression(context);
+ failIfFalse(expression, "Cannot parse expression");
+
+ DeclarationResultMask declarationResult = declareVariable(&m_vm->propertyNames->starDefaultPrivateName, DeclarationType::ConstDeclaration);
+ if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
+ internalFailWithMessage(false, "Only one 'default' export is allowed");
+
+ TreeExpression assignment = context.createAssignResolve(location, m_vm->propertyNames->starDefaultPrivateName, expression, start, start, tokenEndPosition(), AssignmentContext::ConstDeclarationStatement);
+ result = context.createExprStatement(location, assignment, start, tokenEndPosition());
+ if (!isFunctionOrClassDeclaration)
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
+ localName = &m_vm->propertyNames->starDefaultPrivateName;
+ }
+ failIfFalse(result, "Cannot parse the declaration");
+
+ semanticFailIfFalse(exportName(m_vm->propertyNames->defaultKeyword), "Only one 'default' export is allowed");
+ currentScope()->moduleScopeData().exportBinding(*localName);
+ return context.createExportDefaultDeclaration(exportLocation, result, *localName);
+ }
+
+ case OPENBRACE: {
+ // export ExportClause FromClause ;
+ // export ExportClause ;
+ //
+ // ExportClause :
+ // { }
+ // { ExportsList }
+ // { ExportsList , }
+ //
+ // ExportsList :
+ // ExportSpecifier
+ // ExportsList , ExportSpecifier
+
+ next();
+
+ auto specifierList = context.createExportSpecifierList();
+ Vector<const Identifier*> maybeLocalNames;
+
+ bool hasKeywordForLocalBindings = false;
+ while (!match(CLOSEBRACE)) {
+ failIfFalse(matchIdentifierOrKeyword(), "Expected a variable name for the export declaration");
+ auto specifier = parseExportSpecifier(context, maybeLocalNames, hasKeywordForLocalBindings);
+ failIfFalse(specifier, "Cannot parse the named export");
+ context.appendExportSpecifier(specifierList, specifier);
+ if (!consume(COMMA))
+ break;
+ }
+ handleProductionOrFail(CLOSEBRACE, "}", "end", "export list");
+
+ typename TreeBuilder::ModuleName moduleName = 0;
+ if (matchContextualKeyword(m_vm->propertyNames->from)) {
+ next();
+ moduleName = parseModuleName(context);
+ failIfFalse(moduleName, "Cannot parse the 'from' clause");
+ }
+ failIfFalse(autoSemiColon(), "Expected a ';' following a targeted export declaration");
+
+ if (!moduleName) {
+ semanticFailIfTrue(hasKeywordForLocalBindings, "Cannot use keyword as exported variable name");
+ // Since this export declaration does not have module specifier part, it exports the local bindings.
+ // While the export declaration with module specifier does not have any effect on the current module's scope,
+ // the export named declaration without module specifier references the the local binding names.
+ // For example,
+ // export { A, B, C as D } from "mod"
+ // does not have effect on the current module's scope. But,
+ // export { A, B, C as D }
+ // will reference the current module's bindings.
+ for (const Identifier* localName : maybeLocalNames) {
+ currentScope()->useVariable(localName, m_vm->propertyNames->eval == *localName);
+ currentScope()->moduleScopeData().exportBinding(*localName);
+ }
+ }
+
+ return context.createExportNamedDeclaration(exportLocation, specifierList, moduleName);
+ }
+
+ default: {
+ // export VariableStatement
+ // export Declaration
+ TreeStatement result = 0;
+ switch (m_token.m_type) {
+ case VAR:
+ result = parseVariableDeclaration(context, DeclarationType::VarDeclaration, ExportType::Exported);
+ break;
+
+ case CONSTTOKEN:
+ result = parseVariableDeclaration(context, DeclarationType::ConstDeclaration, ExportType::Exported);
+ break;
+
+ case LET:
+ result = parseVariableDeclaration(context, DeclarationType::LetDeclaration, ExportType::Exported);
+ break;
+
+ case FUNCTION:
+ result = parseFunctionDeclaration(context, ExportType::Exported);
+ break;
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ case CLASSTOKEN:
+ result = parseClassDeclaration(context, ExportType::Exported);
+ break;
+#endif
+
+ default:
+ failWithMessage("Expected either a declaration or a variable statement");
+ break;
+ }
+ failIfFalse(result, "Cannot parse the declaration");
+ return context.createExportLocalDeclaration(exportLocation, result);
+ }
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return 0;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ JSTokenLocation location(tokenLocation());
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node, "Cannot parse expression");
+ context.setEndOffset(node, m_lastTokenEndPosition.offset);
+ if (!match(COMMA))
+ return node;
+ next();
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ TreeExpression right = parseAssignmentExpression(context);
+ failIfFalse(right, "Cannot parse expression in a comma expression");
+ context.setEndOffset(right, m_lastTokenEndPosition.offset);
+ typename TreeBuilder::Comma head = context.createCommaExpr(location, node);
+ typename TreeBuilder::Comma tail = context.appendToCommaExpr(location, head, head, right);
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ right = parseAssignmentExpression(context);
+ failIfFalse(right, "Cannot parse expression in a comma expression");
+ context.setEndOffset(right, m_lastTokenEndPosition.offset);
+ tail = context.appendToCommaExpr(location, head, tail, right);
+ }
+ context.setEndOffset(head, m_lastTokenEndPosition.offset);
+ return head;
+}
+
+
+template <typename LexerType>
+template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmentExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ JSTextPosition start = tokenStartPosition();
+ JSTokenLocation location(tokenLocation());
+ int initialAssignmentCount = m_assignmentCount;
+ int initialNonLHSCount = m_nonLHSCount;
+ if (match(OPENBRACE) || match(OPENBRACKET)) {
+ SavePoint savePoint = createSavePoint();
+ auto pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::AssignmentExpression);
+ if (pattern && consume(EQUAL)) {
+ auto rhs = parseAssignmentExpression(context);
+ if (rhs)
+ return context.createDestructuringAssignment(location, pattern, rhs);
+ }
+ restoreSavePoint(savePoint);
+ }
+
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ if (isArrowFunctionParamters())
+ return parseArrowFunctionExpression(context);
+#endif
+
+ TreeExpression lhs = parseConditionalExpression(context);
+ failIfFalse(lhs, "Cannot parse expression");
+ if (initialNonLHSCount != m_nonLHSCount) {
+ if (m_token.m_type >= EQUAL && m_token.m_type <= OREQUAL)
+ semanticFail("Left hand side of operator '", getToken(), "' must be a reference");
+
+ return lhs;
+ }
+
+ int assignmentStack = 0;
+ Operator op;
+ bool hadAssignment = false;
+ while (true) {
+ switch (m_token.m_type) {
+ case EQUAL: op = OpEqual; break;
+ case PLUSEQUAL: op = OpPlusEq; break;
+ case MINUSEQUAL: op = OpMinusEq; break;
+ case MULTEQUAL: op = OpMultEq; break;
+ case DIVEQUAL: op = OpDivEq; break;
+ case LSHIFTEQUAL: op = OpLShift; break;
+ case RSHIFTEQUAL: op = OpRShift; break;
+ case URSHIFTEQUAL: op = OpURShift; break;
+ case ANDEQUAL: op = OpAndEq; break;
+ case XOREQUAL: op = OpXOrEq; break;
+ case OREQUAL: op = OpOrEq; break;
+ case MODEQUAL: op = OpModEq; break;
+ default:
+ goto end;
+ }
+ m_nonTrivialExpressionCount++;
+ hadAssignment = true;
+ context.assignmentStackAppend(assignmentStack, lhs, start, tokenStartPosition(), m_assignmentCount, op);
+ start = tokenStartPosition();
+ m_assignmentCount++;
+ next(TreeBuilder::DontBuildStrings);
+ if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+ failIfTrueIfStrict(m_vm->propertyNames->eval == *m_lastIdentifier, "Cannot modify 'eval' in strict mode");
+ failIfTrueIfStrict(m_vm->propertyNames->arguments == *m_lastIdentifier, "Cannot modify 'arguments' in strict mode");
+ declareWrite(m_lastIdentifier);
+ m_lastIdentifier = 0;
+ }
+ lhs = parseAssignmentExpression(context);
+ failIfFalse(lhs, "Cannot parse the right hand side of an assignment expression");
+ if (initialNonLHSCount != m_nonLHSCount) {
+ if (m_token.m_type >= EQUAL && m_token.m_type <= OREQUAL)
+ semanticFail("Left hand side of operator '", getToken(), "' must be a reference");
+ break;
+ }
+ }
+end:
+ if (hadAssignment)
+ m_nonLHSCount++;
+
+ if (!TreeBuilder::CreatesAST)
+ return lhs;
+
+ while (assignmentStack)
+ lhs = context.createAssignment(location, assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEndPosition());
+
+ return lhs;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context)
+{
+ JSTokenLocation location(tokenLocation());
+ TreeExpression cond = parseBinaryExpression(context);
+ failIfFalse(cond, "Cannot parse expression");
+ if (!match(QUESTION))
+ return cond;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression lhs = parseAssignmentExpression(context);
+ failIfFalse(lhs, "Cannot parse left hand side of ternary operator");
+ context.setEndOffset(lhs, m_lastTokenEndPosition.offset);
+ consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings, "Expected ':' in ternary operator");
+
+ TreeExpression rhs = parseAssignmentExpression(context);
+ failIfFalse(rhs, "Cannot parse right hand side of ternary operator");
+ context.setEndOffset(rhs, m_lastTokenEndPosition.offset);
+ return context.createConditionalExpr(location, cond, lhs, rhs);
+}
+
+ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
+{
+ return token & UnaryOpTokenFlag;
+}
+
+template <typename LexerType>
+int Parser<LexerType>::isBinaryOperator(JSTokenType token)
+{
+ if (m_allowsIn)
+ return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
+ return token & BinaryOpTokenPrecedenceMask;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseBinaryExpression(TreeBuilder& context)
+{
+ int operandStackDepth = 0;
+ int operatorStackDepth = 0;
+ typename TreeBuilder::BinaryExprContext binaryExprContext(context);
+ JSTokenLocation location(tokenLocation());
+ while (true) {
+ JSTextPosition exprStart = tokenStartPosition();
+ int initialAssignments = m_assignmentCount;
+ TreeExpression current = parseUnaryExpression(context);
+ failIfFalse(current, "Cannot parse expression");
+
+ context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEndPosition(), lastTokenEndPosition(), initialAssignments != m_assignmentCount);
+ int precedence = isBinaryOperator(m_token.m_type);
+ if (!precedence)
+ break;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ int operatorToken = m_token.m_type;
+ next(TreeBuilder::DontBuildStrings);
+
+ while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
+ }
+ while (operatorStackDepth) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ return context.popOperandStack(operandStackDepth);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeBuilder& context, bool complete)
+{
+ bool wasIdent = false;
+ switch (m_token.m_type) {
+ namedProperty:
+ case IDENT:
+ wasIdent = true;
+ FALLTHROUGH;
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ unsigned getterOrSetterStartOffset = tokenStart();
+ if (complete || (wasIdent && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set)))
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords);
+ else
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+
+ if (match(COLON)) {
+ next();
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node, "Cannot parse expression for property declaration");
+ context.setEndOffset(node, m_lexer->currentOffset());
+ return context.createProperty(ident, node, PropertyNode::Constant, PropertyNode::Unknown, complete);
+ }
+
+ if (match(OPENPAREN)) {
+ auto method = parsePropertyMethod(context, ident);
+ propagateError();
+ return context.createProperty(ident, method, PropertyNode::Constant, PropertyNode::KnownDirect, complete);
+ }
+
+ failIfFalse(wasIdent, "Expected an identifier as property name");
+
+ if (match(COMMA) || match(CLOSEBRACE)) {
+ JSTextPosition start = tokenStartPosition();
+ JSTokenLocation location(tokenLocation());
+ currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
+ TreeExpression node = context.createResolve(location, ident, start);
+ return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete);
+ }
+
+ PropertyNode::Type type;
+ if (*ident == m_vm->propertyNames->get)
+ type = PropertyNode::Getter;
+ else if (*ident == m_vm->propertyNames->set)
+ type = PropertyNode::Setter;
+ else
+ failWithMessage("Expected a ':' following the property name '", ident->impl(), "'");
+ return parseGetterSetter(context, complete, type, getterOrSetterStartOffset);
+ }
+ case DOUBLE:
+ case INTEGER: {
+ double propertyName = m_token.m_data.doubleValue;
+ next();
+
+ if (match(OPENPAREN)) {
+ const Identifier& ident = m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), propertyName);
+ auto method = parsePropertyMethod(context, &ident);
+ propagateError();
+ return context.createProperty(&ident, method, PropertyNode::Constant, PropertyNode::Unknown, complete);
+ }
+
+ consumeOrFail(COLON, "Expected ':' after property name");
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node, "Cannot parse expression for property declaration");
+ context.setEndOffset(node, m_lexer->currentOffset());
+ return context.createProperty(const_cast<VM*>(m_vm), m_parserArena, propertyName, node, PropertyNode::Constant, PropertyNode::Unknown, complete);
+ }
+ case OPENBRACKET: {
+ next();
+ auto propertyName = parseAssignmentExpression(context);
+ failIfFalse(propertyName, "Cannot parse computed property name");
+ handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
+
+ if (match(OPENPAREN)) {
+ auto method = parsePropertyMethod(context, &m_vm->propertyNames->nullIdentifier);
+ propagateError();
+ return context.createProperty(propertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::KnownDirect, complete);
+ }
+
+ consumeOrFail(COLON, "Expected ':' after property name");
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node, "Cannot parse expression for property declaration");
+ context.setEndOffset(node, m_lexer->currentOffset());
+ return context.createProperty(propertyName, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::Unknown, complete);
+ }
+ default:
+ failIfFalse(m_token.m_type & KeywordTokenFlag, "Expected a property name");
+ goto namedProperty;
+ }
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMethod(TreeBuilder& context, const Identifier* methodName)
+{
+ JSTokenLocation methodLocation(tokenLocation());
+ unsigned methodStart = tokenStart();
+ ParserFunctionInfo<TreeBuilder> methodInfo;
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::MethodMode, false, ConstructorKind::None, SuperBinding::NotNeeded, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method");
+ methodInfo.name = methodName;
+ return context.createFunctionExpr(methodLocation, methodInfo);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(TreeBuilder& context, bool strict, PropertyNode::Type type, unsigned getterOrSetterStartOffset,
+ ConstructorKind constructorKind, SuperBinding superBinding)
+{
+ const Identifier* stringPropertyName = 0;
+ double numericPropertyName = 0;
+ if (m_token.m_type == IDENT || m_token.m_type == STRING || isLETMaskedAsIDENT()) {
+ stringPropertyName = m_token.m_data.ident;
+ semanticFailIfTrue(superBinding == SuperBinding::Needed && *stringPropertyName == m_vm->propertyNames->prototype,
+ "Cannot declare a static method named 'prototype'");
+ semanticFailIfTrue(superBinding == SuperBinding::Needed && *stringPropertyName == m_vm->propertyNames->constructor,
+ "Cannot declare a getter or setter named 'constructor'");
+ } else if (m_token.m_type == DOUBLE || m_token.m_type == INTEGER)
+ numericPropertyName = m_token.m_data.doubleValue;
+ else
+ failDueToUnexpectedToken();
+ JSTokenLocation location(tokenLocation());
+ next();
+ ParserFunctionInfo<TreeBuilder> info;
+ if (type & PropertyNode::Getter) {
+ failIfFalse(match(OPENPAREN), "Expected a parameter list for getter definition");
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::GetterMode, false, constructorKind, superBinding,
+ getterOrSetterStartOffset, info, StandardFunctionParseType)), "Cannot parse getter definition");
+ } else {
+ failIfFalse(match(OPENPAREN), "Expected a parameter list for setter definition");
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::SetterMode, false, constructorKind, superBinding,
+ getterOrSetterStartOffset, info, StandardFunctionParseType)), "Cannot parse setter definition");
+ }
+ if (stringPropertyName)
+ return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, superBinding);
+ return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, superBinding);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> bool Parser<LexerType>::shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder& context, const TreeProperty& property)
+{
+ if (m_syntaxAlreadyValidated)
+ return false;
+
+ if (!context.getName(property))
+ return false;
+
+ // A Constant property that is not a Computed or Shorthand Constant property.
+ return context.getType(property) == PropertyNode::Constant;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseObjectLiteral(TreeBuilder& context)
+{
+ auto savePoint = createSavePoint();
+ consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings, "Expected opening '{' at the start of an object literal");
+
+ int oldNonLHSCount = m_nonLHSCount;
+
+ JSTokenLocation location(tokenLocation());
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral(location);
+ }
+
+ TreeProperty property = parseProperty(context, false);
+ failIfFalse(property, "Cannot parse object literal property");
+
+ if (!m_syntaxAlreadyValidated && context.getType(property) & (PropertyNode::Getter | PropertyNode::Setter)) {
+ restoreSavePoint(savePoint);
+ return parseStrictObjectLiteral(context);
+ }
+
+ bool seenUnderscoreProto = false;
+ if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property))
+ seenUnderscoreProto = *context.getName(property) == m_vm->propertyNames->underscoreProto;
+
+ TreePropertyList propertyList = context.createPropertyList(location, property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ if (match(CLOSEBRACE))
+ break;
+ JSTokenLocation propertyLocation(tokenLocation());
+ property = parseProperty(context, false);
+ failIfFalse(property, "Cannot parse object literal property");
+ if (!m_syntaxAlreadyValidated && context.getType(property) & (PropertyNode::Getter | PropertyNode::Setter)) {
+ restoreSavePoint(savePoint);
+ return parseStrictObjectLiteral(context);
+ }
+ if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) {
+ if (*context.getName(property) == m_vm->propertyNames->underscoreProto) {
+ semanticFailIfTrue(seenUnderscoreProto, "Attempted to redefine __proto__ property");
+ seenUnderscoreProto = true;
+ }
+ }
+ tail = context.createPropertyList(propertyLocation, property, tail);
+ }
+
+ location = tokenLocation();
+ handleProductionOrFail(CLOSEBRACE, "}", "end", "object literal");
+
+ m_nonLHSCount = oldNonLHSCount;
+
+ return context.createObjectLiteral(location, propertyList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseStrictObjectLiteral(TreeBuilder& context)
+{
+ consumeOrFail(OPENBRACE, "Expected opening '{' at the start of an object literal");
+
+ int oldNonLHSCount = m_nonLHSCount;
+
+ JSTokenLocation location(tokenLocation());
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral(location);
+ }
+
+ TreeProperty property = parseProperty(context, true);
+ failIfFalse(property, "Cannot parse object literal property");
+
+ bool seenUnderscoreProto = false;
+ if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property))
+ seenUnderscoreProto = *context.getName(property) == m_vm->propertyNames->underscoreProto;
+
+ TreePropertyList propertyList = context.createPropertyList(location, property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next();
+ if (match(CLOSEBRACE))
+ break;
+ JSTokenLocation propertyLocation(tokenLocation());
+ property = parseProperty(context, true);
+ failIfFalse(property, "Cannot parse object literal property");
+ if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) {
+ if (*context.getName(property) == m_vm->propertyNames->underscoreProto) {
+ semanticFailIfTrue(seenUnderscoreProto, "Attempted to redefine __proto__ property");
+ seenUnderscoreProto = true;
+ }
+ }
+ tail = context.createPropertyList(propertyLocation, property, tail);
+ }
+
+ location = tokenLocation();
+ handleProductionOrFail(CLOSEBRACE, "}", "end", "object literal");
+
+ m_nonLHSCount = oldNonLHSCount;
+
+ return context.createObjectLiteral(location, propertyList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrayLiteral(TreeBuilder& context)
+{
+ consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings, "Expected an opening '[' at the beginning of an array literal");
+
+ int oldNonLHSCount = m_nonLHSCount;
+
+ int elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions++;
+ }
+ if (match(CLOSEBRACKET)) {
+ JSTokenLocation location(tokenLocation());
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(location, elisions);
+ }
+
+ TreeExpression elem;
+ if (UNLIKELY(match(DOTDOTDOT))) {
+ auto spreadLocation = m_token.m_location;
+ auto start = m_token.m_startPosition;
+ auto divot = m_token.m_endPosition;
+ next();
+ auto spreadExpr = parseAssignmentExpression(context);
+ failIfFalse(spreadExpr, "Cannot parse subject of a spread operation");
+ elem = context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, m_lastTokenEndPosition);
+ } else
+ elem = parseAssignmentExpression(context);
+ failIfFalse(elem, "Cannot parse array literal element");
+ typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
+ typename TreeBuilder::ElementList tail = elementList;
+ elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions = 0;
+
+ while (match(COMMA)) {
+ next();
+ elisions++;
+ }
+
+ if (match(CLOSEBRACKET)) {
+ JSTokenLocation location(tokenLocation());
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(location, elisions, elementList);
+ }
+ if (UNLIKELY(match(DOTDOTDOT))) {
+ auto spreadLocation = m_token.m_location;
+ auto start = m_token.m_startPosition;
+ auto divot = m_token.m_endPosition;
+ next();
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem, "Cannot parse subject of a spread operation");
+ auto spread = context.createSpreadExpression(spreadLocation, elem, start, divot, m_lastTokenEndPosition);
+ tail = context.createElementList(tail, elisions, spread);
+ continue;
+ }
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem, "Cannot parse array literal element");
+ tail = context.createElementList(tail, elisions, elem);
+ }
+
+ JSTokenLocation location(tokenLocation());
+ if (!consume(CLOSEBRACKET)) {
+ failIfFalse(match(DOTDOTDOT), "Expected either a closing ']' or a ',' following an array element");
+ semanticFail("The '...' operator should come before a target expression");
+ }
+
+ m_nonLHSCount = oldNonLHSCount;
+
+ return context.createArray(location, elementList);
+}
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail)
+{
+ if (!isTemplateHead) {
+ matchOrFail(CLOSEBRACE, "Expected a closing '}' following an expression in template literal");
+ // Re-scan the token to recognize it as Template Element.
+ m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token, rawStringsBuildMode);
+ }
+ matchOrFail(TEMPLATE, "Expected an template element");
+ const Identifier* cooked = m_token.m_data.cooked;
+ const Identifier* raw = m_token.m_data.raw;
+ elementIsTail = m_token.m_data.isTail;
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createTemplateString(location, *cooked, *raw);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context, typename LexerType::RawStringsBuildMode rawStringsBuildMode)
+{
+ JSTokenLocation location(tokenLocation());
+ bool elementIsTail = false;
+
+ auto headTemplateString = parseTemplateString(context, true, rawStringsBuildMode, elementIsTail);
+ failIfFalse(headTemplateString, "Cannot parse head template element");
+
+ typename TreeBuilder::TemplateStringList templateStringList = context.createTemplateStringList(headTemplateString);
+ typename TreeBuilder::TemplateStringList templateStringTail = templateStringList;
+
+ if (elementIsTail)
+ return context.createTemplateLiteral(location, templateStringList);
+
+ failIfTrue(match(CLOSEBRACE), "Template literal expression cannot be empty");
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression, "Cannot parse expression in template literal");
+
+ typename TreeBuilder::TemplateExpressionList templateExpressionList = context.createTemplateExpressionList(expression);
+ typename TreeBuilder::TemplateExpressionList templateExpressionTail = templateExpressionList;
+
+ auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail);
+ failIfFalse(templateString, "Cannot parse template element");
+ templateStringTail = context.createTemplateStringList(templateStringTail, templateString);
+
+ while (!elementIsTail) {
+ failIfTrue(match(CLOSEBRACE), "Template literal expression cannot be empty");
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression, "Cannot parse expression in template literal");
+
+ templateExpressionTail = context.createTemplateExpressionList(templateExpressionTail, expression);
+
+ auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail);
+ failIfFalse(templateString, "Cannot parse template element");
+ templateStringTail = context.createTemplateStringList(templateStringTail, templateString);
+ }
+
+ return context.createTemplateLiteral(location, templateStringList, templateExpressionList);
+}
+#endif
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ switch (m_token.m_type) {
+ case FUNCTION: {
+ JSTokenLocation location(tokenLocation());
+ unsigned functionKeywordStart = tokenStart();
+ next();
+ ParserFunctionInfo<TreeBuilder> info;
+ info.name = &m_vm->propertyNames->nullIdentifier;
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::NormalFunctionMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, StandardFunctionParseType)), "Cannot parse function expression");
+ return context.createFunctionExpr(location, info);
+ }
+#if ENABLE(ES6_CLASS_SYNTAX)
+ case CLASSTOKEN: {
+ ParserClassInfo<TreeBuilder> info;
+ return parseClass(context, FunctionNoRequirements, info);
+ }
+#endif
+ case OPENBRACE:
+ if (strictMode())
+ return parseStrictObjectLiteral(context);
+ return parseObjectLiteral(context);
+ case OPENBRACKET:
+ return parseArrayLiteral(context);
+ case OPENPAREN: {
+ next();
+ int oldNonLHSCount = m_nonLHSCount;
+ TreeExpression result = parseExpression(context);
+ m_nonLHSCount = oldNonLHSCount;
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "compound expression");
+ return result;
+ }
+ case THISTOKEN: {
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createThisExpr(location, m_thisTDZMode);
+ }
+ case IDENT: {
+ identifierExpression:
+ JSTextPosition start = tokenStartPosition();
+ const Identifier* ident = m_token.m_data.ident;
+ JSTokenLocation location(tokenLocation());
+ next();
+ currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident);
+ m_lastIdentifier = ident;
+ return context.createResolve(location, ident, start);
+ }
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createString(location, ident);
+ }
+ case DOUBLE: {
+ double d = m_token.m_data.doubleValue;
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createDoubleExpr(location, d);
+ }
+ case INTEGER: {
+ double d = m_token.m_data.doubleValue;
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createIntegerExpr(location, d);
+ }
+ case NULLTOKEN: {
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createNull(location);
+ }
+ case TRUETOKEN: {
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createBoolean(location, true);
+ }
+ case FALSETOKEN: {
+ JSTokenLocation location(tokenLocation());
+ next();
+ return context.createBoolean(location, false);
+ }
+ case DIVEQUAL:
+ case DIVIDE: {
+ /* regexp */
+ const Identifier* pattern;
+ const Identifier* flags;
+ if (match(DIVEQUAL))
+ failIfFalse(m_lexer->scanRegExp(pattern, flags, '='), "Invalid regular expression");
+ else
+ failIfFalse(m_lexer->scanRegExp(pattern, flags), "Invalid regular expression");
+
+ JSTextPosition start = tokenStartPosition();
+ JSTokenLocation location(tokenLocation());
+ next();
+ TreeExpression re = context.createRegExp(location, *pattern, *flags, start);
+ if (!re) {
+ const char* yarrErrorMsg = Yarr::checkSyntax(pattern->string());
+ regexFail(yarrErrorMsg);
+ }
+ return re;
+ }
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ case TEMPLATE:
+ return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings);
+#endif
+ case LET:
+ if (!strictMode())
+ goto identifierExpression;
+ FALLTHROUGH;
+ default:
+ failDueToUnexpectedToken();
+ }
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context, SpreadMode mode)
+{
+ consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings, "Expected opening '(' at start of argument list");
+ JSTokenLocation location(tokenLocation());
+ if (match(CLOSEPAREN)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArguments();
+ }
+ if (match(DOTDOTDOT) && mode == AllowSpread) {
+ JSTokenLocation spreadLocation(tokenLocation());
+ auto start = m_token.m_startPosition;
+ auto divot = m_token.m_endPosition;
+ next();
+ auto spreadExpr = parseAssignmentExpression(context);
+ auto end = m_lastTokenEndPosition;
+ if (!spreadExpr)
+ failWithMessage("Cannot parse spread expression");
+ if (!consume(CLOSEPAREN)) {
+ if (match(COMMA))
+ semanticFail("Spread operator may only be applied to the last argument passed to a function");
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list");
+ }
+ auto spread = context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, end);
+ TreeArgumentsList argList = context.createArgumentsList(location, spread);
+ return context.createArguments(argList);
+ }
+ TreeExpression firstArg = parseAssignmentExpression(context);
+ failIfFalse(firstArg, "Cannot parse function argument");
+
+ TreeArgumentsList argList = context.createArgumentsList(location, firstArg);
+ TreeArgumentsList tail = argList;
+ while (match(COMMA)) {
+ JSTokenLocation argumentLocation(tokenLocation());
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression arg = parseAssignmentExpression(context);
+ failIfFalse(arg, "Cannot parse function argument");
+ tail = context.createArgumentsList(argumentLocation, tail, arg);
+ }
+ semanticFailIfTrue(match(DOTDOTDOT), "The '...' operator should come before the target expression");
+ handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list");
+ return context.createArguments(argList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context)
+{
+ TreeExpression base = 0;
+ JSTextPosition expressionStart = tokenStartPosition();
+ int newCount = 0;
+ JSTokenLocation startLocation = tokenLocation();
+ JSTokenLocation location;
+ while (match(NEW)) {
+ next();
+ newCount++;
+ }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ bool baseIsSuper = match(SUPER);
+ semanticFailIfTrue(baseIsSuper && newCount, "Cannot use new with super");
+#else
+ bool baseIsSuper = false;
+#endif
+
+ bool baseIsNewTarget = false;
+ if (newCount && match(DOT)) {
+ next();
+ if (match(IDENT)) {
+ const Identifier* ident = m_token.m_data.ident;
+ if (m_vm->propertyNames->target == *ident) {
+ semanticFailIfFalse(currentScope()->isFunction(), "new.target is only valid inside functions");
+ baseIsNewTarget = true;
+ base = context.createNewTargetExpr(location);
+ newCount--;
+ next();
+ } else
+ failWithMessage("\"new.\" can only followed with target");
+ } else
+ failDueToUnexpectedToken();
+ }
+
+ if (baseIsSuper) {
+ semanticFailIfFalse(currentScope()->isFunction(), "super is only valid inside functions");
+ base = context.createSuperExpr(location);
+ next();
+ currentScope()->setNeedsSuperBinding();
+ } else if (!baseIsNewTarget)
+ base = parsePrimaryExpression(context);
+
+ failIfFalse(base, "Cannot parse base expression");
+ while (true) {
+ location = tokenLocation();
+ switch (m_token.m_type) {
+ case OPENBRACKET: {
+ m_nonTrivialExpressionCount++;
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ next();
+ int nonLHSCount = m_nonLHSCount;
+ int initialAssignments = m_assignmentCount;
+ TreeExpression property = parseExpression(context);
+ failIfFalse(property, "Cannot parse subscript expression");
+ base = context.createBracketAccess(location, base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEndPosition());
+ handleProductionOrFail(CLOSEBRACKET, "]", "end", "subscript expression");
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
+ case OPENPAREN: {
+ m_nonTrivialExpressionCount++;
+ int nonLHSCount = m_nonLHSCount;
+ if (newCount) {
+ newCount--;
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ TreeArguments arguments = parseArguments(context, AllowSpread);
+ failIfFalse(arguments, "Cannot parse call arguments");
+ base = context.createNewExpr(location, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
+ } else {
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ TreeArguments arguments = parseArguments(context, AllowSpread);
+ failIfFalse(arguments, "Cannot parse call arguments");
+ if (baseIsSuper)
+ currentScope()->setHasDirectSuper();
+ base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition());
+ }
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
+ case DOT: {
+ m_nonTrivialExpressionCount++;
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+ matchOrFail(IDENT, "Expected a property name after '.'");
+ base = context.createDotAccess(location, base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEndPosition());
+ next();
+ break;
+ }
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ case TEMPLATE: {
+ semanticFailIfTrue(baseIsSuper, "Cannot use super as tag for tagged templates");
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ int nonLHSCount = m_nonLHSCount;
+ typename TreeBuilder::TemplateLiteral templateLiteral = parseTemplateLiteral(context, LexerType::RawStringsBuildMode::BuildRawStrings);
+ failIfFalse(templateLiteral, "Cannot parse template literal");
+ base = context.createTaggedTemplate(location, base, templateLiteral, expressionStart, expressionEnd, lastTokenEndPosition());
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
+#endif
+ default:
+ goto endMemberExpression;
+ }
+ baseIsSuper = false;
+ }
+endMemberExpression:
+ semanticFailIfTrue(baseIsSuper, "Cannot reference super");
+ while (newCount--)
+ base = context.createNewExpr(location, base, expressionStart, lastTokenEndPosition());
+ return base;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrowFunctionExpression(TreeBuilder& context)
+{
+ JSTokenLocation location;
+
+ unsigned functionKeywordStart = tokenStart();
+ location = tokenLocation();
+ ParserFunctionInfo<TreeBuilder> info;
+ info.name = &m_vm->propertyNames->nullIdentifier;
+ failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SourceParseMode::ArrowFunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, ArrowFunctionParseType)), "Cannot parse arrow function expression");
+
+ return context.createArrowFunctionExpr(location, info);
+}
+
+static const char* operatorString(bool prefix, unsigned tok)
+{
+ switch (tok) {
+ case MINUSMINUS:
+ case AUTOMINUSMINUS:
+ return prefix ? "prefix-decrement" : "decrement";
+
+ case PLUSPLUS:
+ case AUTOPLUSPLUS:
+ return prefix ? "prefix-increment" : "increment";
+
+ case EXCLAMATION:
+ return "logical-not";
+
+ case TILDE:
+ return "bitwise-not";
+
+ case TYPEOF:
+ return "typeof";
+
+ case VOIDTOKEN:
+ return "void";
+
+ case DELETETOKEN:
+ return "delete";
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return "error";
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpression(TreeBuilder& context)
+{
+ typename TreeBuilder::UnaryExprContext unaryExprContext(context);
+ AllowInOverride allowInOverride(this);
+ int tokenStackDepth = 0;
+ bool modifiesExpr = false;
+ bool requiresLExpr = false;
+ unsigned lastOperator = 0;
+ while (isUnaryOp(m_token.m_type)) {
+ if (strictMode()) {
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ case MINUSMINUS:
+ case AUTOPLUSPLUS:
+ case AUTOMINUSMINUS:
+ semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression");
+ modifiesExpr = true;
+ requiresLExpr = true;
+ break;
+ case DELETETOKEN:
+ semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression");
+ requiresLExpr = true;
+ break;
+ default:
+ semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression");
+ break;
+ }
+ }
+ lastOperator = m_token.m_type;
+ m_nonLHSCount++;
+ context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStartPosition());
+ next();
+ m_nonTrivialExpressionCount++;
+ }
+ JSTextPosition subExprStart = tokenStartPosition();
+ ASSERT(subExprStart.offset >= subExprStart.lineStartOffset);
+ JSTokenLocation location(tokenLocation());
+ TreeExpression expr = parseMemberExpression(context);
+ if (!expr) {
+ if (lastOperator)
+ failWithMessage("Cannot parse subexpression of ", operatorString(true, lastOperator), "operator");
+ failWithMessage("Cannot parse member expression");
+ }
+ bool isEvalOrArguments = false;
+ if (strictMode() && !m_syntaxAlreadyValidated) {
+ if (context.isResolve(expr))
+ isEvalOrArguments = *m_lastIdentifier == m_vm->propertyNames->eval || *m_lastIdentifier == m_vm->propertyNames->arguments;
+ }
+ failIfTrueIfStrict(isEvalOrArguments && modifiesExpr, "Cannot modify '", m_lastIdentifier->impl(), "' in strict mode");
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments, "Cannot modify '", m_lastIdentifier->impl(), "' in strict mode");
+ semanticFailIfTrue(requiresLExpr, "The ", operatorString(false, lastOperator), " operator requires a reference expression");
+ lastOperator = PLUSPLUS;
+ next();
+ break;
+ case MINUSMINUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
+ semanticFailIfTrue(requiresLExpr, "The ", operatorString(false, lastOperator), " operator requires a reference expression");
+ lastOperator = PLUSPLUS;
+ next();
+ break;
+ default:
+ break;
+ }
+
+ JSTextPosition end = lastTokenEndPosition();
+
+ if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
+ return expr;
+
+ location = tokenLocation();
+ location.line = m_lexer->lastLineNumber();
+ while (tokenStackDepth) {
+ switch (context.unaryTokenStackLastType(tokenStackDepth)) {
+ case EXCLAMATION:
+ expr = context.createLogicalNot(location, expr);
+ break;
+ case TILDE:
+ expr = context.makeBitwiseNotNode(location, expr);
+ break;
+ case MINUS:
+ expr = context.makeNegateNode(location, expr);
+ break;
+ case PLUS:
+ expr = context.createUnaryPlus(location, expr);
+ break;
+ case PLUSPLUS:
+ case AUTOPLUSPLUS:
+ expr = context.makePrefixNode(location, expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case MINUSMINUS:
+ case AUTOMINUSMINUS:
+ expr = context.makePrefixNode(location, expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case TYPEOF:
+ expr = context.makeTypeOfNode(location, expr);
+ break;
+ case VOIDTOKEN:
+ expr = context.createVoid(location, expr);
+ break;
+ case DELETETOKEN:
+ failIfTrueIfStrict(context.isResolve(expr), "Cannot delete unqualified property '", m_lastIdentifier->impl(), "' in strict mode");
+ expr = context.makeDeleteNode(location, expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
+ break;
+ default:
+ // If we get here something has gone horribly horribly wrong
+ CRASH();
+ }
+ subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
+ context.unaryTokenStackRemoveLast(tokenStackDepth);
+ }
+ return expr;
+}
+
+
+template <typename LexerType> void Parser<LexerType>::printUnexpectedTokenText(WTF::PrintStream& out)
+{
+ switch (m_token.m_type) {
+ case EOFTOK:
+ out.print("Unexpected end of script");
+ return;
+ case UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK:
+ case UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK:
+ out.print("Incomplete unicode escape in identifier: '", getToken(), "'");
+ return;
+ case UNTERMINATED_MULTILINE_COMMENT_ERRORTOK:
+ out.print("Unterminated multiline comment");
+ return;
+ case UNTERMINATED_NUMERIC_LITERAL_ERRORTOK:
+ out.print("Unterminated numeric literal '", getToken(), "'");
+ return;
+ case UNTERMINATED_STRING_LITERAL_ERRORTOK:
+ out.print("Unterminated string literal '", getToken(), "'");
+ return;
+ case INVALID_IDENTIFIER_ESCAPE_ERRORTOK:
+ out.print("Invalid escape in identifier: '", getToken(), "'");
+ return;
+ case INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK:
+ out.print("Invalid unicode escape in identifier: '", getToken(), "'");
+ return;
+ case INVALID_NUMERIC_LITERAL_ERRORTOK:
+ out.print("Invalid numeric literal: '", getToken(), "'");
+ return;
+ case INVALID_OCTAL_NUMBER_ERRORTOK:
+ out.print("Invalid use of octal: '", getToken(), "'");
+ return;
+ case INVALID_STRING_LITERAL_ERRORTOK:
+ out.print("Invalid string literal: '", getToken(), "'");
+ return;
+ case ERRORTOK:
+ out.print("Unrecognized token '", getToken(), "'");
+ return;
+ case STRING:
+ out.print("Unexpected string literal ", getToken());
+ return;
+ case INTEGER:
+ case DOUBLE:
+ out.print("Unexpected number '", getToken(), "'");
+ return;
+
+ case RESERVED_IF_STRICT:
+ out.print("Unexpected use of reserved word '", getToken(), "' in strict mode");
+ return;
+
+ case RESERVED:
+ out.print("Unexpected use of reserved word '", getToken(), "'");
+ return;
+
+ case INVALID_PRIVATE_NAME_ERRORTOK:
+ out.print("Invalid private name '", getToken(), "'");
+ return;
+
+ case IDENT:
+ out.print("Unexpected identifier '", getToken(), "'");
+ return;
+
+ default:
+ break;
+ }
+
+ if (m_token.m_type & KeywordTokenFlag) {
+ out.print("Unexpected keyword '", getToken(), "'");
+ return;
+ }
+
+ out.print("Unexpected token '", getToken(), "'");
+}
+
+// Instantiate the two flavors of Parser we need instead of putting most of this file in Parser.h
+template class Parser<Lexer<LChar>>;
+template class Parser<Lexer<UChar>>;
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
new file mode 100644
index 000000000..c2e6a6504
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Parser_h
+#define Parser_h
+
+#include "Debugger.h"
+#include "ExceptionHelpers.h"
+#include "Executable.h"
+#include "JSGlobalObject.h"
+#include "Lexer.h"
+#include "Nodes.h"
+#include "ParserArena.h"
+#include "ParserError.h"
+#include "ParserFunctionInfo.h"
+#include "ParserTokens.h"
+#include "SourceProvider.h"
+#include "SourceProviderCache.h"
+#include "SourceProviderCacheItem.h"
+#include "VariableEnvironment.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+namespace JSC {
+struct Scope;
+}
+
+namespace WTF {
+template <> struct VectorTraits<JSC::Scope> : SimpleClassVectorTraits {
+ static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0.
+};
+}
+
+namespace JSC {
+
+class ExecState;
+class FunctionMetadataNode;
+class FunctionParameters;
+class Identifier;
+class VM;
+class ProgramNode;
+class SourceCode;
+
+// Macros to make the more common TreeBuilder types a little less verbose
+#define TreeStatement typename TreeBuilder::Statement
+#define TreeExpression typename TreeBuilder::Expression
+#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
+#define TreeSourceElements typename TreeBuilder::SourceElements
+#define TreeClause typename TreeBuilder::Clause
+#define TreeClauseList typename TreeBuilder::ClauseList
+#define TreeArguments typename TreeBuilder::Arguments
+#define TreeArgumentsList typename TreeBuilder::ArgumentsList
+#define TreeFunctionBody typename TreeBuilder::FunctionBody
+#if ENABLE(ES6_CLASS_SYNTAX)
+#define TreeClassExpression typename TreeBuilder::ClassExpression
+#endif
+#define TreeProperty typename TreeBuilder::Property
+#define TreePropertyList typename TreeBuilder::PropertyList
+#define TreeDestructuringPattern typename TreeBuilder::DestructuringPattern
+
+COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
+
+enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+enum FunctionParseType { StandardFunctionParseType, ArrowFunctionParseType };
+enum FunctionBodyType { ArrowFunctionBodyExpression, ArrowFunctionBodyBlock, StandardFunctionBodyBlock };
+enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+
+enum DestructuringKind {
+ DestructureToVariables,
+ DestructureToLet,
+ DestructureToConst,
+ DestructureToParameters,
+ DestructureToExpressions
+};
+
+enum class DeclarationType {
+ VarDeclaration,
+ LetDeclaration,
+ ConstDeclaration
+};
+
+enum class DeclarationImportType {
+ Imported,
+ NotImported
+};
+
+enum DeclarationResult {
+ Valid = 0,
+ InvalidStrictMode = 1 << 0,
+ InvalidDuplicateDeclaration = 1 << 1
+};
+
+typedef uint8_t DeclarationResultMask;
+
+
+template <typename T> inline bool isEvalNode() { return false; }
+template <> inline bool isEvalNode<EvalNode>() { return true; }
+
+struct ScopeLabelInfo {
+ UniquedStringImpl* uid;
+ bool isLoop;
+};
+
+ALWAYS_INLINE static bool isArguments(const VM* vm, const Identifier* ident)
+{
+ return vm->propertyNames->arguments == *ident;
+}
+ALWAYS_INLINE static bool isEval(const VM* vm, const Identifier* ident)
+{
+ return vm->propertyNames->eval == *ident;
+}
+ALWAYS_INLINE static bool isEvalOrArgumentsIdentifier(const VM* vm, const Identifier* ident)
+{
+ return isEval(vm, ident) || isArguments(vm, ident);
+}
+ALWAYS_INLINE static bool isIdentifierOrKeyword(const JSToken& token)
+{
+ return token.m_type == IDENT || token.m_type & KeywordTokenFlag;
+}
+
+class ModuleScopeData : public RefCounted<ModuleScopeData> {
+public:
+ static Ref<ModuleScopeData> create() { return adoptRef(*new ModuleScopeData); }
+
+ const IdentifierSet& exportedBindings() const { return m_exportedBindings; }
+
+ bool exportName(const Identifier& exportedName)
+ {
+ return m_exportedNames.add(exportedName.impl()).isNewEntry;
+ }
+
+ void exportBinding(const Identifier& localName)
+ {
+ m_exportedBindings.add(localName.impl());
+ }
+
+private:
+ IdentifierSet m_exportedNames { };
+ IdentifierSet m_exportedBindings { };
+};
+
+struct Scope {
+ Scope(const VM* vm, bool isFunction, bool strictMode)
+ : m_vm(vm)
+ , m_shadowsArguments(false)
+ , m_usesEval(false)
+ , m_needsFullActivation(false)
+ , m_hasDirectSuper(false)
+ , m_needsSuperBinding(false)
+ , m_allowsVarDeclarations(true)
+ , m_allowsLexicalDeclarations(true)
+ , m_strictMode(strictMode)
+ , m_isFunction(isFunction)
+ , m_isLexicalScope(false)
+ , m_isFunctionBoundary(false)
+ , m_isValidStrictMode(true)
+ , m_loopDepth(0)
+ , m_switchDepth(0)
+ {
+ }
+
+ Scope(const Scope& rhs)
+ : m_vm(rhs.m_vm)
+ , m_shadowsArguments(rhs.m_shadowsArguments)
+ , m_usesEval(rhs.m_usesEval)
+ , m_needsFullActivation(rhs.m_needsFullActivation)
+ , m_hasDirectSuper(rhs.m_hasDirectSuper)
+ , m_needsSuperBinding(rhs.m_needsSuperBinding)
+ , m_allowsVarDeclarations(rhs.m_allowsVarDeclarations)
+ , m_allowsLexicalDeclarations(rhs.m_allowsLexicalDeclarations)
+ , m_strictMode(rhs.m_strictMode)
+ , m_isFunction(rhs.m_isFunction)
+ , m_isLexicalScope(rhs.m_isLexicalScope)
+ , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
+ , m_isValidStrictMode(rhs.m_isValidStrictMode)
+ , m_loopDepth(rhs.m_loopDepth)
+ , m_switchDepth(rhs.m_switchDepth)
+ , m_moduleScopeData(rhs.m_moduleScopeData)
+ {
+ if (rhs.m_labels) {
+ m_labels = std::make_unique<LabelStack>();
+
+ typedef LabelStack::const_iterator iterator;
+ iterator end = rhs.m_labels->end();
+ for (iterator it = rhs.m_labels->begin(); it != end; ++it)
+ m_labels->append(ScopeLabelInfo { it->uid, it->isLoop });
+ }
+ }
+
+ void startSwitch() { m_switchDepth++; }
+ void endSwitch() { m_switchDepth--; }
+ void startLoop() { m_loopDepth++; }
+ void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
+ bool inLoop() { return !!m_loopDepth; }
+ bool breakIsValid() { return m_loopDepth || m_switchDepth; }
+ bool continueIsValid() { return m_loopDepth; }
+
+ void pushLabel(const Identifier* label, bool isLoop)
+ {
+ if (!m_labels)
+ m_labels = std::make_unique<LabelStack>();
+ m_labels->append(ScopeLabelInfo { label->impl(), isLoop });
+ }
+
+ void popLabel()
+ {
+ ASSERT(m_labels);
+ ASSERT(m_labels->size());
+ m_labels->removeLast();
+ }
+
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ if (!m_labels)
+ return 0;
+ for (int i = m_labels->size(); i > 0; i--) {
+ if (m_labels->at(i - 1).uid == label->impl())
+ return &m_labels->at(i - 1);
+ }
+ return 0;
+ }
+
+ void setIsFunction()
+ {
+ m_isFunction = true;
+ m_isFunctionBoundary = true;
+ setIsLexicalScope();
+ }
+
+ void setIsModule()
+ {
+ m_moduleScopeData = ModuleScopeData::create();
+ }
+
+ bool isFunction() const { return m_isFunction; }
+ bool isFunctionBoundary() const { return m_isFunctionBoundary; }
+
+ void setIsLexicalScope()
+ {
+ m_isLexicalScope = true;
+ m_allowsLexicalDeclarations = true;
+ }
+ bool isLexicalScope() { return m_isLexicalScope; }
+
+ VariableEnvironment& declaredVariables() { return m_declaredVariables; }
+ VariableEnvironment& lexicalVariables() { return m_lexicalVariables; }
+ VariableEnvironment& finalizeLexicalEnvironment()
+ {
+ if (m_usesEval || m_needsFullActivation)
+ m_lexicalVariables.markAllVariablesAsCaptured();
+ else
+ computeLexicallyCapturedVariablesAndPurgeCandidates();
+
+ return m_lexicalVariables;
+ }
+
+ ModuleScopeData& moduleScopeData() const
+ {
+ ASSERT(m_moduleScopeData);
+ return *m_moduleScopeData;
+ }
+
+ void computeLexicallyCapturedVariablesAndPurgeCandidates()
+ {
+ // Because variables may be defined at any time in the range of a lexical scope, we must
+ // track lexical variables that might be captured. Then, when we're preparing to pop the top
+ // lexical scope off the stack, we should find which variables are truly captured, and which
+ // variable still may be captured in a parent scope.
+ if (m_lexicalVariables.size() && m_closedVariableCandidates.size()) {
+ auto end = m_closedVariableCandidates.end();
+ for (auto iter = m_closedVariableCandidates.begin(); iter != end; ++iter)
+ m_lexicalVariables.markVariableAsCapturedIfDefined(iter->get());
+ }
+
+ // We can now purge values from the captured candidates because they're captured in this scope.
+ {
+ for (auto entry : m_lexicalVariables) {
+ if (entry.value.isCaptured())
+ m_closedVariableCandidates.remove(entry.key);
+ }
+ }
+ }
+
+ void declareCallee(const Identifier* ident)
+ {
+ auto addResult = m_declaredVariables.add(ident->impl());
+ // We want to track if callee is captured, but we don't want to act like it's a 'var'
+ // because that would cause the BytecodeGenerator to emit bad code.
+ addResult.iterator->value.clearIsVar();
+ }
+
+ DeclarationResultMask declareVariable(const Identifier* ident)
+ {
+ ASSERT(m_allowsVarDeclarations);
+ DeclarationResultMask result = DeclarationResult::Valid;
+ bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident);
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ auto addResult = m_declaredVariables.add(ident->impl());
+ addResult.iterator->value.setIsVar();
+ if (!isValidStrictMode)
+ result |= DeclarationResult::InvalidStrictMode;
+ return result;
+ }
+
+ DeclarationResultMask declareLexicalVariable(const Identifier* ident, bool isConstant, DeclarationImportType importType = DeclarationImportType::NotImported)
+ {
+ ASSERT(m_allowsLexicalDeclarations);
+ DeclarationResultMask result = DeclarationResult::Valid;
+ bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident);
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ auto addResult = m_lexicalVariables.add(ident->impl());
+ if (isConstant)
+ addResult.iterator->value.setIsConst();
+ else
+ addResult.iterator->value.setIsLet();
+
+ if (importType == DeclarationImportType::Imported)
+ addResult.iterator->value.setIsImported();
+
+ if (!addResult.isNewEntry)
+ result |= DeclarationResult::InvalidDuplicateDeclaration;
+ if (!isValidStrictMode)
+ result |= DeclarationResult::InvalidStrictMode;
+
+ return result;
+ }
+
+ bool hasDeclaredVariable(const Identifier& ident)
+ {
+ return hasDeclaredVariable(ident.impl());
+ }
+
+ bool hasDeclaredVariable(const RefPtr<UniquedStringImpl>& ident)
+ {
+ return m_declaredVariables.contains(ident.get());
+ }
+
+ bool hasLexicallyDeclaredVariable(const RefPtr<UniquedStringImpl>& ident) const
+ {
+ return m_lexicalVariables.contains(ident.get());
+ }
+
+ ALWAYS_INLINE bool hasDeclaredParameter(const Identifier& ident)
+ {
+ return hasDeclaredParameter(ident.impl());
+ }
+
+ bool hasDeclaredParameter(const RefPtr<UniquedStringImpl>& ident)
+ {
+ return m_declaredParameters.contains(ident) || m_declaredVariables.contains(ident.get());
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ ASSERT(m_strictMode);
+ m_writtenVariables.add(ident->impl());
+ }
+
+ void preventAllVariableDeclarations()
+ {
+ m_allowsVarDeclarations = false;
+ m_allowsLexicalDeclarations = false;
+ }
+ void preventVarDeclarations() { m_allowsVarDeclarations = false; }
+ bool allowsVarDeclarations() const { return m_allowsVarDeclarations; }
+ bool allowsLexicalDeclarations() const { return m_allowsLexicalDeclarations; }
+
+ DeclarationResultMask declareParameter(const Identifier* ident)
+ {
+ ASSERT(m_allowsVarDeclarations);
+ DeclarationResultMask result = DeclarationResult::Valid;
+ bool isArgumentsIdent = isArguments(m_vm, ident);
+ auto addResult = m_declaredVariables.add(ident->impl());
+ addResult.iterator->value.clearIsVar();
+ bool isValidStrictMode = addResult.isNewEntry && m_vm->propertyNames->eval != *ident && !isArgumentsIdent;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ m_declaredParameters.add(ident->impl());
+ if (!isValidStrictMode)
+ result |= DeclarationResult::InvalidStrictMode;
+ if (isArgumentsIdent)
+ m_shadowsArguments = true;
+ if (!addResult.isNewEntry)
+ result |= DeclarationResult::InvalidDuplicateDeclaration;
+
+ return result;
+ }
+
+ enum BindingResult {
+ BindingFailed,
+ StrictBindingFailed,
+ BindingSucceeded
+ };
+ BindingResult declareBoundParameter(const Identifier* ident)
+ {
+ bool isArgumentsIdent = isArguments(m_vm, ident);
+ auto addResult = m_declaredVariables.add(ident->impl());
+ addResult.iterator->value.setIsVar(); // Treat destructuring parameters as "var"s.
+ bool isValidStrictMode = addResult.isNewEntry && !isEval(m_vm, ident) && !isArgumentsIdent;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+
+ if (isArgumentsIdent)
+ m_shadowsArguments = true;
+ if (!addResult.isNewEntry)
+ return BindingFailed;
+ return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
+ }
+
+ void getUsedVariables(IdentifierSet& usedVariables)
+ {
+ usedVariables.swap(m_usedVariables);
+ }
+
+ void useVariable(const Identifier* ident, bool isEval)
+ {
+ m_usesEval |= isEval;
+ m_usedVariables.add(ident->impl());
+ }
+
+ void setNeedsFullActivation() { m_needsFullActivation = true; }
+ bool needsFullActivation() const { return m_needsFullActivation; }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ bool hasDirectSuper() { return m_hasDirectSuper; }
+#else
+ bool hasDirectSuper() { return false; }
+#endif
+ void setHasDirectSuper() { m_hasDirectSuper = true; }
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ bool needsSuperBinding() { return m_needsSuperBinding; }
+#else
+ bool needsSuperBinding() { return false; }
+#endif
+ void setNeedsSuperBinding() { m_needsSuperBinding = true; }
+
+ void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
+ {
+ if (nestedScope->m_usesEval)
+ m_usesEval = true;
+
+ {
+ IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr) || nestedScope->m_lexicalVariables.contains(*ptr))
+ continue;
+ m_usedVariables.add(*ptr);
+ // We don't want a declared variable that is used in an inner scope to be thought of as captured if
+ // that inner scope is both a lexical scope and not a function. Only inner functions and "catch"
+ // statements can cause variables to be captured.
+ if (shouldTrackClosedVariables && (nestedScope->m_isFunctionBoundary || !nestedScope->m_isLexicalScope))
+ m_closedVariableCandidates.add(*ptr);
+ }
+ }
+ // Propagate closed variable candidates downwards within the same function.
+ // Cross function captures will be realized via m_usedVariables propagation.
+ if (shouldTrackClosedVariables && !nestedScope->m_isFunctionBoundary && nestedScope->m_closedVariableCandidates.size()) {
+ IdentifierSet::iterator end = nestedScope->m_closedVariableCandidates.end();
+ IdentifierSet::iterator begin = nestedScope->m_closedVariableCandidates.begin();
+ m_closedVariableCandidates.add(begin, end);
+ }
+
+ if (nestedScope->m_writtenVariables.size()) {
+ IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr) || nestedScope->m_lexicalVariables.contains(*ptr))
+ continue;
+ m_writtenVariables.add(*ptr);
+ }
+ }
+ }
+
+ void getCapturedVars(IdentifierSet& capturedVariables, bool& modifiedParameter, bool& modifiedArguments)
+ {
+ if (m_needsFullActivation || m_usesEval) {
+ modifiedParameter = true;
+ for (auto& entry : m_declaredVariables)
+ capturedVariables.add(entry.key);
+ return;
+ }
+ for (IdentifierSet::iterator ptr = m_closedVariableCandidates.begin(); ptr != m_closedVariableCandidates.end(); ++ptr) {
+ if (!m_declaredVariables.contains(*ptr))
+ continue;
+ capturedVariables.add(*ptr);
+ }
+ modifiedParameter = false;
+ if (shadowsArguments())
+ modifiedArguments = true;
+ if (m_declaredParameters.size()) {
+ IdentifierSet::iterator end = m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (*ptr == m_vm->propertyNames->arguments.impl())
+ modifiedArguments = true;
+ if (!m_declaredParameters.contains(*ptr))
+ continue;
+ modifiedParameter = true;
+ break;
+ }
+ }
+ }
+ void setStrictMode() { m_strictMode = true; }
+ bool strictMode() const { return m_strictMode; }
+ bool isValidStrictMode() const { return m_isValidStrictMode; }
+ bool shadowsArguments() const { return m_shadowsArguments; }
+
+ void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<UniquedStringImpl>>& vector)
+ {
+ IdentifierSet::iterator end = capturedVariables.end();
+ for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
+ if (m_declaredVariables.contains(*it) || m_lexicalVariables.contains(*it))
+ continue;
+ vector.append(*it);
+ }
+ }
+
+ void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters)
+ {
+ ASSERT(m_isFunction);
+ parameters.usesEval = m_usesEval;
+ parameters.strictMode = m_strictMode;
+ parameters.needsFullActivation = m_needsFullActivation;
+ copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables);
+ copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables);
+ }
+
+ void restoreFromSourceProviderCache(const SourceProviderCacheItem* info)
+ {
+ ASSERT(m_isFunction);
+ m_usesEval = info->usesEval;
+ m_strictMode = info->strictMode;
+ m_needsFullActivation = info->needsFullActivation;
+ for (unsigned i = 0; i < info->usedVariablesCount; ++i)
+ m_usedVariables.add(info->usedVariables()[i]);
+ for (unsigned i = 0; i < info->writtenVariablesCount; ++i)
+ m_writtenVariables.add(info->writtenVariables()[i]);
+ }
+
+private:
+ const VM* m_vm;
+ bool m_shadowsArguments : 1;
+ bool m_usesEval : 1;
+ bool m_needsFullActivation : 1;
+ bool m_hasDirectSuper : 1;
+ bool m_needsSuperBinding : 1;
+ bool m_allowsVarDeclarations : 1;
+ bool m_allowsLexicalDeclarations : 1;
+ bool m_strictMode : 1;
+ bool m_isFunction : 1;
+ bool m_isLexicalScope : 1;
+ bool m_isFunctionBoundary : 1;
+ bool m_isValidStrictMode : 1;
+ int m_loopDepth;
+ int m_switchDepth;
+
+ typedef Vector<ScopeLabelInfo, 2> LabelStack;
+ std::unique_ptr<LabelStack> m_labels;
+ IdentifierSet m_declaredParameters;
+ VariableEnvironment m_declaredVariables;
+ VariableEnvironment m_lexicalVariables;
+ IdentifierSet m_usedVariables;
+ IdentifierSet m_closedVariableCandidates;
+ IdentifierSet m_writtenVariables;
+ RefPtr<ModuleScopeData> m_moduleScopeData { };
+};
+
+typedef Vector<Scope, 10> ScopeStack;
+
+struct ScopeRef {
+ ScopeRef(ScopeStack* scopeStack, unsigned index)
+ : m_scopeStack(scopeStack)
+ , m_index(index)
+ {
+ }
+ Scope* operator->() { return &m_scopeStack->at(m_index); }
+ unsigned index() const { return m_index; }
+
+ bool hasContainingScope()
+ {
+ return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
+ }
+
+ ScopeRef containingScope()
+ {
+ ASSERT(hasContainingScope());
+ return ScopeRef(m_scopeStack, m_index - 1);
+ }
+
+private:
+ ScopeStack* m_scopeStack;
+ unsigned m_index;
+};
+
+template <typename LexerType>
+class Parser {
+ WTF_MAKE_NONCOPYABLE(Parser);
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ Parser(
+ VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, SourceParseMode,
+ ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded);
+ ~Parser();
+
+ template <class ParsedNode>
+ std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode);
+
+ JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
+ JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); }
+ Vector<RefPtr<UniquedStringImpl>>&& closedVariables() { return WTF::move(m_closedVariables); }
+
+private:
+ struct AllowInOverride {
+ AllowInOverride(Parser* parser)
+ : m_parser(parser)
+ , m_oldAllowsIn(parser->m_allowsIn)
+ {
+ parser->m_allowsIn = true;
+ }
+ ~AllowInOverride()
+ {
+ m_parser->m_allowsIn = m_oldAllowsIn;
+ }
+ Parser* m_parser;
+ bool m_oldAllowsIn;
+ };
+
+ struct AutoPopScopeRef : public ScopeRef {
+ AutoPopScopeRef(Parser* parser, ScopeRef scope)
+ : ScopeRef(scope)
+ , m_parser(parser)
+ {
+ }
+
+ ~AutoPopScopeRef()
+ {
+ if (m_parser)
+ m_parser->popScope(*this, false);
+ }
+
+ void setPopped()
+ {
+ m_parser = 0;
+ }
+
+ private:
+ Parser* m_parser;
+ };
+
+ struct AutoCleanupLexicalScope {
+ // We can allocate this object on the stack without actually knowing beforehand if we're
+ // going to create a new lexical scope. If we decide to create a new lexical scope, we
+ // can pass the scope into this obejct and it will take care of the cleanup for us if the parse fails.
+ // This is helpful if we may fail from syntax errors after creating a lexical scope conditionally.
+ AutoCleanupLexicalScope()
+ : m_scope(nullptr, UINT_MAX)
+ , m_parser(nullptr)
+ {
+ }
+
+ ~AutoCleanupLexicalScope()
+ {
+ // This should only ever be called if we fail from a syntax error. Otherwise
+ // it's the intention that a user of this class pops this scope manually on a
+ // successful parse.
+ if (isValid())
+ m_parser->popScope(*this, false);
+ }
+
+ void setIsValid(ScopeRef& scope, Parser* parser)
+ {
+ RELEASE_ASSERT(scope->isLexicalScope());
+ m_scope = scope;
+ m_parser = parser;
+ }
+
+ bool isValid() const { return !!m_parser; }
+
+ void setPopped()
+ {
+ m_parser = nullptr;
+ }
+
+ ScopeRef& scope() { return m_scope; }
+
+ private:
+ ScopeRef m_scope;
+ Parser* m_parser;
+ };
+
+ ALWAYS_INLINE DestructuringKind destructuringKindFromDeclarationType(DeclarationType type)
+ {
+ switch (type) {
+ case DeclarationType::VarDeclaration:
+ return DestructureToVariables;
+ case DeclarationType::LetDeclaration:
+ return DestructureToLet;
+ case DeclarationType::ConstDeclaration:
+ return DestructureToConst;
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return DestructureToVariables;
+ }
+
+ ALWAYS_INLINE AssignmentContext assignmentContextFromDeclarationType(DeclarationType type)
+ {
+ switch (type) {
+ case DeclarationType::ConstDeclaration:
+ return AssignmentContext::ConstDeclarationStatement;
+ default:
+ return AssignmentContext::DeclarationStatement;
+ }
+ }
+
+ ALWAYS_INLINE bool isEvalOrArguments(const Identifier* ident) { return isEvalOrArgumentsIdentifier(m_vm, ident); }
+
+ ScopeRef currentScope()
+ {
+ return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+ }
+
+ ScopeRef pushScope()
+ {
+ bool isFunction = false;
+ bool isStrict = false;
+ if (!m_scopeStack.isEmpty()) {
+ isStrict = m_scopeStack.last().strictMode();
+ isFunction = m_scopeStack.last().isFunction();
+ }
+ m_scopeStack.append(Scope(m_vm, isFunction, isStrict));
+ return currentScope();
+ }
+
+ void popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
+ ASSERT(m_scopeStack.size() > 1);
+ m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+ if (!m_scopeStack.last().isFunctionBoundary() && m_scopeStack.last().needsFullActivation())
+ m_scopeStack[m_scopeStack.size() - 2].setNeedsFullActivation();
+ m_scopeStack.removeLast();
+ }
+
+ ALWAYS_INLINE void popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ ALWAYS_INLINE void popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ scope.setPopped();
+ popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ ALWAYS_INLINE void popScope(AutoCleanupLexicalScope& cleanupScope, bool shouldTrackClosedVariables)
+ {
+ RELEASE_ASSERT(cleanupScope.isValid());
+ ScopeRef& scope = cleanupScope.scope();
+ cleanupScope.setPopped();
+ popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ DeclarationResultMask declareVariable(const Identifier* ident, DeclarationType type = DeclarationType::VarDeclaration, DeclarationImportType importType = DeclarationImportType::NotImported)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+
+ if (type == DeclarationType::VarDeclaration) {
+ while (!m_scopeStack[i].allowsVarDeclarations()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+
+ return m_scopeStack[i].declareVariable(ident);
+ }
+
+ ASSERT(type == DeclarationType::LetDeclaration || type == DeclarationType::ConstDeclaration);
+
+ // Lexical variables declared at a top level scope that shadow arguments or vars are not allowed.
+ if (m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
+ return DeclarationResult::InvalidDuplicateDeclaration;
+
+ while (!m_scopeStack[i].allowsLexicalDeclarations()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+
+ return m_scopeStack[i].declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration, importType);
+ }
+
+ NEVER_INLINE bool hasDeclaredVariable(const Identifier& ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsVarDeclarations()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].hasDeclaredVariable(ident);
+ }
+
+ NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsVarDeclarations()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].hasDeclaredParameter(ident);
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ if (!m_syntaxAlreadyValidated || strictMode())
+ m_scopeStack.last().declareWrite(ident);
+ }
+
+ bool exportName(const Identifier& ident)
+ {
+ ASSERT(currentScope().index() == 0);
+ return currentScope()->moduleScopeData().exportName(ident);
+ }
+
+ ScopeStack m_scopeStack;
+
+ const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos)
+ {
+ return m_functionCache ? m_functionCache->get(openBracePos) : 0;
+ }
+
+ Parser();
+ String parseInner(const Identifier&, SourceParseMode);
+
+ void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&, VariableEnvironment&, CodeFeatures, int, const Vector<RefPtr<UniquedStringImpl>>&&);
+
+ // Used to determine type of error to report.
+ bool isFunctionMetadataNode(ScopeNode*) { return false; }
+ bool isFunctionMetadataNode(FunctionMetadataNode*) { return true; }
+
+ ALWAYS_INLINE void next(unsigned lexerFlags = 0)
+ {
+ int lastLine = m_token.m_location.line;
+ int lastTokenEnd = m_token.m_location.endOffset;
+ int lastTokenLineStart = m_token.m_location.lineStartOffset;
+ m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+ m_lexer->setLastLineNumber(lastLine);
+ m_token.m_type = m_lexer->lex(&m_token, lexerFlags, strictMode());
+ }
+
+ ALWAYS_INLINE void nextExpectIdentifier(unsigned lexerFlags = 0)
+ {
+ int lastLine = m_token.m_location.line;
+ int lastTokenEnd = m_token.m_location.endOffset;
+ int lastTokenLineStart = m_token.m_location.lineStartOffset;
+ m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+ m_lexer->setLastLineNumber(lastLine);
+ m_token.m_type = m_lexer->lexExpectIdentifier(&m_token, lexerFlags, strictMode());
+ }
+
+ ALWAYS_INLINE bool nextTokenIsColon()
+ {
+ return m_lexer->nextTokenIsColon();
+ }
+
+ ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+ {
+ bool result = m_token.m_type == expected;
+ if (result)
+ next(flags);
+ return result;
+ }
+
+ void printUnexpectedTokenText(WTF::PrintStream&);
+ ALWAYS_INLINE String getToken() {
+ SourceProvider* sourceProvider = m_source->provider();
+ return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset);
+ }
+
+ ALWAYS_INLINE bool match(JSTokenType expected)
+ {
+ return m_token.m_type == expected;
+ }
+
+ ALWAYS_INLINE bool matchContextualKeyword(const Identifier& identifier)
+ {
+ return m_token.m_type == IDENT && *m_token.m_data.ident == identifier;
+ }
+
+ ALWAYS_INLINE bool matchIdentifierOrKeyword()
+ {
+ return isIdentifierOrKeyword(m_token);
+ }
+
+ ALWAYS_INLINE bool isEndOfArrowFunction()
+ {
+ return match(SEMICOLON) || match(COMMA) || match(CLOSEPAREN) || match(CLOSEBRACE) || match(CLOSEBRACKET) || match(EOFTOK) || m_lexer->prevTerminator();
+ }
+
+ ALWAYS_INLINE bool isArrowFunctionParamters()
+ {
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ bool isArrowFunction = false;
+
+ if (match(EOFTOK))
+ return isArrowFunction;
+
+ SavePoint saveArrowFunctionPoint = createSavePoint();
+
+ if (consume(OPENPAREN)) {
+ bool isArrowFunctionParamters = true;
+
+ while (consume(IDENT)) {
+ if (consume(COMMA)) {
+ if (!match(IDENT)) {
+ isArrowFunctionParamters = false;
+ break;
+ }
+ } else
+ break;
+ }
+
+ if (isArrowFunctionParamters) {
+ if (consume(CLOSEPAREN) && match(ARROWFUNCTION))
+ isArrowFunction = true;
+ }
+ } else if (consume(IDENT) && match(ARROWFUNCTION))
+ isArrowFunction = true;
+
+ restoreSavePoint(saveArrowFunctionPoint);
+
+ return isArrowFunction;
+#else
+ return false;
+#endif
+ }
+
+ ALWAYS_INLINE unsigned tokenStart()
+ {
+ return m_token.m_location.startOffset;
+ }
+
+ ALWAYS_INLINE const JSTextPosition& tokenStartPosition()
+ {
+ return m_token.m_startPosition;
+ }
+
+ ALWAYS_INLINE int tokenLine()
+ {
+ return m_token.m_location.line;
+ }
+
+ ALWAYS_INLINE int tokenColumn()
+ {
+ return tokenStart() - tokenLineStart();
+ }
+
+ ALWAYS_INLINE const JSTextPosition& tokenEndPosition()
+ {
+ return m_token.m_endPosition;
+ }
+
+ ALWAYS_INLINE unsigned tokenLineStart()
+ {
+ return m_token.m_location.lineStartOffset;
+ }
+
+ ALWAYS_INLINE const JSTokenLocation& tokenLocation()
+ {
+ return m_token.m_location;
+ }
+
+ void setErrorMessage(const String& message)
+ {
+ m_errorMessage = message;
+ }
+
+ NEVER_INLINE void logError(bool);
+ template <typename A> NEVER_INLINE void logError(bool, const A&);
+ template <typename A, typename B> NEVER_INLINE void logError(bool, const A&, const B&);
+ template <typename A, typename B, typename C> NEVER_INLINE void logError(bool, const A&, const B&, const C&);
+ template <typename A, typename B, typename C, typename D> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&);
+ template <typename A, typename B, typename C, typename D, typename E> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&);
+ template <typename A, typename B, typename C, typename D, typename E, typename F> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&);
+ template <typename A, typename B, typename C, typename D, typename E, typename F, typename G> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&, const G&);
+
+ NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMessage, const String& name, const char* afterMessage)
+ {
+ m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage);
+ }
+
+ NEVER_INLINE void updateErrorMessage(const char* msg)
+ {
+ ASSERT(msg);
+ m_errorMessage = String(msg);
+ ASSERT(!m_errorMessage.isNull());
+ }
+
+ void startLoop() { currentScope()->startLoop(); }
+ void endLoop() { currentScope()->endLoop(); }
+ void startSwitch() { currentScope()->startSwitch(); }
+ void endSwitch() { currentScope()->endSwitch(); }
+ void setStrictMode() { currentScope()->setStrictMode(); }
+ bool strictMode() { return currentScope()->strictMode(); }
+ bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+ DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
+ bool breakIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->breakIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ bool continueIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->continueIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+ void popLabel(ScopeRef scope) { scope->popLabel(); }
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ ScopeRef current = currentScope();
+ ScopeLabelInfo* result = 0;
+ while (!(result = current->getLabel(label))) {
+ if (!current.hasContainingScope())
+ return 0;
+ current = current.containingScope();
+ }
+ return result;
+ }
+
+ ALWAYS_INLINE bool isLETMaskedAsIDENT()
+ {
+ return match(LET) && !strictMode();
+ }
+
+ template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
+ template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
+ enum class ExportType { Exported, NotExported };
+#if ENABLE(ES6_CLASS_SYNTAX)
+ template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
+#endif
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported);
+ template <class TreeBuilder> TreeStatement parseVariableDeclaration(TreeBuilder&, DeclarationType, ExportType = ExportType::NotExported);
+ template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
+ template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
+ 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> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+ enum SpreadMode { AllowSpread, DontAllowSpread };
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode);
+ template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
+ template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName);
+ template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionBodyType, unsigned, SourceParseMode);
+ template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, unsigned&);
+ enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
+ template <class TreeBuilder> TreeExpression parseVariableDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext, DeclarationType, ExportType, bool& forLoopConstDoesNotHaveInitializer);
+ template <class TreeBuilder> TreeSourceElements parseArrowFunctionSingleExpressionBodySourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, int depth, JSToken, AssignmentContext, const Identifier** duplicateIdentifier);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier** duplicateIdentifier = nullptr, bool* hasDestructuringPattern = nullptr, AssignmentContext = AssignmentContext::DeclarationStatement, int depth = 0);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&, AssignmentContext);
+ template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&);
+ template <class TreeBuilder> TreeSourceElements parseModuleSourceElements(TreeBuilder&, SourceParseMode);
+ enum class ImportSpecifierType { NamespaceImport, NamedImport, DefaultImport };
+ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier parseImportClauseItem(TreeBuilder&, ImportSpecifierType);
+ template <class TreeBuilder> typename TreeBuilder::ModuleName parseModuleName(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseImportDeclaration(TreeBuilder&);
+ template <class TreeBuilder> typename TreeBuilder::ExportSpecifier parseExportSpecifier(TreeBuilder& context, Vector<const Identifier*>& maybeLocalNames, bool& hasKeywordForLocalBindings);
+ template <class TreeBuilder> TreeStatement parseExportDeclaration(TreeBuilder&);
+
+ template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionParseType);
+
+ template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, SourceParseMode, ParserFunctionInfo<TreeBuilder>&);
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
+#endif
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail);
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode);
+#endif
+
+ template <class TreeBuilder> ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&);
+
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType);
+ bool allowAutomaticSemicolon();
+
+ bool autoSemiColon()
+ {
+ if (m_token.m_type == SEMICOLON) {
+ next();
+ return true;
+ }
+ return allowAutomaticSemicolon();
+ }
+
+ void setEndOfStatement()
+ {
+ m_lexer->setTokenPosition(&m_token);
+ }
+
+ bool canRecurse()
+ {
+ return m_vm->isSafeToRecurse();
+ }
+
+ const JSTextPosition& lastTokenEndPosition() const
+ {
+ return m_lastTokenEndPosition;
+ }
+
+ bool hasError() const
+ {
+ return !m_errorMessage.isNull();
+ }
+
+ struct SavePoint {
+ int startOffset;
+ unsigned oldLineStartOffset;
+ unsigned oldLastLineNumber;
+ unsigned oldLineNumber;
+ };
+
+ ALWAYS_INLINE SavePoint createSavePoint()
+ {
+ ASSERT(!hasError());
+ SavePoint result;
+ result.startOffset = m_token.m_location.startOffset;
+ result.oldLineStartOffset = m_token.m_location.lineStartOffset;
+ result.oldLastLineNumber = m_lexer->lastLineNumber();
+ result.oldLineNumber = m_lexer->lineNumber();
+ return result;
+ }
+
+ ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint)
+ {
+ m_errorMessage = String();
+ m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset);
+ next();
+ m_lexer->setLastLineNumber(savePoint.oldLastLineNumber);
+ m_lexer->setLineNumber(savePoint.oldLineNumber);
+ }
+
+ struct ParserState {
+ int assignmentCount;
+ int nonLHSCount;
+ int nonTrivialExpressionCount;
+ };
+
+ ALWAYS_INLINE ParserState saveState()
+ {
+ ParserState result;
+ result.assignmentCount = m_assignmentCount;
+ result.nonLHSCount = m_nonLHSCount;
+ result.nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ return result;
+ }
+
+ ALWAYS_INLINE void restoreState(const ParserState& state)
+ {
+ m_assignmentCount = state.assignmentCount;
+ m_nonLHSCount = state.nonLHSCount;
+ m_nonTrivialExpressionCount = state.nonTrivialExpressionCount;
+
+ }
+
+
+ VM* m_vm;
+ const SourceCode* m_source;
+ ParserArena m_parserArena;
+ std::unique_ptr<LexerType> m_lexer;
+ FunctionParameters* m_parameters { nullptr };
+
+ bool m_hasStackOverflow;
+ String m_errorMessage;
+ JSToken m_token;
+ bool m_allowsIn;
+ JSTextPosition m_lastTokenEndPosition;
+ int m_assignmentCount;
+ int m_nonLHSCount;
+ bool m_syntaxAlreadyValidated;
+ int m_statementDepth;
+ int m_nonTrivialExpressionCount;
+ const Identifier* m_lastIdentifier;
+ const Identifier* m_lastFunctionName;
+ RefPtr<SourceProviderCache> m_functionCache;
+ SourceElements* m_sourceElements;
+ bool m_parsingBuiltin;
+ ConstructorKind m_defaultConstructorKind;
+ ThisTDZMode m_thisTDZMode;
+ VariableEnvironment m_varDeclarations;
+ DeclarationStacks::FunctionStack m_funcDeclarations;
+ Vector<RefPtr<UniquedStringImpl>> m_closedVariables;
+ CodeFeatures m_features;
+ int m_numConstants;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+ private:
+ int m_originalDepth;
+ int* m_depth;
+ };
+};
+
+
+template <typename LexerType>
+template <class ParsedNode>
+std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode)
+{
+ int errLine;
+ String errMsg;
+
+ if (ParsedNode::scopeIsFunction)
+ m_lexer->setIsReparsingFunction();
+
+ m_sourceElements = 0;
+
+ errLine = -1;
+ errMsg = String();
+
+ JSTokenLocation startLocation(tokenLocation());
+ ASSERT(m_source->startColumn() > 0);
+ unsigned startColumn = m_source->startColumn() - 1;
+
+ String parseError = parseInner(calleeName, parseMode);
+
+ int lineNumber = m_lexer->lineNumber();
+ bool lexError = m_lexer->sawError();
+ String lexErrorMessage = lexError ? m_lexer->getErrorMessage() : String();
+ ASSERT(lexErrorMessage.isNull() != lexError);
+ m_lexer->clear();
+
+ if (!parseError.isNull() || lexError) {
+ errLine = lineNumber;
+ errMsg = !lexErrorMessage.isNull() ? lexErrorMessage : parseError;
+ m_sourceElements = 0;
+ }
+
+ std::unique_ptr<ParsedNode> result;
+ if (m_sourceElements) {
+ JSTokenLocation endLocation;
+ endLocation.line = m_lexer->lineNumber();
+ endLocation.lineStartOffset = m_lexer->currentLineStartOffset();
+ endLocation.startOffset = m_lexer->currentOffset();
+ unsigned endColumn = endLocation.startOffset - endLocation.lineStartOffset;
+ result = std::make_unique<ParsedNode>(m_parserArena,
+ startLocation,
+ endLocation,
+ startColumn,
+ endColumn,
+ m_sourceElements,
+ m_varDeclarations,
+ m_funcDeclarations,
+ currentScope()->finalizeLexicalEnvironment(),
+ m_parameters,
+ *m_source,
+ m_features,
+ m_numConstants);
+ result->setLoc(m_source->firstLine(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset());
+ result->setEndOffset(m_lexer->currentOffset());
+ } else {
+ // We can never see a syntax error when reparsing a function, since we should have
+ // reported the error when parsing the containing program or eval code. So if we're
+ // parsing a function body node, we assume that what actually happened here is that
+ // we ran out of stack while parsing. If we see an error while parsing eval or program
+ // code we assume that it was a syntax error since running out of stack is much less
+ // likely, and we are currently unable to distinguish between the two cases.
+ if (isFunctionMetadataNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow)
+ error = ParserError(ParserError::StackOverflow, ParserError::SyntaxErrorNone, m_token);
+ else {
+ ParserError::SyntaxErrorType errorType = ParserError::SyntaxErrorIrrecoverable;
+ if (m_token.m_type == EOFTOK)
+ errorType = ParserError::SyntaxErrorRecoverable;
+ else if (m_token.m_type & UnterminatedErrorTokenFlag)
+ errorType = ParserError::SyntaxErrorUnterminatedLiteral;
+
+ if (isEvalNode<ParsedNode>())
+ error = ParserError(ParserError::EvalError, errorType, m_token, errMsg, errLine);
+ else
+ error = ParserError(ParserError::SyntaxError, errorType, m_token, errMsg, errLine);
+ }
+ }
+
+ return result;
+}
+
+template <class ParsedNode>
+std::unique_ptr<ParsedNode> parse(
+ VM* vm, const SourceCode& source,
+ const Identifier& name, JSParserBuiltinMode builtinMode,
+ JSParserStrictMode strictMode, SourceParseMode parseMode,
+ ParserError& error, JSTextPosition* positionBeforeLastNewline = nullptr,
+ ConstructorKind defaultConstructorKind = ConstructorKind::None,
+ ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded)
+{
+ SamplingRegion samplingRegion("Parsing");
+
+ ASSERT(!source.provider()->source().isNull());
+ if (source.provider()->source().is8Bit()) {
+ Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, parseMode, defaultConstructorKind, thisTDZMode);
+ std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
+ if (positionBeforeLastNewline)
+ *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+ if (builtinMode == JSParserBuiltinMode::Builtin) {
+ if (!result)
+ WTF::dataLog("Error compiling builtin: ", error.message(), "\n");
+ RELEASE_ASSERT(result);
+ result->setClosedVariables(parser.closedVariables());
+ }
+ return result;
+ }
+ ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string");
+ Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, parseMode, defaultConstructorKind, thisTDZMode);
+ std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode);
+ if (positionBeforeLastNewline)
+ *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+ return result;
+}
+
+} // namespace
+#endif
diff --git a/Source/JavaScriptCore/parser/ParserArena.cpp b/Source/JavaScriptCore/parser/ParserArena.cpp
new file mode 100644
index 000000000..a27688770
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ParserArena.h"
+
+#include "Nodes.h"
+#include "JSCInlines.h"
+
+namespace JSC {
+
+ParserArena::ParserArena()
+ : m_freeableMemory(0)
+ , m_freeablePoolEnd(0)
+{
+}
+
+inline void* ParserArena::freeablePool()
+{
+ ASSERT(m_freeablePoolEnd);
+ return m_freeablePoolEnd - freeablePoolSize;
+}
+
+inline void ParserArena::deallocateObjects()
+{
+ size_t size = m_deletableObjects.size();
+ for (size_t i = 0; i < size; ++i)
+ m_deletableObjects[i]->~ParserArenaDeletable();
+
+ if (m_freeablePoolEnd)
+ fastFree(freeablePool());
+
+ size = m_freeablePools.size();
+ for (size_t i = 0; i < size; ++i)
+ fastFree(m_freeablePools[i]);
+}
+
+ParserArena::~ParserArena()
+{
+ deallocateObjects();
+}
+
+void ParserArena::allocateFreeablePool()
+{
+ if (m_freeablePoolEnd)
+ m_freeablePools.append(freeablePool());
+
+ char* pool = static_cast<char*>(fastMalloc(freeablePoolSize));
+ m_freeableMemory = pool;
+ m_freeablePoolEnd = pool + freeablePoolSize;
+ ASSERT(freeablePool() == pool);
+}
+
+}
diff --git a/Source/JavaScriptCore/parser/ParserArena.h b/Source/JavaScriptCore/parser/ParserArena.h
new file mode 100644
index 000000000..2a7d44de7
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserArena_h
+#define ParserArena_h
+
+#include "CommonIdentifiers.h"
+#include "Identifier.h"
+#include <array>
+#include <wtf/SegmentedVector.h>
+
+namespace JSC {
+
+ class ParserArenaDeletable;
+
+ class IdentifierArena {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ IdentifierArena()
+ {
+ clear();
+ }
+
+ template <typename T>
+ ALWAYS_INLINE const Identifier& makeIdentifier(VM*, const T* characters, size_t length);
+ ALWAYS_INLINE const Identifier& makeEmptyIdentifier(VM*);
+ ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(VM*, const UChar* characters, size_t length);
+
+ const Identifier& makeNumericIdentifier(VM*, double number);
+
+ public:
+ static const int MaximumCachableCharacter = 128;
+ typedef SegmentedVector<Identifier, 64> IdentifierVector;
+ void clear()
+ {
+ m_identifiers.clear();
+ for (int i = 0; i < MaximumCachableCharacter; i++)
+ m_shortIdentifiers[i] = 0;
+ for (int i = 0; i < MaximumCachableCharacter; i++)
+ m_recentIdentifiers[i] = 0;
+ }
+
+ private:
+ IdentifierVector m_identifiers;
+ std::array<Identifier*, MaximumCachableCharacter> m_shortIdentifiers;
+ std::array<Identifier*, MaximumCachableCharacter> m_recentIdentifiers;
+ };
+
+ template <typename T>
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(VM* vm, const T* characters, size_t length)
+ {
+ if (!length)
+ return vm->propertyNames->emptyIdentifier;
+ if (characters[0] >= MaximumCachableCharacter) {
+ m_identifiers.append(Identifier::fromString(vm, characters, length));
+ return m_identifiers.last();
+ }
+ if (length == 1) {
+ if (Identifier* ident = m_shortIdentifiers[characters[0]])
+ return *ident;
+ m_identifiers.append(Identifier::fromString(vm, characters, length));
+ m_shortIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+ Identifier* ident = m_recentIdentifiers[characters[0]];
+ if (ident && Identifier::equal(ident->impl(), characters, length))
+ return *ident;
+ m_identifiers.append(Identifier::fromString(vm, characters, length));
+ m_recentIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeEmptyIdentifier(VM* vm)
+ {
+ return vm->propertyNames->emptyIdentifier;
+ }
+
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM* vm, const UChar* characters, size_t length)
+ {
+ if (!length)
+ return vm->propertyNames->emptyIdentifier;
+ if (characters[0] >= MaximumCachableCharacter) {
+ m_identifiers.append(Identifier::createLCharFromUChar(vm, characters, length));
+ return m_identifiers.last();
+ }
+ if (length == 1) {
+ if (Identifier* ident = m_shortIdentifiers[characters[0]])
+ return *ident;
+ m_identifiers.append(Identifier::fromString(vm, characters, length));
+ m_shortIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+ Identifier* ident = m_recentIdentifiers[characters[0]];
+ if (ident && Identifier::equal(ident->impl(), characters, length))
+ return *ident;
+ m_identifiers.append(Identifier::createLCharFromUChar(vm, characters, length));
+ m_recentIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+
+ inline const Identifier& IdentifierArena::makeNumericIdentifier(VM* vm, double number)
+ {
+ m_identifiers.append(Identifier::fromString(vm, String::numberToStringECMAScript(number)));
+ return m_identifiers.last();
+ }
+
+ class ParserArena {
+ WTF_MAKE_NONCOPYABLE(ParserArena);
+ public:
+ ParserArena();
+ ~ParserArena();
+
+ void swap(ParserArena& otherArena)
+ {
+ std::swap(m_freeableMemory, otherArena.m_freeableMemory);
+ std::swap(m_freeablePoolEnd, otherArena.m_freeablePoolEnd);
+ m_identifierArena.swap(otherArena.m_identifierArena);
+ m_freeablePools.swap(otherArena.m_freeablePools);
+ m_deletableObjects.swap(otherArena.m_deletableObjects);
+ }
+
+ void* allocateFreeable(size_t size)
+ {
+ ASSERT(size);
+ ASSERT(size <= freeablePoolSize);
+ size_t alignedSize = alignSize(size);
+ ASSERT(alignedSize <= freeablePoolSize);
+ if (UNLIKELY(static_cast<size_t>(m_freeablePoolEnd - m_freeableMemory) < alignedSize))
+ allocateFreeablePool();
+ void* block = m_freeableMemory;
+ m_freeableMemory += alignedSize;
+ return block;
+ }
+
+ void* allocateDeletable(size_t size)
+ {
+ ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(allocateFreeable(size));
+ m_deletableObjects.append(deletable);
+ return deletable;
+ }
+
+ IdentifierArena& identifierArena()
+ {
+ if (UNLIKELY (!m_identifierArena))
+ m_identifierArena = std::make_unique<IdentifierArena>();
+ return *m_identifierArena;
+ }
+
+ private:
+ static const size_t freeablePoolSize = 8000;
+
+ static size_t alignSize(size_t size)
+ {
+ return (size + sizeof(WTF::AllocAlignmentInteger) - 1) & ~(sizeof(WTF::AllocAlignmentInteger) - 1);
+ }
+
+ void* freeablePool();
+ void allocateFreeablePool();
+ void deallocateObjects();
+
+ char* m_freeableMemory;
+ char* m_freeablePoolEnd;
+
+ std::unique_ptr<IdentifierArena> m_identifierArena;
+ Vector<void*> m_freeablePools;
+ Vector<ParserArenaDeletable*> m_deletableObjects;
+ };
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/ParserError.h b/Source/JavaScriptCore/parser/ParserError.h
new file mode 100644
index 000000000..89a05ab42
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserError.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserError_h
+#define ParserError_h
+
+#include "Error.h"
+#include "ErrorHandlingScope.h"
+#include "ExceptionHelpers.h"
+#include "ParserTokens.h"
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class ParserError {
+public:
+ enum SyntaxErrorType {
+ SyntaxErrorNone,
+ SyntaxErrorIrrecoverable,
+ SyntaxErrorUnterminatedLiteral,
+ SyntaxErrorRecoverable
+ };
+
+ enum ErrorType {
+ ErrorNone,
+ StackOverflow,
+ EvalError,
+ OutOfMemory,
+ SyntaxError
+ };
+
+ ParserError()
+ : m_type(ErrorNone)
+ , m_syntaxErrorType(SyntaxErrorNone)
+ {
+ }
+
+ explicit ParserError(ErrorType type)
+ : m_type(type)
+ , m_syntaxErrorType(SyntaxErrorNone)
+ {
+ }
+
+ ParserError(ErrorType type, SyntaxErrorType syntaxError, JSToken token)
+ : m_token(token)
+ , m_type(type)
+ , m_syntaxErrorType(syntaxError)
+ {
+ }
+
+ ParserError(ErrorType type, SyntaxErrorType syntaxError, JSToken token, const String& msg, int line)
+ : m_token(token)
+ , m_message(msg)
+ , m_line(line)
+ , m_type(type)
+ , m_syntaxErrorType(syntaxError)
+ {
+ }
+
+ bool isValid() const { return m_type != ErrorNone; }
+ SyntaxErrorType syntaxErrorType() const { return m_syntaxErrorType; }
+ const JSToken& token() const { return m_token; }
+ const String& message() const { return m_message; }
+ int line() const { return m_line; }
+
+ JSObject* toErrorObject(
+ JSGlobalObject* globalObject, const SourceCode& source,
+ int overrideLineNumber = -1)
+ {
+ ExecState* exec = globalObject->globalExec();
+ switch (m_type) {
+ case ErrorNone:
+ return nullptr;
+ case SyntaxError:
+ return addErrorInfo(
+ exec,
+ createSyntaxError(exec, m_message),
+ overrideLineNumber == -1 ? m_line : overrideLineNumber, source);
+ case EvalError:
+ return createSyntaxError(exec, m_message);
+ case StackOverflow: {
+ ErrorHandlingScope errorScope(globalObject->vm());
+ return createStackOverflowError(exec);
+ }
+ case OutOfMemory:
+ return createOutOfMemoryError(exec);
+ }
+ CRASH();
+ return nullptr;
+ }
+
+private:
+ JSToken m_token;
+ String m_message;
+ int m_line { -1 };
+ ErrorType m_type;
+ SyntaxErrorType m_syntaxErrorType;
+};
+
+} // namespace JSC
+
+#endif // ParserError_h
diff --git a/Source/JavaScriptCore/parser/ParserFunctionInfo.h b/Source/JavaScriptCore/parser/ParserFunctionInfo.h
new file mode 100644
index 000000000..4c565aae6
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserFunctionInfo.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserFunctionInfo_h
+#define ParserFunctionInfo_h
+
+namespace JSC {
+
+template <class TreeBuilder>
+struct ParserFunctionInfo {
+ const Identifier* name = 0;
+ typename TreeBuilder::FormalParameterList parameters = 0;
+ typename TreeBuilder::FunctionBody body = 0;
+ unsigned parameterCount = 0;
+ unsigned startOffset = 0;
+ unsigned endOffset = 0;
+ int startLine = 0;
+ int endLine = 0;
+ unsigned bodyStartColumn = 0;
+};
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+template <class TreeBuilder>
+struct ParserClassInfo {
+ const Identifier* className = 0;
+};
+#endif
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/ParserModes.h b/Source/JavaScriptCore/parser/ParserModes.h
new file mode 100644
index 000000000..a65603805
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserModes.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef ParserModes_h
+#define ParserModes_h
+
+#include "Identifier.h"
+
+namespace JSC {
+
+enum class JSParserStrictMode { NotStrict, Strict };
+enum class JSParserBuiltinMode { NotBuiltin, Builtin };
+enum class JSParserCodeType { Program, Function, Module };
+
+enum class ConstructorKind { None, Base, Derived };
+enum class SuperBinding { Needed, NotNeeded };
+enum class ThisTDZMode { AlwaysCheck, CheckIfNeeded };
+
+enum ProfilerMode { ProfilerOff, ProfilerOn };
+enum DebuggerMode { DebuggerOff, DebuggerOn };
+
+enum FunctionMode { FunctionExpression, FunctionDeclaration };
+
+enum class SourceParseMode {
+ NormalFunctionMode,
+ GetterMode,
+ SetterMode,
+ MethodMode,
+ ArrowFunctionMode,
+ ProgramMode,
+ ModuleAnalyzeMode,
+ ModuleEvaluateMode
+};
+
+inline bool isFunctionParseMode(SourceParseMode parseMode)
+{
+ switch (parseMode) {
+ case SourceParseMode::NormalFunctionMode:
+ case SourceParseMode::GetterMode:
+ case SourceParseMode::SetterMode:
+ case SourceParseMode::MethodMode:
+ case SourceParseMode::ArrowFunctionMode:
+ return true;
+
+ case SourceParseMode::ProgramMode:
+ case SourceParseMode::ModuleAnalyzeMode:
+ case SourceParseMode::ModuleEvaluateMode:
+ return false;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+}
+
+inline bool isModuleParseMode(SourceParseMode parseMode)
+{
+ switch (parseMode) {
+ case SourceParseMode::ModuleAnalyzeMode:
+ case SourceParseMode::ModuleEvaluateMode:
+ return true;
+
+ case SourceParseMode::NormalFunctionMode:
+ case SourceParseMode::GetterMode:
+ case SourceParseMode::SetterMode:
+ case SourceParseMode::MethodMode:
+ case SourceParseMode::ArrowFunctionMode:
+ case SourceParseMode::ProgramMode:
+ return false;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+}
+
+inline bool isProgramParseMode(SourceParseMode parseMode)
+{
+ switch (parseMode) {
+ case SourceParseMode::ProgramMode:
+ return true;
+
+ case SourceParseMode::NormalFunctionMode:
+ case SourceParseMode::GetterMode:
+ case SourceParseMode::SetterMode:
+ case SourceParseMode::MethodMode:
+ case SourceParseMode::ArrowFunctionMode:
+ case SourceParseMode::ModuleAnalyzeMode:
+ case SourceParseMode::ModuleEvaluateMode:
+ return false;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+ return false;
+}
+
+inline bool functionNameIsInScope(const Identifier& name, FunctionMode functionMode)
+{
+ if (name.isNull())
+ return false;
+
+ if (functionMode != FunctionExpression)
+ return false;
+
+ return true;
+}
+
+inline bool functionNameScopeIsDynamic(bool usesEval, bool isStrictMode)
+{
+ // If non-strict eval is in play, a function gets a separate object in the scope chain for its name.
+ // This enables eval to declare and then delete a name that shadows the function's name.
+
+ if (!usesEval)
+ return false;
+
+ if (isStrictMode)
+ return false;
+
+ return true;
+}
+
+typedef unsigned CodeFeatures;
+
+const CodeFeatures NoFeatures = 0;
+const CodeFeatures EvalFeature = 1 << 0;
+const CodeFeatures ArgumentsFeature = 1 << 1;
+const CodeFeatures WithFeature = 1 << 2;
+const CodeFeatures CatchFeature = 1 << 3;
+const CodeFeatures ThisFeature = 1 << 4;
+const CodeFeatures StrictModeFeature = 1 << 5;
+const CodeFeatures ShadowsArgumentsFeature = 1 << 6;
+const CodeFeatures ModifiedParameterFeature = 1 << 7;
+const CodeFeatures ModifiedArgumentsFeature = 1 << 8;
+
+const CodeFeatures AllFeatures = EvalFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature | ModifiedParameterFeature;
+
+} // namespace JSC
+
+#endif // ParserModes_h
diff --git a/Source/JavaScriptCore/parser/ParserTokens.h b/Source/JavaScriptCore/parser/ParserTokens.h
new file mode 100644
index 000000000..3dfdc28a8
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserTokens.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserTokens_h
+#define ParserTokens_h
+
+#include "ParserModes.h"
+#include <limits.h>
+#include <stdint.h>
+
+namespace JSC {
+
+class Identifier;
+
+enum {
+ UnaryOpTokenFlag = 64,
+ KeywordTokenFlag = 128,
+ BinaryOpTokenPrecedenceShift = 8,
+ BinaryOpTokenAllowsInPrecedenceAdditionalShift = 4,
+ BinaryOpTokenPrecedenceMask = 15 << BinaryOpTokenPrecedenceShift,
+ ErrorTokenFlag = 1 << (BinaryOpTokenAllowsInPrecedenceAdditionalShift + BinaryOpTokenPrecedenceShift + 7),
+ UnterminatedErrorTokenFlag = ErrorTokenFlag << 1
+};
+
+#define BINARY_OP_PRECEDENCE(prec) (((prec) << BinaryOpTokenPrecedenceShift) | ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift)))
+#define IN_OP_PRECEDENCE(prec) ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift))
+
+enum JSTokenType {
+ NULLTOKEN = KeywordTokenFlag,
+ TRUETOKEN,
+ FALSETOKEN,
+ BREAK,
+ CASE,
+ DEFAULT,
+ FOR,
+ NEW,
+ VAR,
+ LET,
+ CONSTTOKEN,
+ CONTINUE,
+ FUNCTION,
+ RETURN,
+ IF,
+ THISTOKEN,
+ DO,
+ WHILE,
+ SWITCH,
+ WITH,
+ RESERVED,
+ RESERVED_IF_STRICT,
+ THROW,
+ TRY,
+ CATCH,
+ FINALLY,
+ DEBUGGER,
+ ELSE,
+ IMPORT,
+ EXPORT,
+#if ENABLE(ES6_CLASS_SYNTAX)
+ CLASSTOKEN,
+ EXTENDS,
+ SUPER,
+#else
+ CLASSTOKEN = RESERVED,
+ EXTENDS = RESERVED,
+ SUPER = RESERVED,
+#endif
+ OPENBRACE = 0,
+ CLOSEBRACE,
+ OPENPAREN,
+ CLOSEPAREN,
+ OPENBRACKET,
+ CLOSEBRACKET,
+ COMMA,
+ QUESTION,
+ INTEGER,
+ DOUBLE,
+ IDENT,
+ STRING,
+ TEMPLATE,
+ SEMICOLON,
+ COLON,
+ DOT,
+ EOFTOK,
+ EQUAL,
+ PLUSEQUAL,
+ MINUSEQUAL,
+ MULTEQUAL,
+ DIVEQUAL,
+ LSHIFTEQUAL,
+ RSHIFTEQUAL,
+ URSHIFTEQUAL,
+ ANDEQUAL,
+ MODEQUAL,
+ XOREQUAL,
+ OREQUAL,
+ DOTDOTDOT,
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ ARROWFUNCTION,
+#endif
+ 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 | KeywordTokenFlag,
+ VOIDTOKEN = 7 | UnaryOpTokenFlag | KeywordTokenFlag,
+ DELETETOKEN = 8 | UnaryOpTokenFlag | KeywordTokenFlag,
+ 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) | KeywordTokenFlag,
+ INTOKEN = 14 | IN_OP_PRECEDENCE(7) | KeywordTokenFlag,
+ 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),
+ ERRORTOK = 0 | ErrorTokenFlag,
+ UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK = 0 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_IDENTIFIER_ESCAPE_ERRORTOK = 1 | ErrorTokenFlag,
+ UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK = 2 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK = 3 | ErrorTokenFlag,
+ UNTERMINATED_MULTILINE_COMMENT_ERRORTOK = 4 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ UNTERMINATED_NUMERIC_LITERAL_ERRORTOK = 5 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_OCTAL_NUMBER_ERRORTOK = 6 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_NUMERIC_LITERAL_ERRORTOK = 7 | ErrorTokenFlag,
+ UNTERMINATED_STRING_LITERAL_ERRORTOK = 8 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_STRING_LITERAL_ERRORTOK = 9 | ErrorTokenFlag,
+ INVALID_PRIVATE_NAME_ERRORTOK = 10 | ErrorTokenFlag,
+ INVALID_HEX_NUMBER_ERRORTOK = 11 | ErrorTokenFlag,
+ INVALID_BINARY_NUMBER_ERRORTOK = 12 | ErrorTokenFlag,
+ UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK = 13 | ErrorTokenFlag | UnterminatedErrorTokenFlag,
+ INVALID_TEMPLATE_LITERAL_ERRORTOK = 14 | ErrorTokenFlag,
+};
+
+struct JSTextPosition {
+ JSTextPosition() : line(0), offset(0), lineStartOffset(0) { }
+ JSTextPosition(int _line, int _offset, int _lineStartOffset) : line(_line), offset(_offset), lineStartOffset(_lineStartOffset) { }
+ JSTextPosition(const JSTextPosition& other) : line(other.line), offset(other.offset), lineStartOffset(other.lineStartOffset) { }
+
+ JSTextPosition operator+(int adjustment) const { return JSTextPosition(line, offset + adjustment, lineStartOffset); }
+ JSTextPosition operator+(unsigned adjustment) const { return *this + static_cast<int>(adjustment); }
+ JSTextPosition operator-(int adjustment) const { return *this + (- adjustment); }
+ JSTextPosition operator-(unsigned adjustment) const { return *this + (- static_cast<int>(adjustment)); }
+
+ operator int() const { return offset; }
+
+ int line;
+ int offset;
+ int lineStartOffset;
+};
+
+union JSTokenData {
+ struct {
+ uint32_t line;
+ uint32_t offset;
+ uint32_t lineStartOffset;
+ };
+ double doubleValue;
+ const Identifier* ident;
+ struct {
+ const Identifier* cooked;
+ const Identifier* raw;
+ bool isTail;
+ };
+};
+
+struct JSTokenLocation {
+ JSTokenLocation() : line(0), lineStartOffset(0), startOffset(0) { }
+ JSTokenLocation(const JSTokenLocation& location)
+ {
+ line = location.line;
+ lineStartOffset = location.lineStartOffset;
+ startOffset = location.startOffset;
+ endOffset = location.endOffset;
+ }
+
+ int line;
+ unsigned lineStartOffset;
+ unsigned startOffset;
+ unsigned endOffset;
+};
+
+struct JSToken {
+ JSTokenType m_type;
+ JSTokenData m_data;
+ JSTokenLocation m_location;
+ JSTextPosition m_startPosition;
+ JSTextPosition m_endPosition;
+};
+
+} // namespace JSC
+
+#endif // ParserTokens_h
diff --git a/Source/JavaScriptCore/parser/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h
new file mode 100644
index 000000000..ad86c98c7
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ResultType.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ResultType_h
+#define ResultType_h
+
+namespace JSC {
+
+ struct ResultType {
+ friend struct OperandTypes;
+
+ typedef char Type;
+ static const Type TypeInt32 = 1;
+
+ static const Type TypeMaybeNumber = 0x04;
+ static const Type TypeMaybeString = 0x08;
+ static const Type TypeMaybeNull = 0x10;
+ static const Type TypeMaybeBool = 0x20;
+ static const Type TypeMaybeOther = 0x40;
+
+ static const Type TypeBits = TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther;
+
+ explicit ResultType(Type type)
+ : m_type(type)
+ {
+ }
+
+ bool isInt32()
+ {
+ return m_type & TypeInt32;
+ }
+
+ bool definitelyIsNumber()
+ {
+ return (m_type & TypeBits) == TypeMaybeNumber;
+ }
+
+ bool definitelyIsString()
+ {
+ return (m_type & TypeBits) == TypeMaybeString;
+ }
+
+ bool definitelyIsBoolean()
+ {
+ return (m_type & TypeBits) == TypeMaybeBool;
+ }
+
+ bool mightBeNumber()
+ {
+ return m_type & TypeMaybeNumber;
+ }
+
+ bool isNotNumber()
+ {
+ return !mightBeNumber();
+ }
+
+ static ResultType nullType()
+ {
+ return ResultType(TypeMaybeNull);
+ }
+
+ static ResultType booleanType()
+ {
+ return ResultType(TypeMaybeBool);
+ }
+
+ static ResultType numberType()
+ {
+ return ResultType(TypeMaybeNumber);
+ }
+
+ static ResultType numberTypeIsInt32()
+ {
+ return ResultType(TypeInt32 | TypeMaybeNumber);
+ }
+
+ static ResultType stringOrNumberType()
+ {
+ return ResultType(TypeMaybeNumber | TypeMaybeString);
+ }
+
+ static ResultType stringType()
+ {
+ return ResultType(TypeMaybeString);
+ }
+
+ static ResultType unknownType()
+ {
+ return ResultType(TypeBits);
+ }
+
+ static ResultType forAdd(ResultType op1, ResultType op2)
+ {
+ if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+ return numberType();
+ if (op1.definitelyIsString() || op2.definitelyIsString())
+ return stringType();
+ return stringOrNumberType();
+ }
+
+ // Unlike in C, a logical op produces the value of the
+ // last expression evaluated (and not true or false).
+ static ResultType forLogicalOp(ResultType op1, ResultType op2)
+ {
+ if (op1.definitelyIsBoolean() && op2.definitelyIsBoolean())
+ return booleanType();
+ if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+ return numberType();
+ if (op1.definitelyIsString() && op2.definitelyIsString())
+ return stringType();
+ return unknownType();
+ }
+
+ static ResultType forBitOp()
+ {
+ return numberTypeIsInt32();
+ }
+
+ private:
+ Type m_type;
+ };
+
+ struct OperandTypes
+ {
+ OperandTypes(ResultType first = ResultType::unknownType(), ResultType second = ResultType::unknownType())
+ {
+ // We have to initialize one of the int to ensure that
+ // the entire struct is initialized.
+ m_u.i = 0;
+ m_u.rds.first = first.m_type;
+ m_u.rds.second = second.m_type;
+ }
+
+ union {
+ struct {
+ ResultType::Type first;
+ ResultType::Type second;
+ } rds;
+ int i;
+ } m_u;
+
+ ResultType first()
+ {
+ return ResultType(m_u.rds.first);
+ }
+
+ ResultType second()
+ {
+ return ResultType(m_u.rds.second);
+ }
+
+ int toInt()
+ {
+ return m_u.i;
+ }
+ static OperandTypes fromInt(int value)
+ {
+ OperandTypes types;
+ types.m_u.i = value;
+ return types;
+ }
+ };
+
+} // namespace JSC
+
+#endif // ResultType_h
diff --git a/Source/JavaScriptCore/parser/SourceCode.cpp b/Source/JavaScriptCore/parser/SourceCode.cpp
new file mode 100644
index 000000000..8ef168dea
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceCode.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SourceCode.h"
+
+#include "JSCInlines.h"
+#include <wtf/text/CString.h>
+
+namespace JSC {
+
+CString SourceCode::toUTF8() const
+{
+ if (!m_provider)
+ return CString("", 0);
+
+ return m_provider->source().impl()->utf8ForRange(m_startChar, m_endChar - m_startChar);
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/parser/SourceCode.h b/Source/JavaScriptCore/parser/SourceCode.h
new file mode 100644
index 000000000..7f37ecf86
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceCode.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceCode_h
+#define SourceCode_h
+
+#include "SourceProvider.h"
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class SourceCode {
+ public:
+ SourceCode()
+ : m_provider(0)
+ , m_startChar(0)
+ , m_endChar(0)
+ , m_firstLine(0)
+ , m_startColumn(0)
+ {
+ }
+
+ SourceCode(WTF::HashTableDeletedValueType)
+ : m_provider(WTF::HashTableDeletedValue)
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider)
+ : m_provider(provider)
+ , m_startChar(0)
+ , m_endChar(m_provider->source().length())
+ , m_firstLine(1)
+ , m_startColumn(1)
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int firstLine, int startColumn)
+ : m_provider(provider)
+ , m_startChar(0)
+ , m_endChar(m_provider->source().length())
+ , m_firstLine(std::max(firstLine, 1))
+ , m_startColumn(std::max(startColumn, 1))
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine, int startColumn)
+ : m_provider(provider)
+ , m_startChar(start)
+ , m_endChar(end)
+ , m_firstLine(std::max(firstLine, 1))
+ , m_startColumn(std::max(startColumn, 1))
+ {
+ }
+
+ bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); }
+
+ String toString() const
+ {
+ if (!m_provider)
+ return String();
+ return m_provider->getRange(m_startChar, m_endChar);
+ }
+
+ CString toUTF8() const;
+
+ intptr_t providerID() const
+ {
+ if (!m_provider)
+ return SourceProvider::nullID;
+ return m_provider->asID();
+ }
+
+ bool isNull() const { return !m_provider; }
+ SourceProvider* provider() const { return m_provider.get(); }
+ int firstLine() const { return m_firstLine; }
+ int startColumn() const { return m_startColumn; }
+ int startOffset() const { return m_startChar; }
+ int endOffset() const { return m_endChar; }
+ int length() const { return m_endChar - m_startChar; }
+
+ SourceCode subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn);
+
+ private:
+ RefPtr<SourceProvider> m_provider;
+ int m_startChar;
+ int m_endChar;
+ int m_firstLine;
+ int m_startColumn;
+ };
+
+ inline SourceCode makeSource(const String& source, const String& url = String(), const TextPosition& startPosition = TextPosition::minimumPosition())
+ {
+ return SourceCode(StringSourceProvider::create(source, url, startPosition), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
+ }
+
+ inline SourceCode SourceCode::subExpression(unsigned openBrace, unsigned closeBrace, int firstLine, int startColumn)
+ {
+ startColumn += 1; // Convert to base 1.
+ return SourceCode(provider(), openBrace, closeBrace + 1, firstLine, startColumn);
+ }
+
+} // namespace JSC
+
+#endif // SourceCode_h
diff --git a/Source/JavaScriptCore/parser/SourceProvider.cpp b/Source/JavaScriptCore/parser/SourceProvider.cpp
new file mode 100644
index 000000000..19ffb3372
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProvider.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SourceProvider.h"
+
+#include "JSCInlines.h"
+#include <wtf/Lock.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+SourceProvider::SourceProvider(const String& url, const TextPosition& startPosition)
+ : m_url(url)
+ , m_startPosition(startPosition)
+ , m_validated(false)
+ , m_id(0)
+{
+}
+
+SourceProvider::~SourceProvider()
+{
+}
+
+static StaticLock providerIdLock;
+
+void SourceProvider::getID()
+{
+ LockHolder lock(&providerIdLock);
+ if (!m_id) {
+ static intptr_t nextProviderID = 0;
+ m_id = ++nextProviderID;
+ }
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/parser/SourceProvider.h b/Source/JavaScriptCore/parser/SourceProvider.h
new file mode 100644
index 000000000..c263a1390
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProvider.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProvider_h
+#define SourceProvider_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/text/TextPosition.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+ class SourceProvider : public RefCounted<SourceProvider> {
+ public:
+ static const intptr_t nullID = 1;
+
+ JS_EXPORT_PRIVATE SourceProvider(const String& url, const TextPosition& startPosition);
+
+ JS_EXPORT_PRIVATE virtual ~SourceProvider();
+
+ virtual const String& source() const = 0;
+ String getRange(int start, int end) const
+ {
+ return source().substringSharingImpl(start, end - start);
+ }
+
+ const String& url() { return m_url; }
+ TextPosition startPosition() const { return m_startPosition; }
+ intptr_t asID()
+ {
+ if (!m_id)
+ getID();
+ return m_id;
+ }
+
+ bool isValid() const { return m_validated; }
+ void setValid() { m_validated = true; }
+
+ private:
+
+ JS_EXPORT_PRIVATE void getID();
+ Vector<size_t>& lineStarts();
+
+ String m_url;
+ TextPosition m_startPosition;
+ bool m_validated : 1;
+ uintptr_t m_id : sizeof(uintptr_t) * 8 - 1;
+ };
+
+ class StringSourceProvider : public SourceProvider {
+ public:
+ static Ref<StringSourceProvider> create(const String& source, const String& url, const TextPosition& startPosition = TextPosition::minimumPosition())
+ {
+ return adoptRef(*new StringSourceProvider(source, url, startPosition));
+ }
+
+ virtual const String& source() const override
+ {
+ return m_source;
+ }
+
+ private:
+ StringSourceProvider(const String& source, const String& url, const TextPosition& startPosition)
+ : SourceProvider(url, startPosition)
+ , m_source(source)
+ {
+ }
+
+ String m_source;
+ };
+
+#if ENABLE(WEBASSEMBLY)
+ class WebAssemblySourceProvider : public SourceProvider {
+ public:
+ static Ref<WebAssemblySourceProvider> create(const Vector<uint8_t>& data, const String& url)
+ {
+ return adoptRef(*new WebAssemblySourceProvider(data, url));
+ }
+
+ virtual const String& source() const override
+ {
+ return m_source;
+ }
+
+ const Vector<uint8_t>& data() const
+ {
+ return m_data;
+ }
+
+ private:
+ WebAssemblySourceProvider(const Vector<uint8_t>& data, const String& url)
+ : SourceProvider(url, TextPosition::minimumPosition())
+ , m_source("[WebAssembly source]")
+ , m_data(data)
+ {
+ }
+
+ String m_source;
+ Vector<uint8_t> m_data;
+ };
+#endif
+
+} // namespace JSC
+
+#endif // SourceProvider_h
diff --git a/Source/JavaScriptCore/parser/SourceProviderCache.cpp b/Source/JavaScriptCore/parser/SourceProviderCache.cpp
new file mode 100644
index 000000000..d5958e8c4
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCache.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SourceProviderCache.h"
+
+#include "JSCInlines.h"
+
+namespace JSC {
+
+SourceProviderCache::~SourceProviderCache()
+{
+ clear();
+}
+
+void SourceProviderCache::clear()
+{
+ m_map.clear();
+}
+
+void SourceProviderCache::add(int sourcePosition, std::unique_ptr<SourceProviderCacheItem> item)
+{
+ m_map.add(sourcePosition, WTF::move(item));
+}
+
+}
diff --git a/Source/JavaScriptCore/parser/SourceProviderCache.h b/Source/JavaScriptCore/parser/SourceProviderCache.h
new file mode 100644
index 000000000..5070b2811
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCache.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProviderCache_h
+#define SourceProviderCache_h
+
+#include "SourceProviderCacheItem.h"
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+
+namespace JSC {
+
+class SourceProviderCache : public RefCounted<SourceProviderCache> {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ SourceProviderCache() { }
+ JS_EXPORT_PRIVATE ~SourceProviderCache();
+
+ JS_EXPORT_PRIVATE void clear();
+ void add(int sourcePosition, std::unique_ptr<SourceProviderCacheItem>);
+ const SourceProviderCacheItem* get(int sourcePosition) const { return m_map.get(sourcePosition); }
+
+private:
+ HashMap<int, std::unique_ptr<SourceProviderCacheItem>, WTF::IntHash<int>, WTF::UnsignedWithZeroKeyHashTraits<int>> m_map;
+};
+
+}
+
+#endif // SourceProviderCache_h
diff --git a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h
new file mode 100644
index 000000000..81d221b39
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProviderCacheItem_h
+#define SourceProviderCacheItem_h
+
+#include "ParserTokens.h"
+#include <wtf/Vector.h>
+#include <wtf/text/UniquedStringImpl.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+struct SourceProviderCacheItemCreationParameters {
+ unsigned functionNameStart;
+ unsigned lastTockenLine;
+ unsigned lastTockenStartOffset;
+ unsigned lastTockenEndOffset;
+ unsigned lastTockenLineStartOffset;
+ unsigned endFunctionOffset;
+ unsigned parameterCount;
+ bool needsFullActivation;
+ bool usesEval;
+ bool strictMode;
+ Vector<RefPtr<UniquedStringImpl>> usedVariables;
+ Vector<RefPtr<UniquedStringImpl>> writtenVariables;
+ bool isBodyArrowExpression { false };
+ JSTokenType tokenType { CLOSEBRACE };
+};
+
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
+#endif
+
+class SourceProviderCacheItem {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ static std::unique_ptr<SourceProviderCacheItem> create(const SourceProviderCacheItemCreationParameters&);
+ ~SourceProviderCacheItem();
+
+ JSToken endFunctionToken() const
+ {
+ JSToken token;
+ token.m_type = isBodyArrowExpression ? tokenType : CLOSEBRACE;
+ token.m_data.offset = lastTockenStartOffset;
+ token.m_location.startOffset = lastTockenStartOffset;
+ token.m_location.endOffset = lastTockenEndOffset;
+ token.m_location.line = lastTockenLine;
+ token.m_location.lineStartOffset = lastTockenLineStartOffset;
+ // token.m_location.sourceOffset is initialized once by the client. So,
+ // we do not need to set it here.
+ return token;
+ }
+
+ unsigned functionNameStart : 31;
+ bool needsFullActivation : 1;
+
+ unsigned endFunctionOffset : 31;
+ unsigned lastTockenLine : 31;
+ unsigned lastTockenStartOffset : 31;
+ unsigned lastTockenEndOffset: 31;
+ unsigned parameterCount;
+
+ bool usesEval : 1;
+
+ bool strictMode : 1;
+
+ unsigned lastTockenLineStartOffset;
+ unsigned usedVariablesCount;
+ unsigned writtenVariablesCount;
+
+ UniquedStringImpl** usedVariables() const { return const_cast<UniquedStringImpl**>(m_variables); }
+ UniquedStringImpl** writtenVariables() const { return const_cast<UniquedStringImpl**>(&m_variables[usedVariablesCount]); }
+ bool isBodyArrowExpression;
+ JSTokenType tokenType;
+
+private:
+ SourceProviderCacheItem(const SourceProviderCacheItemCreationParameters&);
+
+ UniquedStringImpl* m_variables[0];
+};
+
+inline SourceProviderCacheItem::~SourceProviderCacheItem()
+{
+ for (unsigned i = 0; i < usedVariablesCount + writtenVariablesCount; ++i)
+ m_variables[i]->deref();
+}
+
+inline std::unique_ptr<SourceProviderCacheItem> SourceProviderCacheItem::create(const SourceProviderCacheItemCreationParameters& parameters)
+{
+ size_t variableCount = parameters.writtenVariables.size() + parameters.usedVariables.size();
+ size_t objectSize = sizeof(SourceProviderCacheItem) + sizeof(UniquedStringImpl*) * variableCount;
+ void* slot = fastMalloc(objectSize);
+ return std::unique_ptr<SourceProviderCacheItem>(new (slot) SourceProviderCacheItem(parameters));
+}
+
+inline SourceProviderCacheItem::SourceProviderCacheItem(const SourceProviderCacheItemCreationParameters& parameters)
+ : functionNameStart(parameters.functionNameStart)
+ , needsFullActivation(parameters.needsFullActivation)
+ , endFunctionOffset(parameters.endFunctionOffset)
+ , lastTockenLine(parameters.lastTockenLine)
+ , lastTockenStartOffset(parameters.lastTockenStartOffset)
+ , lastTockenEndOffset(parameters.lastTockenEndOffset)
+ , parameterCount(parameters.parameterCount)
+ , usesEval(parameters.usesEval)
+ , strictMode(parameters.strictMode)
+ , lastTockenLineStartOffset(parameters.lastTockenLineStartOffset)
+ , usedVariablesCount(parameters.usedVariables.size())
+ , writtenVariablesCount(parameters.writtenVariables.size())
+ , isBodyArrowExpression(parameters.isBodyArrowExpression)
+ , tokenType(parameters.tokenType)
+{
+ unsigned j = 0;
+ for (unsigned i = 0; i < usedVariablesCount; ++i, ++j) {
+ m_variables[j] = parameters.usedVariables[i].get();
+ m_variables[j]->ref();
+ }
+ for (unsigned i = 0; i < writtenVariablesCount; ++i, ++j) {
+ m_variables[j] = parameters.writtenVariables[i].get();
+ m_variables[j]->ref();
+ }
+}
+
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+}
+
+#endif // SourceProviderCacheItem_h
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
new file mode 100644
index 000000000..0760c19eb
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SyntaxChecker_h
+#define SyntaxChecker_h
+
+#include "Lexer.h"
+#include "ParserFunctionInfo.h"
+#include "YarrSyntaxChecker.h"
+
+namespace JSC {
+
+class SyntaxChecker {
+public:
+ struct BinaryExprContext {
+ BinaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topBinaryExprs.append(m_context->m_topBinaryExpr);
+ m_context->m_topBinaryExpr = 0;
+ }
+ ~BinaryExprContext()
+ {
+ m_context->m_topBinaryExpr = m_context->m_topBinaryExprs.last();
+ m_context->m_topBinaryExprs.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topUnaryTokens.append(m_context->m_topUnaryToken);
+ m_context->m_topUnaryToken = 0;
+ }
+ ~UnaryExprContext()
+ {
+ m_context->m_topUnaryToken = m_context->m_topUnaryTokens.last();
+ m_context->m_topUnaryTokens.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+
+ SyntaxChecker(VM* , void*)
+ {
+ }
+
+ enum { NoneExpr = 0,
+ ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
+ ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
+ FunctionExpr, ClassExpr, SuperExpr, BracketExpr, DotExpr, CallExpr,
+ NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
+ ConditionalExpr, AssignmentExpr, TypeofExpr, NewTargetExpr,
+ DeleteExpr, ArrayLiteralExpr, BindingDestructuring,
+ ArrayDestructuring, ObjectDestructuring, SourceElementsResult,
+ FunctionBodyResult, SpreadExpr, ArgumentsResult,
+ PropertyListResult, ArgumentsListResult, ElementsListResult,
+ StatementResult, FormalParameterListResult, ClauseResult,
+ ClauseListResult, CommaExpr, DestructuringAssignment,
+ TemplateStringResult, TemplateStringListResult,
+ TemplateExpressionListResult, TemplateExpr,
+ TaggedTemplateExpr,
+ ModuleNameResult,
+ ImportSpecifierResult, ImportSpecifierListResult,
+ ExportSpecifierResult, ExportSpecifierListResult
+ };
+ typedef int ExpressionType;
+
+ typedef ExpressionType Expression;
+ typedef int SourceElements;
+ typedef int Arguments;
+ typedef ExpressionType Comma;
+ 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;
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ typedef int TemplateExpressionList;
+ typedef int TemplateString;
+ typedef int TemplateStringList;
+ typedef int TemplateLiteral;
+#endif
+ typedef int FormalParameterList;
+ typedef int FunctionBody;
+#if ENABLE(ES6_CLASS_SYNTAX)
+ typedef int ClassExpression;
+#endif
+ typedef int ModuleName;
+ typedef int ImportSpecifier;
+ typedef int ImportSpecifierList;
+ typedef int ExportSpecifier;
+ typedef int ExportSpecifierList;
+ typedef int Statement;
+ typedef int ClauseList;
+ typedef int Clause;
+ typedef int BinaryOperand;
+ typedef int DestructuringPattern;
+ typedef DestructuringPattern ArrayPattern;
+ typedef DestructuringPattern ObjectPattern;
+
+ static const bool CreatesAST = false;
+ static const bool NeedsFreeVariableInfo = false;
+ static const bool CanUseFunctionCache = true;
+ static const unsigned DontBuildKeywords = LexexFlagsDontBuildKeywords;
+ static const unsigned DontBuildStrings = LexerFlagsDontBuildStrings;
+
+ int createSourceElements() { return SourceElementsResult; }
+ ExpressionType makeFunctionCallNode(const JSTokenLocation&, int, int, int, int, int) { return CallExpr; }
+ ExpressionType createCommaExpr(const JSTokenLocation&, ExpressionType expr) { return expr; }
+ ExpressionType appendToCommaExpr(const JSTokenLocation&, ExpressionType& head, ExpressionType, ExpressionType next) { head = next; return next; }
+ ExpressionType makeAssignNode(const JSTokenLocation&, ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType makePrefixNode(const JSTokenLocation&, ExpressionType, Operator, int, int, int) { return PreExpr; }
+ ExpressionType makePostfixNode(const JSTokenLocation&, ExpressionType, Operator, int, int, int) { return PostExpr; }
+ ExpressionType makeTypeOfNode(const JSTokenLocation&, ExpressionType) { return TypeofExpr; }
+ ExpressionType makeDeleteNode(const JSTokenLocation&, ExpressionType, int, int, int) { return DeleteExpr; }
+ ExpressionType makeNegateNode(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+ ExpressionType makeBitwiseNotNode(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+ ExpressionType createLogicalNot(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+ ExpressionType createUnaryPlus(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+ ExpressionType createVoid(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+ ExpressionType createThisExpr(const JSTokenLocation&, ThisTDZMode) { return ThisExpr; }
+ ExpressionType createSuperExpr(const JSTokenLocation&) { return SuperExpr; }
+ ExpressionType createNewTargetExpr(const JSTokenLocation&) { return NewTargetExpr; }
+ ExpressionType createResolve(const JSTokenLocation&, const Identifier*, int) { return ResolveExpr; }
+ ExpressionType createObjectLiteral(const JSTokenLocation&) { return ObjectLiteralExpr; }
+ ExpressionType createObjectLiteral(const JSTokenLocation&, int) { return ObjectLiteralExpr; }
+ ExpressionType createArray(const JSTokenLocation&, int) { return ArrayLiteralExpr; }
+ ExpressionType createArray(const JSTokenLocation&, int, int) { return ArrayLiteralExpr; }
+ ExpressionType createDoubleExpr(const JSTokenLocation&, double) { return DoubleExpr; }
+ ExpressionType createIntegerExpr(const JSTokenLocation&, double) { return IntegerExpr; }
+ ExpressionType createString(const JSTokenLocation&, const Identifier*) { return StringExpr; }
+ ExpressionType createBoolean(const JSTokenLocation&, bool) { return BoolExpr; }
+ ExpressionType createNull(const JSTokenLocation&) { return NullExpr; }
+ ExpressionType createBracketAccess(const JSTokenLocation&, ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
+ ExpressionType createDotAccess(const JSTokenLocation&, ExpressionType, const Identifier*, int, int, int) { return DotExpr; }
+ ExpressionType createRegExp(const JSTokenLocation&, const Identifier& pattern, const Identifier&, int) { return Yarr::checkSyntax(pattern.string()) ? 0 : RegExpExpr; }
+ ExpressionType createNewExpr(const JSTokenLocation&, ExpressionType, int, int, int, int) { return NewExpr; }
+ ExpressionType createNewExpr(const JSTokenLocation&, ExpressionType, int, int) { return NewExpr; }
+ ExpressionType createConditionalExpr(const JSTokenLocation&, ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
+ ExpressionType createAssignResolve(const JSTokenLocation&, const Identifier&, ExpressionType, int, int, int, AssignmentContext) { return AssignmentExpr; }
+ ExpressionType createEmptyVarExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
+ ExpressionType createEmptyLetExpression(const JSTokenLocation&, const Identifier&) { return AssignmentExpr; }
+#if ENABLE(ES6_CLASS_SYNTAX)
+ ClassExpression createClassExpr(const JSTokenLocation&, const Identifier&, ExpressionType, ExpressionType, PropertyList, PropertyList) { return ClassExpr; }
+#endif
+ ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
+ int createFunctionMetadata(const JSTokenLocation&, const JSTokenLocation&, int, int, bool, int, int, int, ConstructorKind, unsigned, SourceParseMode) { return FunctionBodyResult; }
+ ExpressionType createArrowFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
+ void setFunctionNameStart(int, int) { }
+ int createArguments() { return ArgumentsResult; }
+ int createArguments(int) { return ArgumentsResult; }
+ ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return SpreadExpr; }
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ TemplateString createTemplateString(const JSTokenLocation&, const Identifier&, const Identifier&) { return TemplateStringResult; }
+ TemplateStringList createTemplateStringList(TemplateString) { return TemplateStringListResult; }
+ TemplateStringList createTemplateStringList(TemplateStringList, TemplateString) { return TemplateStringListResult; }
+ TemplateExpressionList createTemplateExpressionList(Expression) { return TemplateExpressionListResult; }
+ TemplateExpressionList createTemplateExpressionList(TemplateExpressionList, Expression) { return TemplateExpressionListResult; }
+ TemplateLiteral createTemplateLiteral(const JSTokenLocation&, TemplateStringList) { return TemplateExpr; }
+ TemplateLiteral createTemplateLiteral(const JSTokenLocation&, TemplateStringList, TemplateExpressionList) { return TemplateExpr; }
+ ExpressionType createTaggedTemplate(const JSTokenLocation&, ExpressionType, TemplateLiteral, int, int, int) { return TaggedTemplateExpr; }
+#endif
+
+ int createArgumentsList(const JSTokenLocation&, int) { return ArgumentsListResult; }
+ int createArgumentsList(const JSTokenLocation&, int, int) { return ArgumentsListResult; }
+ Property createProperty(const Identifier* name, int, PropertyNode::Type type, PropertyNode::PutType, bool complete, SuperBinding = SuperBinding::NotNeeded)
+ {
+ if (!complete)
+ return Property(type);
+ ASSERT(name);
+ return Property(name, type);
+ }
+ Property createProperty(VM* vm, ParserArena& parserArena, double name, int, PropertyNode::Type type, PropertyNode::PutType, bool complete)
+ {
+ if (!complete)
+ return Property(type);
+ return Property(&parserArena.identifierArena().makeNumericIdentifier(vm, name), type);
+ }
+ Property createProperty(int, int, PropertyNode::Type type, PropertyNode::PutType, bool)
+ {
+ return Property(type);
+ }
+ int createPropertyList(const JSTokenLocation&, Property) { return PropertyListResult; }
+ int createPropertyList(const JSTokenLocation&, Property, int) { return PropertyListResult; }
+ int createElementList(int, int) { return ElementsListResult; }
+ int createElementList(int, int, int) { return ElementsListResult; }
+ int createFormalParameterList() { return FormalParameterListResult; }
+ void appendParameter(int, DestructuringPattern, int) { }
+ int createClause(int, int) { return ClauseResult; }
+ int createClauseList(int) { return ClauseListResult; }
+ int createClauseList(int, int) { return ClauseListResult; }
+ int createFuncDeclStatement(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return StatementResult; }
+#if ENABLE(ES6_CLASS_SYNTAX)
+ int createClassDeclStatement(const JSTokenLocation&, ClassExpression,
+ const JSTextPosition&, const JSTextPosition&, int, int) { return StatementResult; }
+#endif
+ int createBlockStatement(const JSTokenLocation&, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createExprStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+ int createIfStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+ int createIfStatement(const JSTokenLocation&, int, int, int, int, int) { return StatementResult; }
+ int createForLoop(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createForInLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createForOfLoop(const JSTokenLocation&, int, int, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createEmptyStatement(const JSTokenLocation&) { return StatementResult; }
+ int createDeclarationStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+ int createReturnStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+ int createBreakStatement(const JSTokenLocation&, int, int) { return StatementResult; }
+ int createBreakStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
+ int createContinueStatement(const JSTokenLocation&, int, int) { return StatementResult; }
+ int createContinueStatement(const JSTokenLocation&, const Identifier*, int, int) { return StatementResult; }
+ int createTryStatement(const JSTokenLocation&, int, const Identifier*, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createSwitchStatement(const JSTokenLocation&, int, int, int, int, int, int, VariableEnvironment&) { return StatementResult; }
+ int createWhileStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+ int createWithStatement(const JSTokenLocation&, int, int, int, int, int, int) { return StatementResult; }
+ int createDoWhileStatement(const JSTokenLocation&, int, int, int, int) { return StatementResult; }
+ int createLabelStatement(const JSTokenLocation&, const Identifier*, int, int, int) { return StatementResult; }
+ int createThrowStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+ int createDebugger(const JSTokenLocation&, int, int) { return StatementResult; }
+ int createConstStatement(const JSTokenLocation&, int, int, int) { return StatementResult; }
+ int createModuleName(const JSTokenLocation&, const Identifier&) { return ModuleNameResult; }
+ ImportSpecifier createImportSpecifier(const JSTokenLocation&, const Identifier&, const Identifier&) { return ImportSpecifierResult; }
+ ImportSpecifierList createImportSpecifierList() { return ImportSpecifierListResult; }
+ void appendImportSpecifier(ImportSpecifierList, ImportSpecifier) { }
+ int createImportDeclaration(const JSTokenLocation&, ImportSpecifierList, ModuleName) { return StatementResult; }
+ int createExportAllDeclaration(const JSTokenLocation&, ModuleName) { return StatementResult; }
+ int createExportDefaultDeclaration(const JSTokenLocation&, int, const Identifier&) { return StatementResult; }
+ int createExportLocalDeclaration(const JSTokenLocation&, int) { return StatementResult; }
+ int createExportNamedDeclaration(const JSTokenLocation&, ExportSpecifierList, ModuleName) { return StatementResult; }
+ ExportSpecifier createExportSpecifier(const JSTokenLocation&, const Identifier&, const Identifier&) { return ExportSpecifierResult; }
+ ExportSpecifierList createExportSpecifierList() { return ExportSpecifierListResult; }
+ void appendExportSpecifier(ExportSpecifierList, ExportSpecifier) { }
+
+ int appendConstDecl(const JSTokenLocation&, int, const Identifier*, int) { return StatementResult; }
+ Property createGetterOrSetterProperty(const JSTokenLocation&, PropertyNode::Type type, bool strict, const Identifier* name, const ParserFunctionInfo<SyntaxChecker>&, SuperBinding)
+ {
+ ASSERT(name);
+ if (!strict)
+ return Property(type);
+ return Property(name, type);
+ }
+ Property createGetterOrSetterProperty(VM* vm, ParserArena& parserArena, const JSTokenLocation&, PropertyNode::Type type, bool strict, double name, const ParserFunctionInfo<SyntaxChecker>&, SuperBinding)
+ {
+ if (!strict)
+ return Property(type);
+ return Property(&parserArena.identifierArena().makeNumericIdentifier(vm, name), type);
+ }
+
+ void appendStatement(int, int) { }
+ int combineCommaNodes(const JSTokenLocation&, int, int) { return CommaExpr; }
+ int evalCount() const { return 0; }
+ void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool)
+ {
+ if (!m_topBinaryExpr)
+ m_topBinaryExpr = expr;
+ else
+ m_topBinaryExpr = BinaryExpr;
+ operandStackDepth++;
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth) { operatorStackDepth--; }
+ bool operatorStackHasHigherPrecedence(int&, int) { return true; }
+ BinaryOperand getFromOperandStack(int) { return m_topBinaryExpr; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount) { operandStackDepth -= amount; }
+ void appendBinaryOperation(const JSTokenLocation&, int& operandStackDepth, int&, BinaryOperand, BinaryOperand) { operandStackDepth++; }
+ void operatorStackAppend(int& operatorStackDepth, int, int) { operatorStackDepth++; }
+ int popOperandStack(int&) { int res = m_topBinaryExpr; m_topBinaryExpr = 0; return res; }
+
+ void appendUnaryToken(int& stackDepth, int tok, int) { stackDepth = 1; m_topUnaryToken = tok; }
+ int unaryTokenStackLastType(int&) { return m_topUnaryToken; }
+ JSTextPosition unaryTokenStackLastStart(int&) { return JSTextPosition(0, 0, 0); }
+ void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
+
+ void assignmentStackAppend(int, int, int, int, int, Operator) { }
+ int createAssignment(const JSTokenLocation&, int, int, int, int, int) { RELEASE_ASSERT_NOT_REACHED(); return AssignmentExpr; }
+ const Identifier* getName(const Property& property) const { return property.name; }
+ PropertyNode::Type getType(const Property& property) const { return property.type; }
+ bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+ ExpressionType createDestructuringAssignment(const JSTokenLocation&, int, ExpressionType)
+ {
+ return DestructuringAssignment;
+ }
+
+ ArrayPattern createArrayPattern(const JSTokenLocation&)
+ {
+ return ArrayDestructuring;
+ }
+ void appendArrayPatternSkipEntry(ArrayPattern, const JSTokenLocation&)
+ {
+ }
+ void appendArrayPatternEntry(ArrayPattern, const JSTokenLocation&, DestructuringPattern, int)
+ {
+ }
+ void appendArrayPatternRestEntry(ArrayPattern, const JSTokenLocation&, DestructuringPattern)
+ {
+ }
+ void finishArrayPattern(ArrayPattern, const JSTextPosition&, const JSTextPosition&, const JSTextPosition&)
+ {
+ }
+ ObjectPattern createObjectPattern(const JSTokenLocation&)
+ {
+ return ObjectDestructuring;
+ }
+ void appendObjectPatternEntry(ArrayPattern, const JSTokenLocation&, bool, const Identifier&, DestructuringPattern, int)
+ {
+ }
+ DestructuringPattern createBindingLocation(const JSTokenLocation&, const Identifier&, const JSTextPosition&, const JSTextPosition&, AssignmentContext)
+ {
+ return BindingDestructuring;
+ }
+
+ bool isBindingNode(DestructuringPattern pattern)
+ {
+ return pattern == BindingDestructuring;
+ }
+
+ void setEndOffset(int, int) { }
+ int endOffset(int) { return 0; }
+ void setStartOffset(int, int) { }
+
+private:
+ int m_topBinaryExpr;
+ int m_topUnaryToken;
+ Vector<int, 8> m_topBinaryExprs;
+ Vector<int, 8> m_topUnaryTokens;
+};
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.cpp b/Source/JavaScriptCore/parser/VariableEnvironment.cpp
new file mode 100644
index 000000000..ed055f98a
--- /dev/null
+++ b/Source/JavaScriptCore/parser/VariableEnvironment.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "VariableEnvironment.h"
+
+namespace JSC {
+
+void VariableEnvironment::markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier)
+{
+ auto findResult = m_map.find(identifier);
+ if (findResult != m_map.end())
+ findResult->value.setIsCaptured();
+}
+
+void VariableEnvironment::markVariableAsCaptured(const RefPtr<UniquedStringImpl>& identifier)
+{
+ auto findResult = m_map.find(identifier);
+ RELEASE_ASSERT(findResult != m_map.end());
+ findResult->value.setIsCaptured();
+}
+
+void VariableEnvironment::markAllVariablesAsCaptured()
+{
+ if (m_isEverythingCaptured)
+ return;
+
+ m_isEverythingCaptured = true; // For fast queries.
+ // We must mark every entry as captured for when we iterate through m_map and entry.isCaptured() is called.
+ for (auto iter = m_map.begin(), end = m_map.end(); iter != end; ++iter)
+ iter->value.setIsCaptured();
+}
+
+bool VariableEnvironment::hasCapturedVariables() const
+{
+ if (m_isEverythingCaptured)
+ return size() > 0;
+ for (auto entry : m_map) {
+ if (entry.value.isCaptured())
+ return true;
+ }
+ return false;
+}
+
+bool VariableEnvironment::captures(UniquedStringImpl* identifier) const
+{
+ if (m_isEverythingCaptured)
+ return true;
+
+ auto findResult = m_map.find(identifier);
+ if (findResult == m_map.end())
+ return false;
+ return findResult->value.isCaptured();
+}
+
+void VariableEnvironment::swap(VariableEnvironment& other)
+{
+ m_map.swap(other.m_map);
+ m_isEverythingCaptured = other.m_isEverythingCaptured;
+}
+
+void VariableEnvironment::markVariableAsImported(const RefPtr<UniquedStringImpl>& identifier)
+{
+ auto findResult = m_map.find(identifier);
+ RELEASE_ASSERT(findResult != m_map.end());
+ findResult->value.setIsImported();
+}
+
+void VariableEnvironment::markVariableAsExported(const RefPtr<UniquedStringImpl>& identifier)
+{
+ auto findResult = m_map.find(identifier);
+ RELEASE_ASSERT(findResult != m_map.end());
+ findResult->value.setIsExported();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.h b/Source/JavaScriptCore/parser/VariableEnvironment.h
new file mode 100644
index 000000000..5ed2a6bda
--- /dev/null
+++ b/Source/JavaScriptCore/parser/VariableEnvironment.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VariableEnvironment_h
+#define VariableEnvironment_h
+
+#include "Identifier.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/UniquedStringImpl.h>
+
+namespace JSC {
+
+struct VariableEnvironmentEntry {
+public:
+ ALWAYS_INLINE bool isCaptured() const { return m_bits & IsCaptured; }
+ ALWAYS_INLINE bool isConst() const { return m_bits & IsConst; }
+ ALWAYS_INLINE bool isVar() const { return m_bits & IsVar; }
+ ALWAYS_INLINE bool isLet() const { return m_bits & IsLet; }
+ ALWAYS_INLINE bool isExported() const { return m_bits & IsExported; }
+ ALWAYS_INLINE bool isImported() const { return m_bits & IsImported; }
+
+ ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
+ ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }
+ ALWAYS_INLINE void setIsVar() { m_bits |= IsVar; }
+ ALWAYS_INLINE void setIsLet() { m_bits |= IsLet; }
+ ALWAYS_INLINE void setIsExported() { m_bits |= IsExported; }
+ ALWAYS_INLINE void setIsImported() { m_bits |= IsImported; }
+
+ ALWAYS_INLINE void clearIsVar() { m_bits &= ~IsVar; }
+
+private:
+ enum Traits {
+ IsCaptured = 1 << 0,
+ IsConst = 1 << 1,
+ IsVar = 1 << 2,
+ IsLet = 1 << 3,
+ IsExported = 1 << 4,
+ IsImported = 1 << 5
+ };
+ uint8_t m_bits { 0 };
+};
+
+struct VariableEnvironmentEntryHashTraits : HashTraits<VariableEnvironmentEntry> {
+ static const bool needsDestruction = false;
+};
+
+class VariableEnvironment {
+private:
+ typedef HashMap<RefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map;
+public:
+ ALWAYS_INLINE Map::iterator begin() { return m_map.begin(); }
+ ALWAYS_INLINE Map::iterator end() { return m_map.end(); }
+ ALWAYS_INLINE Map::const_iterator begin() const { return m_map.begin(); }
+ ALWAYS_INLINE Map::const_iterator end() const { return m_map.end(); }
+ ALWAYS_INLINE Map::AddResult add(const RefPtr<UniquedStringImpl>& identifier) { return m_map.add(identifier, VariableEnvironmentEntry()); }
+ ALWAYS_INLINE Map::AddResult add(const Identifier& identifier) { return add(identifier.impl()); }
+ ALWAYS_INLINE unsigned size() const { return m_map.size(); }
+ ALWAYS_INLINE bool contains(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.contains(identifier); }
+ ALWAYS_INLINE bool remove(const RefPtr<UniquedStringImpl>& identifier) { return m_map.remove(identifier); }
+ void swap(VariableEnvironment& other);
+ void markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier);
+ void markVariableAsCaptured(const RefPtr<UniquedStringImpl>& identifier);
+ void markAllVariablesAsCaptured();
+ bool hasCapturedVariables() const;
+ bool captures(UniquedStringImpl* identifier) const;
+ void markVariableAsImported(const RefPtr<UniquedStringImpl>& identifier);
+ void markVariableAsExported(const RefPtr<UniquedStringImpl>& identifier);
+
+private:
+ Map m_map;
+ bool m_isEverythingCaptured { false };
+};
+
+} // namespace JSC
+
+#endif // VariableEnvironment_h