diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/parser/Parser.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/parser/Parser.h')
-rw-r--r-- | Source/JavaScriptCore/parser/Parser.h | 1571 |
1 files changed, 1259 insertions, 312 deletions
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h index b698ef936..d8f92c00f 100644 --- a/Source/JavaScriptCore/parser/Parser.h +++ b/Source/JavaScriptCore/parser/Parser.h @@ -20,44 +20,34 @@ * */ -#ifndef Parser_h -#define Parser_h +#pragma once -#include "Debugger.h" +#include "ExecutableInfo.h" #include "ExceptionHelpers.h" -#include "Executable.h" -#include "JSGlobalObject.h" #include "Lexer.h" +#include "ModuleScopeData.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/OwnPtr.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 FunctionBodyNode; +class FunctionMetadataNode; class FunctionParameters; class Identifier; class VM; -class ProgramNode; class SourceCode; +class SyntaxChecker; +struct DebuggerParseData; // Macros to make the more common TreeBuilder types a little less verbose #define TreeStatement typename TreeBuilder::Statement @@ -66,93 +56,168 @@ class SourceCode; #define TreeSourceElements typename TreeBuilder::SourceElements #define TreeClause typename TreeBuilder::Clause #define TreeClauseList typename TreeBuilder::ClauseList -#define TreeConstDeclList typename TreeBuilder::ConstDeclList #define TreeArguments typename TreeBuilder::Arguments #define TreeArgumentsList typename TreeBuilder::ArgumentsList #define TreeFunctionBody typename TreeBuilder::FunctionBody +#define TreeClassExpression typename TreeBuilder::ClassExpression #define TreeProperty typename TreeBuilder::Property #define TreePropertyList typename TreeBuilder::PropertyList -#define TreeDeconstructionPattern typename TreeBuilder::DeconstructionPattern +#define TreeDestructuringPattern typename TreeBuilder::DestructuringPattern COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens); enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode }; -enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; -enum FunctionParseMode { FunctionMode, GetterMode, SetterMode }; -enum DeconstructionKind { - DeconstructToVariables, - DeconstructToParameters, - DeconstructToExpressions +enum FunctionBodyType { ArrowFunctionBodyExpression, ArrowFunctionBodyBlock, StandardFunctionBodyBlock }; +enum class FunctionNameRequirements { None, Named, Unnamed }; + +enum class DestructuringKind { + DestructureToVariables, + DestructureToLet, + DestructureToConst, + DestructureToCatchParameters, + DestructureToParameters, + DestructureToExpressions }; -template <typename T> inline bool isEvalNode() { return false; } -template <> inline bool isEvalNode<EvalNode>() { return true; } +enum class DeclarationType { + VarDeclaration, + LetDeclaration, + ConstDeclaration +}; -struct DepthManager { - DepthManager(int* depth) - : m_originalDepth(*depth) - , m_depth(depth) - { - } +enum class DeclarationImportType { + Imported, + ImportedNamespace, + NotImported +}; - ~DepthManager() - { - *m_depth = m_originalDepth; - } +enum DeclarationResult { + Valid = 0, + InvalidStrictMode = 1 << 0, + InvalidDuplicateDeclaration = 1 << 1 +}; -private: - int m_originalDepth; - int* m_depth; +typedef uint8_t DeclarationResultMask; + +enum class DeclarationDefaultContext { + Standard, + ExportDefault, }; -struct ScopeLabelInfo { - ScopeLabelInfo(StringImpl* ident, bool isLoop) - : m_ident(ident) - , m_isLoop(isLoop) - { - } +template <typename T> inline bool isEvalNode() { return false; } +template <> inline bool isEvalNode<EvalNode>() { return true; } - StringImpl* m_ident; - bool m_isLoop; +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; +} +// _Any_ContextualKeyword includes keywords such as "let" or "yield", which have a specific meaning depending on the current parse mode +// or strict mode. These helpers allow to treat all contextual keywords as identifiers as required. +ALWAYS_INLINE static bool isAnyContextualKeyword(const JSToken& token) +{ + return token.m_type >= FirstContextualKeywordToken && token.m_type <= LastContextualKeywordToken; +} +ALWAYS_INLINE static bool isIdentifierOrAnyContextualKeyword(const JSToken& token) +{ + return token.m_type == IDENT || isAnyContextualKeyword(token); +} +// _Safe_ContextualKeyword includes only contextual keywords which can be treated as identifiers independently from parse mode. The exeption +// to this rule is `await`, but matchSpecIdentifier() always treats it as an identifier regardless. +ALWAYS_INLINE static bool isSafeContextualKeyword(const JSToken& token) +{ + return token.m_type >= FirstSafeContextualKeywordToken && token.m_type <= LastSafeContextualKeywordToken; +} + struct Scope { - Scope(const VM* vm, bool isFunction, bool strictMode) + WTF_MAKE_NONCOPYABLE(Scope); + +public: + Scope(const VM* vm, bool isFunction, bool isGenerator, bool strictMode, bool isArrowFunction, bool isAsyncFunction) : m_vm(vm) , m_shadowsArguments(false) , m_usesEval(false) , m_needsFullActivation(false) - , m_allowsNewDecls(true) + , m_hasDirectSuper(false) + , m_needsSuperBinding(false) + , m_allowsVarDeclarations(true) + , m_allowsLexicalDeclarations(true) , m_strictMode(strictMode) , m_isFunction(isFunction) + , m_isGenerator(isGenerator) + , m_isGeneratorBoundary(false) + , m_isArrowFunction(isArrowFunction) + , m_isArrowFunctionBoundary(false) + , m_isAsyncFunction(isAsyncFunction) + , m_isAsyncFunctionBoundary(false) + , m_isLexicalScope(false) , m_isFunctionBoundary(false) , m_isValidStrictMode(true) + , m_hasArguments(false) + , m_isEvalContext(false) + , m_hasNonSimpleParameterList(false) + , m_evalContextType(EvalContextType::None) + , m_constructorKind(static_cast<unsigned>(ConstructorKind::None)) + , m_expectedSuperBinding(static_cast<unsigned>(SuperBinding::NotNeeded)) , m_loopDepth(0) , m_switchDepth(0) + , m_innerArrowFunctionFeatures(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_allowsNewDecls(rhs.m_allowsNewDecls) - , m_strictMode(rhs.m_strictMode) - , m_isFunction(rhs.m_isFunction) - , m_isFunctionBoundary(rhs.m_isFunctionBoundary) - , m_isValidStrictMode(rhs.m_isValidStrictMode) - , m_loopDepth(rhs.m_loopDepth) - , m_switchDepth(rhs.m_switchDepth) + m_usedVariables.append(UniquedStringImplPtrSet()); + } + + Scope(Scope&& other) + : m_vm(other.m_vm) + , m_shadowsArguments(other.m_shadowsArguments) + , m_usesEval(other.m_usesEval) + , m_needsFullActivation(other.m_needsFullActivation) + , m_hasDirectSuper(other.m_hasDirectSuper) + , m_needsSuperBinding(other.m_needsSuperBinding) + , m_allowsVarDeclarations(other.m_allowsVarDeclarations) + , m_allowsLexicalDeclarations(other.m_allowsLexicalDeclarations) + , m_strictMode(other.m_strictMode) + , m_isFunction(other.m_isFunction) + , m_isGenerator(other.m_isGenerator) + , m_isGeneratorBoundary(other.m_isGeneratorBoundary) + , m_isArrowFunction(other.m_isArrowFunction) + , m_isArrowFunctionBoundary(other.m_isArrowFunctionBoundary) + , m_isAsyncFunction(other.m_isAsyncFunction) + , m_isAsyncFunctionBoundary(other.m_isAsyncFunctionBoundary) + , m_isLexicalScope(other.m_isLexicalScope) + , m_isFunctionBoundary(other.m_isFunctionBoundary) + , m_isValidStrictMode(other.m_isValidStrictMode) + , m_hasArguments(other.m_hasArguments) + , m_isEvalContext(other.m_isEvalContext) + , m_hasNonSimpleParameterList(other.m_hasNonSimpleParameterList) + , m_constructorKind(other.m_constructorKind) + , m_expectedSuperBinding(other.m_expectedSuperBinding) + , m_loopDepth(other.m_loopDepth) + , m_switchDepth(other.m_switchDepth) + , m_innerArrowFunctionFeatures(other.m_innerArrowFunctionFeatures) + , m_labels(WTFMove(other.m_labels)) + , m_declaredParameters(WTFMove(other.m_declaredParameters)) + , m_declaredVariables(WTFMove(other.m_declaredVariables)) + , m_lexicalVariables(WTFMove(other.m_lexicalVariables)) + , m_usedVariables(WTFMove(other.m_usedVariables)) + , m_closedVariableCandidates(WTFMove(other.m_closedVariableCandidates)) + , m_functionDeclarations(WTFMove(other.m_functionDeclarations)) { - if (rhs.m_labels) { - m_labels = adoptPtr(new 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->m_ident, it->m_isLoop)); - } } void startSwitch() { m_switchDepth++; } @@ -166,8 +231,8 @@ struct Scope { void pushLabel(const Identifier* label, bool isLoop) { if (!m_labels) - m_labels = adoptPtr(new LabelStack); - m_labels->append(ScopeLabelInfo(label->impl(), isLoop)); + m_labels = std::make_unique<LabelStack>(); + m_labels->append(ScopeLabelInfo { label->impl(), isLoop }); } void popLabel() @@ -182,162 +247,458 @@ struct Scope { if (!m_labels) return 0; for (int i = m_labels->size(); i > 0; i--) { - if (m_labels->at(i - 1).m_ident == label->impl()) + if (m_labels->at(i - 1).uid == label->impl()) return &m_labels->at(i - 1); } return 0; } - void setIsFunction() + void setSourceParseMode(SourceParseMode mode) { - m_isFunction = true; - m_isFunctionBoundary = true; + switch (mode) { + case SourceParseMode::AsyncArrowFunctionBodyMode: + setIsAsyncArrowFunctionBody(); + break; + + case SourceParseMode::AsyncFunctionBodyMode: + setIsAsyncFunctionBody(); + break; + + case SourceParseMode::GeneratorBodyMode: + setIsGenerator(); + break; + + case SourceParseMode::GeneratorWrapperFunctionMode: + setIsGeneratorFunction(); + break; + + case SourceParseMode::NormalFunctionMode: + case SourceParseMode::GetterMode: + case SourceParseMode::SetterMode: + case SourceParseMode::MethodMode: + setIsFunction(); + break; + + case SourceParseMode::ArrowFunctionMode: + setIsArrowFunction(); + break; + + case SourceParseMode::AsyncFunctionMode: + case SourceParseMode::AsyncMethodMode: + setIsAsyncFunction(); + break; + + case SourceParseMode::AsyncArrowFunctionMode: + setIsAsyncArrowFunction(); + break; + + case SourceParseMode::ProgramMode: + case SourceParseMode::ModuleAnalyzeMode: + case SourceParseMode::ModuleEvaluateMode: + break; + } + } + + bool isFunction() const { return m_isFunction; } + bool isFunctionBoundary() const { return m_isFunctionBoundary; } + bool isGenerator() const { return m_isGenerator; } + bool isGeneratorBoundary() const { return m_isGeneratorBoundary; } + bool isAsyncFunction() const { return m_isAsyncFunction; } + bool isAsyncFunctionBoundary() const { return m_isAsyncFunctionBoundary; } + + bool hasArguments() const { return m_hasArguments; } + + void setIsLexicalScope() + { + m_isLexicalScope = true; + m_allowsLexicalDeclarations = true; + } + bool isLexicalScope() { return m_isLexicalScope; } + bool usesEval() { return m_usesEval; } + + const HashSet<UniquedStringImpl*>& closedVariableCandidates() const { return m_closedVariableCandidates; } + 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; + } + + 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()) { + for (UniquedStringImpl* impl : m_closedVariableCandidates) + m_lexicalVariables.markVariableAsCapturedIfDefined(impl); + } + + // 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.get()); + } + } } - bool isFunction() { return m_isFunction; } - bool isFunctionBoundary() { return m_isFunctionBoundary; } - void declareCallee(const Identifier* ident) + DeclarationResultMask declareCallee(const Identifier* ident) { - m_declaredVariables.add(ident->string().impl()); + 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 result = DeclarationResult::Valid; + if (isEvalOrArgumentsIdentifier(m_vm, ident)) + result |= DeclarationResult::InvalidStrictMode; + return result; } - bool declareVariable(const Identifier* ident) + DeclarationResultMask declareVariable(const Identifier* ident) { - bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident; + ASSERT(m_allowsVarDeclarations); + DeclarationResultMask result = DeclarationResult::Valid; + bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident); m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; - m_declaredVariables.add(ident->string().impl()); - return isValidStrictMode; + auto addResult = m_declaredVariables.add(ident->impl()); + addResult.iterator->value.setIsVar(); + if (!isValidStrictMode) + result |= DeclarationResult::InvalidStrictMode; + if (m_lexicalVariables.contains(ident->impl())) + result |= DeclarationResult::InvalidDuplicateDeclaration; + return result; } - bool hasDeclaredVariable(const Identifier& ident) + DeclarationResultMask declareFunction(const Identifier* ident, bool declareAsVar, bool isSloppyModeHoistingCandidate) { - return m_declaredVariables.contains(ident.impl()); + ASSERT(m_allowsVarDeclarations || m_allowsLexicalDeclarations); + DeclarationResultMask result = DeclarationResult::Valid; + bool isValidStrictMode = !isEvalOrArgumentsIdentifier(m_vm, ident); + if (!isValidStrictMode) + result |= DeclarationResult::InvalidStrictMode; + m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; + auto addResult = declareAsVar ? m_declaredVariables.add(ident->impl()) : m_lexicalVariables.add(ident->impl()); + if (isSloppyModeHoistingCandidate) + addResult.iterator->value.setIsSloppyModeHoistingCandidate(); + if (declareAsVar) { + addResult.iterator->value.setIsVar(); + if (m_lexicalVariables.contains(ident->impl())) + result |= DeclarationResult::InvalidDuplicateDeclaration; + } else { + addResult.iterator->value.setIsLet(); + ASSERT_WITH_MESSAGE(!m_declaredVariables.size(), "We should only declare a function as a lexically scoped variable in scopes where var declarations aren't allowed. I.e, in strict mode and not at the top-level scope of a function or program."); + if (!addResult.isNewEntry) { + if (!isSloppyModeHoistingCandidate || !addResult.iterator->value.isFunction()) + result |= DeclarationResult::InvalidDuplicateDeclaration; + } + } + + addResult.iterator->value.setIsFunction(); + + return result; } - - bool hasDeclaredParameter(const Identifier& ident) + + void addSloppyModeHoistableFunctionCandidate(const Identifier* ident) { - return m_declaredParameters.contains(ident.impl()) || m_declaredVariables.contains(ident.impl()); + ASSERT(m_allowsVarDeclarations); + m_sloppyModeHoistableFunctionCandidates.add(ident->impl()); + } + + void appendFunction(FunctionMetadataNode* node) + { + ASSERT(node); + m_functionDeclarations.append(node); } + DeclarationStacks::FunctionStack&& takeFunctionDeclarations() { return WTFMove(m_functionDeclarations); } - void declareWrite(const Identifier* ident) + + DeclarationResultMask declareLexicalVariable(const Identifier* ident, bool isConstant, DeclarationImportType importType = DeclarationImportType::NotImported) { - ASSERT(m_strictMode); - m_writtenVariables.add(ident->impl()); + 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(); + else if (importType == DeclarationImportType::ImportedNamespace) { + addResult.iterator->value.setIsImported(); + addResult.iterator->value.setIsImportedNamespace(); + } + + if (!addResult.isNewEntry) + result |= DeclarationResult::InvalidDuplicateDeclaration; + if (!isValidStrictMode) + result |= DeclarationResult::InvalidStrictMode; + + return result; } - void preventNewDecls() { m_allowsNewDecls = false; } - bool allowsNewDecls() const { return m_allowsNewDecls; } + bool hasDeclaredVariable(const Identifier& ident) + { + return hasDeclaredVariable(ident.impl()); + } - bool declareParameter(const Identifier* ident) + bool hasDeclaredVariable(const RefPtr<UniquedStringImpl>& ident) { - bool isArguments = m_vm->propertyNames->arguments == *ident; - bool isValidStrictMode = m_declaredVariables.add(ident->string().impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments; - m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; - m_declaredParameters.add(ident->string().impl()); + auto iter = m_declaredVariables.find(ident.get()); + if (iter == m_declaredVariables.end()) + return false; + VariableEnvironmentEntry entry = iter->value; + return entry.isVar(); // The callee isn't a "var". + } - if (isArguments) - m_shadowsArguments = true; - return isValidStrictMode; + bool hasLexicallyDeclaredVariable(const RefPtr<UniquedStringImpl>& ident) const + { + return m_lexicalVariables.contains(ident.get()); } - enum BindingResult { - BindingFailed, - StrictBindingFailed, - BindingSucceeded - }; - BindingResult declareBoundParameter(const Identifier* ident) + ALWAYS_INLINE bool hasDeclaredParameter(const Identifier& ident) { - bool isArguments = m_vm->propertyNames->arguments == *ident; - bool newEntry = m_declaredVariables.add(ident->string().impl()).isNewEntry; - bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments; - m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; + return hasDeclaredParameter(ident.impl()); + } + + bool hasDeclaredParameter(const RefPtr<UniquedStringImpl>& ident) + { + return m_declaredParameters.contains(ident.get()) || hasDeclaredVariable(ident); + } - if (isArguments) - m_shadowsArguments = true; - if (!newEntry) - return BindingFailed; - return isValidStrictMode ? BindingSucceeded : StrictBindingFailed; + 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()); + bool isValidStrictMode = (addResult.isNewEntry || !addResult.iterator->value.isParameter()) + && m_vm->propertyNames->eval != *ident && !isArgumentsIdent; + addResult.iterator->value.clearIsVar(); + addResult.iterator->value.setIsParameter(); + 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; + } + + bool usedVariablesContains(UniquedStringImpl* impl) const + { + for (const UniquedStringImplPtrSet& set : m_usedVariables) { + if (set.contains(impl)) + return true; + } + return false; + } + template <typename Func> + void forEachUsedVariable(const Func& func) + { + for (const UniquedStringImplPtrSet& set : m_usedVariables) { + for (UniquedStringImpl* impl : set) + func(impl); + } + } void useVariable(const Identifier* ident, bool isEval) { + useVariable(ident->impl(), isEval); + } + void useVariable(UniquedStringImpl* impl, bool isEval) + { m_usesEval |= isEval; - m_usedVariables.add(ident->string().impl()); + m_usedVariables.last().add(impl); } + void pushUsedVariableSet() { m_usedVariables.append(UniquedStringImplPtrSet()); } + size_t currentUsedVariablesSize() { return m_usedVariables.size(); } + + void revertToPreviousUsedVariables(size_t size) { m_usedVariables.resize(size); } + void setNeedsFullActivation() { m_needsFullActivation = true; } + bool needsFullActivation() const { return m_needsFullActivation; } + bool isArrowFunctionBoundary() { return m_isArrowFunctionBoundary; } + bool isArrowFunction() { return m_isArrowFunction; } + + bool hasDirectSuper() const { return m_hasDirectSuper; } + bool setHasDirectSuper() { return std::exchange(m_hasDirectSuper, true); } + + bool needsSuperBinding() const { return m_needsSuperBinding; } + bool setNeedsSuperBinding() { return std::exchange(m_needsSuperBinding, true); } + + void setEvalContextType(EvalContextType evalContextType) { m_evalContextType = evalContextType; } + EvalContextType evalContextType() { return m_evalContextType; } + + InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures() { return m_innerArrowFunctionFeatures; } + + void setExpectedSuperBinding(SuperBinding superBinding) { m_expectedSuperBinding = static_cast<unsigned>(superBinding); } + SuperBinding expectedSuperBinding() const { return static_cast<SuperBinding>(m_expectedSuperBinding); } + void setConstructorKind(ConstructorKind constructorKind) { m_constructorKind = static_cast<unsigned>(constructorKind); } + ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); } + + void setInnerArrowFunctionUsesSuperCall() { m_innerArrowFunctionFeatures |= SuperCallInnerArrowFunctionFeature; } + void setInnerArrowFunctionUsesSuperProperty() { m_innerArrowFunctionFeatures |= SuperPropertyInnerArrowFunctionFeature; } + void setInnerArrowFunctionUsesEval() { m_innerArrowFunctionFeatures |= EvalInnerArrowFunctionFeature; } + void setInnerArrowFunctionUsesThis() { m_innerArrowFunctionFeatures |= ThisInnerArrowFunctionFeature; } + void setInnerArrowFunctionUsesNewTarget() { m_innerArrowFunctionFeatures |= NewTargetInnerArrowFunctionFeature; } + void setInnerArrowFunctionUsesArguments() { m_innerArrowFunctionFeatures |= ArgumentsInnerArrowFunctionFeature; } + + bool isEvalContext() const { return m_isEvalContext; } + void setIsEvalContext(bool isEvalContext) { m_isEvalContext = isEvalContext; } - bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) + void setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded() + { + ASSERT(m_isArrowFunction); + + if (m_usesEval) + setInnerArrowFunctionUsesEval(); + + if (usedVariablesContains(m_vm->propertyNames->arguments.impl())) + setInnerArrowFunctionUsesArguments(); + } + + void addClosedVariableCandidateUnconditionally(UniquedStringImpl* impl) + { + m_closedVariableCandidates.add(impl); + } + + 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)) - continue; - m_usedVariables.add(*ptr); - if (shouldTrackClosedVariables) - m_closedVariables.add(*ptr); - } - 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)) - continue; - m_writtenVariables.add(*ptr); + + { + UniquedStringImplPtrSet& destinationSet = m_usedVariables.last(); + for (const UniquedStringImplPtrSet& usedVariablesSet : nestedScope->m_usedVariables) { + for (UniquedStringImpl* impl : usedVariablesSet) { + if (nestedScope->m_declaredVariables.contains(impl) || nestedScope->m_lexicalVariables.contains(impl)) + continue; + + // "arguments" reference should be resolved at function boudary. + if (nestedScope->isFunctionBoundary() && nestedScope->hasArguments() && impl == m_vm->propertyNames->arguments.impl() && !nestedScope->isArrowFunctionBoundary()) + continue; + + destinationSet.add(impl); + // 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(impl); + } + } + } + // 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()) { + auto end = nestedScope->m_closedVariableCandidates.end(); + auto begin = nestedScope->m_closedVariableCandidates.begin(); + m_closedVariableCandidates.add(begin, end); + } + } + + void mergeInnerArrowFunctionFeatures(InnerArrowFunctionCodeFeatures arrowFunctionCodeFeatures) + { + m_innerArrowFunctionFeatures = m_innerArrowFunctionFeatures | arrowFunctionCodeFeatures; + } + + void getSloppyModeHoistedFunctions(UniquedStringImplPtrSet& sloppyModeHoistedFunctions) + { + for (UniquedStringImpl* function : m_sloppyModeHoistableFunctionCandidates) { + // ES6 Annex B.3.3. The only time we can't hoist a function is if a syntax error would + // be caused by declaring a var with that function's name or if we have a parameter with + // that function's name. Note that we would only cause a syntax error if we had a let/const/class + // variable with the same name. + if (!m_lexicalVariables.contains(function)) { + auto iter = m_declaredVariables.find(function); + bool isParameter = iter != m_declaredVariables.end() && iter->value.isParameter(); + if (!isParameter) { + auto addResult = m_declaredVariables.add(function); + addResult.iterator->value.setIsVar(); + sloppyModeHoistedFunctions.add(function); + } } } - - return true; } - void getCapturedVariables(IdentifierSet& capturedVariables, bool& modifiedParameter) + void getCapturedVars(IdentifierSet& capturedVariables) { if (m_needsFullActivation || m_usesEval) { - modifiedParameter = true; - capturedVariables.swap(m_declaredVariables); + for (auto& entry : m_declaredVariables) + capturedVariables.add(entry.key); return; } - for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) { - if (!m_declaredVariables.contains(*ptr)) + for (UniquedStringImpl* impl : m_closedVariableCandidates) { + // We refer to m_declaredVariables here directly instead of a hasDeclaredVariable because we want to mark the callee as captured. + if (!m_declaredVariables.contains(impl)) continue; - capturedVariables.add(*ptr); - } - modifiedParameter = false; - if (m_declaredParameters.size()) { - IdentifierSet::iterator end = m_writtenVariables.end(); - for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) { - if (!m_declaredParameters.contains(*ptr)) - continue; - modifiedParameter = true; - break; - } + capturedVariables.add(impl); } } void setStrictMode() { m_strictMode = true; } bool strictMode() const { return m_strictMode; } bool isValidStrictMode() const { return m_isValidStrictMode; } bool shadowsArguments() const { return m_shadowsArguments; } + void setHasNonSimpleParameterList() + { + m_isValidStrictMode = false; + m_hasNonSimpleParameterList = true; + } + bool hasNonSimpleParameterList() const { return m_hasNonSimpleParameterList; } - void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl>>& vector) + void copyCapturedVariablesToVector(const UniquedStringImplPtrSet& usedVariables, Vector<UniquedStringImpl*, 8>& vector) { - IdentifierSet::iterator end = capturedVariables.end(); - for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) { - if (m_declaredVariables.contains(*it)) + for (UniquedStringImpl* impl : usedVariables) { + if (m_declaredVariables.contains(impl) || m_lexicalVariables.contains(impl)) continue; - vector.append(*it); + vector.append(impl); } } - void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters) + void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters, const UniquedStringImplPtrSet& capturesFromParameterExpressions) { 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); + parameters.innerArrowFunctionFeatures = m_innerArrowFunctionFeatures; + parameters.needsSuperBinding = m_needsSuperBinding; + for (const UniquedStringImplPtrSet& set : m_usedVariables) + copyCapturedVariablesToVector(set, parameters.usedVariables); + + // FIXME: https://bugs.webkit.org/show_bug.cgi?id=156962 + // We add these unconditionally because we currently don't keep a separate + // declaration scope for a function's parameters and its var/let/const declarations. + // This is somewhat unfortunate and we should refactor to do this at some point + // because parameters logically form a parent scope to var/let/const variables. + // But because we don't do this, we must grab capture candidates from a parameter + // list before we parse the body of a function because the body's declarations + // might make us believe something isn't actually a capture candidate when it really + // is. + for (UniquedStringImpl* impl : capturesFromParameterExpressions) + parameters.usedVariables.append(impl); } void restoreFromSourceProviderCache(const SourceProviderCacheItem* info) @@ -345,33 +706,116 @@ struct Scope { ASSERT(m_isFunction); m_usesEval = info->usesEval; m_strictMode = info->strictMode; + m_innerArrowFunctionFeatures = info->innerArrowFunctionFeatures; m_needsFullActivation = info->needsFullActivation; + m_needsSuperBinding = info->needsSuperBinding; + UniquedStringImplPtrSet& destSet = m_usedVariables.last(); 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]); + destSet.add(info->usedVariables()[i]); } + class MaybeParseAsGeneratorForScope; + private: + void setIsFunction() + { + m_isFunction = true; + m_isFunctionBoundary = true; + m_hasArguments = true; + setIsLexicalScope(); + m_isGenerator = false; + m_isGeneratorBoundary = false; + m_isArrowFunctionBoundary = false; + m_isArrowFunction = false; + } + + void setIsGeneratorFunction() + { + setIsFunction(); + m_isGenerator = true; + } + + void setIsGenerator() + { + setIsFunction(); + m_isGenerator = true; + m_isGeneratorBoundary = true; + m_hasArguments = false; + } + + void setIsArrowFunction() + { + setIsFunction(); + m_isArrowFunctionBoundary = true; + m_isArrowFunction = true; + } + + void setIsAsyncArrowFunction() + { + setIsArrowFunction(); + m_isAsyncFunction = true; + } + + void setIsAsyncFunction() + { + setIsFunction(); + m_isAsyncFunction = true; + } + + void setIsAsyncFunctionBody() + { + setIsFunction(); + m_hasArguments = false; + m_isAsyncFunction = true; + m_isAsyncFunctionBoundary = true; + } + + void setIsAsyncArrowFunctionBody() + { + setIsArrowFunction(); + m_hasArguments = false; + m_isAsyncFunction = true; + m_isAsyncFunctionBoundary = true; + } + const VM* m_vm; - bool m_shadowsArguments : 1; - bool m_usesEval : 1; - bool m_needsFullActivation : 1; - bool m_allowsNewDecls : 1; - bool m_strictMode : 1; - bool m_isFunction : 1; - bool m_isFunctionBoundary : 1; - bool m_isValidStrictMode : 1; + bool m_shadowsArguments; + bool m_usesEval; + bool m_needsFullActivation; + bool m_hasDirectSuper; + bool m_needsSuperBinding; + bool m_allowsVarDeclarations; + bool m_allowsLexicalDeclarations; + bool m_strictMode; + bool m_isFunction; + bool m_isGenerator; + bool m_isGeneratorBoundary; + bool m_isArrowFunction; + bool m_isArrowFunctionBoundary; + bool m_isAsyncFunction; + bool m_isAsyncFunctionBoundary; + bool m_isLexicalScope; + bool m_isFunctionBoundary; + bool m_isValidStrictMode; + bool m_hasArguments; + bool m_isEvalContext; + bool m_hasNonSimpleParameterList; + EvalContextType m_evalContextType; + unsigned m_constructorKind; + unsigned m_expectedSuperBinding; int m_loopDepth; int m_switchDepth; + InnerArrowFunctionCodeFeatures m_innerArrowFunctionFeatures; typedef Vector<ScopeLabelInfo, 2> LabelStack; - OwnPtr<LabelStack> m_labels; - IdentifierSet m_declaredParameters; - IdentifierSet m_declaredVariables; - IdentifierSet m_usedVariables; - IdentifierSet m_closedVariables; - IdentifierSet m_writtenVariables; + std::unique_ptr<LabelStack> m_labels; + UniquedStringImplPtrSet m_declaredParameters; + VariableEnvironment m_declaredVariables; + VariableEnvironment m_lexicalVariables; + Vector<UniquedStringImplPtrSet, 6> m_usedVariables; + UniquedStringImplPtrSet m_sloppyModeHoistableFunctionCandidates; + HashSet<UniquedStringImpl*> m_closedVariableCandidates; + DeclarationStacks::FunctionStack m_functionDeclarations; }; typedef Vector<Scope, 10> ScopeStack; @@ -396,24 +840,41 @@ struct ScopeRef { return ScopeRef(m_scopeStack, m_index - 1); } + bool operator==(const ScopeRef& other) + { + ASSERT(other.m_scopeStack == m_scopeStack); + return m_index == other.m_index; + } + + bool operator!=(const ScopeRef& other) + { + return !(*this == other); + } + private: ScopeStack* m_scopeStack; unsigned m_index; }; +enum class ArgumentType { + Normal, + Spread +}; + template <typename LexerType> class Parser { WTF_MAKE_NONCOPYABLE(Parser); WTF_MAKE_FAST_ALLOCATED; public: - Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode); + Parser(VM*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, JSParserScriptMode, SourceParseMode, SuperBinding, ConstructorKind defaultConstructorKind = ConstructorKind::None, DerivedContextType = DerivedContextType::None, bool isEvalContext = false, EvalContextType = EvalContextType::None, DebuggerParseData* = nullptr); ~Parser(); template <class ParsedNode> - PassRefPtr<ParsedNode> parse(ParserError&); + std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode); JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); } + JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); } private: struct AllowInOverride { @@ -453,82 +914,362 @@ 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; + }; + + enum ExpressionErrorClass { + ErrorIndicatesNothing = 0, + ErrorIndicatesPattern, + ErrorIndicatesAsyncArrowFunction + }; + + struct ExpressionErrorClassifier { + ExpressionErrorClassifier(Parser* parser) + : m_class(ErrorIndicatesNothing) + , m_previous(parser->m_expressionErrorClassifier) + , m_parser(parser) + { + m_parser->m_expressionErrorClassifier = this; + } + + ~ExpressionErrorClassifier() + { + m_parser->m_expressionErrorClassifier = m_previous; + } + + void classifyExpressionError(ExpressionErrorClass classification) + { + if (m_class != ErrorIndicatesNothing) + return; + m_class = classification; + } + + void forceClassifyExpressionError(ExpressionErrorClass classification) + { + m_class = classification; + } + + void reclassifyExpressionError(ExpressionErrorClass oldClassification, ExpressionErrorClass classification) + { + if (m_class != oldClassification) + return; + m_class = classification; + } + + void propagateExpressionErrorClass() + { + if (m_previous) + m_previous->m_class = m_class; + } + + bool indicatesPossiblePattern() const { return m_class == ErrorIndicatesPattern; } + bool indicatesPossibleAsyncArrowFunction() const { return m_class == ErrorIndicatesAsyncArrowFunction; } + + private: + ExpressionErrorClass m_class; + ExpressionErrorClassifier* m_previous; + Parser* m_parser; + }; + + ALWAYS_INLINE void classifyExpressionError(ExpressionErrorClass classification) + { + if (m_expressionErrorClassifier) + m_expressionErrorClassifier->classifyExpressionError(classification); + } + + ALWAYS_INLINE void forceClassifyExpressionError(ExpressionErrorClass classification) + { + if (m_expressionErrorClassifier) + m_expressionErrorClassifier->forceClassifyExpressionError(classification); + } + + ALWAYS_INLINE void reclassifyExpressionError(ExpressionErrorClass oldClassification, ExpressionErrorClass classification) + { + if (m_expressionErrorClassifier) + m_expressionErrorClassifier->reclassifyExpressionError(oldClassification, classification); + } + + ALWAYS_INLINE DestructuringKind destructuringKindFromDeclarationType(DeclarationType type) + { + switch (type) { + case DeclarationType::VarDeclaration: + return DestructuringKind::DestructureToVariables; + case DeclarationType::LetDeclaration: + return DestructuringKind::DestructureToLet; + case DeclarationType::ConstDeclaration: + return DestructuringKind::DestructureToConst; + } + + RELEASE_ASSERT_NOT_REACHED(); + return DestructuringKind::DestructureToVariables; + } + + ALWAYS_INLINE const char* declarationTypeToVariableKind(DeclarationType type) + { + switch (type) { + case DeclarationType::VarDeclaration: + return "variable name"; + case DeclarationType::LetDeclaration: + case DeclarationType::ConstDeclaration: + return "lexical variable name"; + } + RELEASE_ASSERT_NOT_REACHED(); + return "invalid"; + } + + 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 upperScope(int n) + { + ASSERT(m_scopeStack.size() >= size_t(1 + n)); + return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1 - n); + } + ScopeRef currentScope() { return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1); } + + ScopeRef currentVariableScope() + { + unsigned i = m_scopeStack.size() - 1; + ASSERT(i < m_scopeStack.size()); + while (!m_scopeStack[i].allowsVarDeclarations()) { + i--; + ASSERT(i < m_scopeStack.size()); + } + return ScopeRef(&m_scopeStack, i); + } + + ScopeRef currentLexicalDeclarationScope() + { + unsigned i = m_scopeStack.size() - 1; + ASSERT(i < m_scopeStack.size()); + while (!m_scopeStack[i].allowsLexicalDeclarations()) { + i--; + ASSERT(i < m_scopeStack.size()); + } + + return ScopeRef(&m_scopeStack, i); + } + + ScopeRef currentFunctionScope() + { + unsigned i = m_scopeStack.size() - 1; + ASSERT(i < m_scopeStack.size()); + while (i && !m_scopeStack[i].isFunctionBoundary()) { + i--; + ASSERT(i < m_scopeStack.size()); + } + // When reaching the top level scope (it can be non function scope), we return it. + return ScopeRef(&m_scopeStack, i); + } + + ScopeRef closestParentOrdinaryFunctionNonLexicalScope() + { + unsigned i = m_scopeStack.size() - 1; + ASSERT(i < m_scopeStack.size() && m_scopeStack.size()); + while (i && (!m_scopeStack[i].isFunctionBoundary() || m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary() || m_scopeStack[i].isArrowFunctionBoundary())) + i--; + // When reaching the top level scope (it can be non ordinary function scope), we return it. + return ScopeRef(&m_scopeStack, i); + } ScopeRef pushScope() { bool isFunction = false; bool isStrict = false; + bool isGenerator = false; + bool isArrowFunction = false; + bool isAsyncFunction = false; if (!m_scopeStack.isEmpty()) { isStrict = m_scopeStack.last().strictMode(); isFunction = m_scopeStack.last().isFunction(); + isGenerator = m_scopeStack.last().isGenerator(); + isArrowFunction = m_scopeStack.last().isArrowFunction(); + isAsyncFunction = m_scopeStack.last().isAsyncFunction(); } - m_scopeStack.append(Scope(m_vm, isFunction, isStrict)); + m_scopeStack.constructAndAppend(m_vm, isFunction, isGenerator, isStrict, isArrowFunction, isAsyncFunction); return currentScope(); } - - bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables) + + void popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables) { ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1); ASSERT(m_scopeStack.size() > 1); - bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); + m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); + + if (m_scopeStack.last().isArrowFunction()) + m_scopeStack.last().setInnerArrowFunctionUsesEvalAndUseArgumentsIfNeeded(); + + if (!(m_scopeStack.last().isFunctionBoundary() && !m_scopeStack.last().isArrowFunctionBoundary())) + m_scopeStack[m_scopeStack.size() - 2].mergeInnerArrowFunctionFeatures(m_scopeStack.last().innerArrowFunctionFeatures()); + + if (!m_scopeStack.last().isFunctionBoundary() && m_scopeStack.last().needsFullActivation()) + m_scopeStack[m_scopeStack.size() - 2].setNeedsFullActivation(); m_scopeStack.removeLast(); - return result; } - bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables) + ALWAYS_INLINE void popScope(ScopeRef& scope, bool shouldTrackClosedVariables) { - return popScopeInternal(scope, shouldTrackClosedVariables); + popScopeInternal(scope, shouldTrackClosedVariables); } - bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables) + ALWAYS_INLINE void popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables) { scope.setPopped(); - return popScopeInternal(scope, shouldTrackClosedVariables); + popScopeInternal(scope, shouldTrackClosedVariables); + } + + ALWAYS_INLINE void popScope(AutoCleanupLexicalScope& cleanupScope, bool shouldTrackClosedVariables) + { + RELEASE_ASSERT(cleanupScope.isValid()); + ScopeRef& scope = cleanupScope.scope(); + cleanupScope.setPopped(); + popScopeInternal(scope, shouldTrackClosedVariables); } - bool declareVariable(const Identifier* ident) + DeclarationResultMask declareVariable(const Identifier* ident, DeclarationType type = DeclarationType::VarDeclaration, DeclarationImportType importType = DeclarationImportType::NotImported) { - unsigned i = m_scopeStack.size() - 1; - ASSERT(i < m_scopeStack.size()); - while (!m_scopeStack[i].allowsNewDecls()) { - i--; - ASSERT(i < m_scopeStack.size()); + if (type == DeclarationType::VarDeclaration) + return currentVariableScope()->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_lexer->isReparsingFunction() && m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident))) + return DeclarationResult::InvalidDuplicateDeclaration; + + return currentLexicalDeclarationScope()->declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration, importType); + } + + std::pair<DeclarationResultMask, ScopeRef> declareFunction(const Identifier* ident) + { + if (m_statementDepth == 1 || (!strictMode() && !currentScope()->isFunction())) { + // Functions declared at the top-most scope (both in sloppy and strict mode) are declared as vars + // for backwards compatibility. This allows us to declare functions with the same name more than once. + // In sloppy mode, we always declare functions as vars. + bool declareAsVar = true; + bool isSloppyModeHoistingCandidate = false; + ScopeRef variableScope = currentVariableScope(); + return std::make_pair(variableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), variableScope); + } + + if (!strictMode()) { + ASSERT(currentScope()->isFunction()); + + // Functions declared inside a function inside a nested block scope in sloppy mode are subject to this + // crazy rule defined inside Annex B.3.3 in the ES6 spec. It basically states that we will create + // the function as a local block scoped variable, but when we evaluate the block that the function is + // contained in, we will assign the function to a "var" variable only if declaring such a "var" wouldn't + // be a syntax error and if there isn't a parameter with the same name. (It would only be a syntax error if + // there are is a let/class/const with the same name). Note that this mean we only do the "var" hoisting + // binding if the block evaluates. For example, this means we wont won't perform the binding if it's inside + // the untaken branch of an if statement. + bool declareAsVar = false; + bool isSloppyModeHoistingCandidate = true; + ScopeRef lexicalVariableScope = currentLexicalDeclarationScope(); + ScopeRef varScope = currentVariableScope(); + varScope->addSloppyModeHoistableFunctionCandidate(ident); + ASSERT(varScope != lexicalVariableScope); + return std::make_pair(lexicalVariableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope); } - return m_scopeStack[i].declareVariable(ident); + + bool declareAsVar = false; + bool isSloppyModeHoistingCandidate = false; + ScopeRef lexicalVariableScope = currentLexicalDeclarationScope(); + return std::make_pair(lexicalVariableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope); } - + NEVER_INLINE bool hasDeclaredVariable(const Identifier& ident) { unsigned i = m_scopeStack.size() - 1; ASSERT(i < m_scopeStack.size()); - while (!m_scopeStack[i].allowsNewDecls()) { + while (!m_scopeStack[i].allowsVarDeclarations()) { i--; ASSERT(i < m_scopeStack.size()); } return m_scopeStack[i].hasDeclaredVariable(ident); } - + NEVER_INLINE bool hasDeclaredParameter(const Identifier& ident) { + // FIXME: hasDeclaredParameter() is not valid during reparsing of generator or async function bodies, because their formal + // parameters are declared in a scope unavailable during reparsing. Note that it is redundant to call this function during + // reparsing anyways, as the function is already guaranteed to be valid by the original parsing. + // https://bugs.webkit.org/show_bug.cgi?id=164087 + ASSERT(!m_lexer->isReparsingFunction()); + unsigned i = m_scopeStack.size() - 1; ASSERT(i < m_scopeStack.size()); - while (!m_scopeStack[i].allowsNewDecls()) { + while (!m_scopeStack[i].allowsVarDeclarations()) { + i--; + ASSERT(i < m_scopeStack.size()); + } + + if (m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary()) { + // The formal parameters which need to be verified for Generators and Async Function bodies occur + // in the outer wrapper function, so pick the outer scope here. i--; ASSERT(i < m_scopeStack.size()); } return m_scopeStack[i].hasDeclaredParameter(ident); } - void declareWrite(const Identifier* ident) + bool exportName(const Identifier& ident) { - if (!m_syntaxAlreadyValidated || strictMode()) - m_scopeStack.last().declareWrite(ident); + ASSERT(currentScope().index() == 0); + ASSERT(m_moduleScopeData); + return m_moduleScopeData->exportName(ident); } - + ScopeStack m_scopeStack; const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos) @@ -537,14 +1278,13 @@ private: } Parser(); - String parseInner(); + String parseInner(const Identifier&, SourceParseMode); - void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, - ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures, int, IdentifierSet&); + void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, CodeFeatures, int); // Used to determine type of error to report. - bool isFunctionBodyNode(ScopeNode*) { return false; } - bool isFunctionBodyNode(FunctionBodyNode*) { return true; } + bool isFunctionMetadataNode(ScopeNode*) { return false; } + bool isFunctionMetadataNode(FunctionMetadataNode*) { return true; } ALWAYS_INLINE void next(unsigned lexerFlags = 0) { @@ -580,9 +1320,9 @@ private: } void printUnexpectedTokenText(WTF::PrintStream&); - ALWAYS_INLINE String getToken() { - SourceProvider* sourceProvider = m_source->provider(); - return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset); + ALWAYS_INLINE StringView getToken() + { + return m_lexer->getToken(m_token); } ALWAYS_INLINE bool match(JSTokenType expected) @@ -590,9 +1330,14 @@ private: return m_token.m_type == expected; } - ALWAYS_INLINE bool isofToken() + ALWAYS_INLINE bool matchContextualKeyword(const Identifier& identifier) + { + return m_token.m_type == IDENT && *m_token.m_data.ident == identifier; + } + + ALWAYS_INLINE bool matchIdentifierOrKeyword() { - return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of; + return isIdentifierOrKeyword(m_token); } ALWAYS_INLINE unsigned tokenStart() @@ -630,23 +1375,21 @@ private: return m_token.m_location; } - void setErrorMessage(String msg) + void setErrorMessage(const String& message) { - m_errorMessage = msg; + ASSERT_WITH_MESSAGE(!message.isEmpty(), "Attempted to set the empty string as an error message. Likely caused by invalid UTF8 used when creating the message."); + m_errorMessage = message; + if (m_errorMessage.isEmpty()) + m_errorMessage = ASCIILiteral("Unparseable script"); } 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&); + template <typename... Args> + NEVER_INLINE void logError(bool, Args&&...); - NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, String name, const char* afterMsg) + NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMessage, const String& name, const char* afterMessage) { - m_errorMessage = makeString(beforeMsg, " '", name, "' ", afterMsg); + m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage); } NEVER_INLINE void updateErrorMessage(const char* msg) @@ -655,16 +1398,32 @@ private: m_errorMessage = String(msg); ASSERT(!m_errorMessage.isNull()); } - + + ALWAYS_INLINE void recordPauseLocation(const JSTextPosition&); + ALWAYS_INLINE void recordFunctionEntryLocation(const JSTextPosition&); + ALWAYS_INLINE void recordFunctionLeaveLocation(const JSTextPosition&); + 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(); } - bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } - Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); } + bool isValidStrictMode() + { + int i = m_scopeStack.size() - 1; + if (!m_scopeStack[i].isValidStrictMode()) + return false; + + // In the case of Generator or Async function bodies, also check the wrapper function, whose name or + // arguments may be invalid. + if (UNLIKELY((m_scopeStack[i].isGeneratorBoundary() || m_scopeStack[i].isAsyncFunctionBoundary()) && i)) + return m_scopeStack[i - 1].isValidStrictMode(); + return true; + } + DeclarationResultMask declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); } + bool declareRestOrNormalParameter(const Identifier&, const Identifier**); + bool breakIsValid() { ScopeRef current = currentScope(); @@ -686,7 +1445,7 @@ private: return true; } void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); } - void popLabel() { currentScope()->popLabel(); } + void popLabel(ScopeRef scope) { scope->popLabel(); } ScopeLabelInfo* getLabel(const Identifier* label) { ScopeRef current = currentScope(); @@ -698,12 +1457,42 @@ private: } return result; } - + + // http://ecma-international.org/ecma-262/6.0/#sec-identifiers-static-semantics-early-errors + ALWAYS_INLINE bool isLETMaskedAsIDENT() + { + return match(LET) && !strictMode(); + } + + // http://ecma-international.org/ecma-262/6.0/#sec-identifiers-static-semantics-early-errors + ALWAYS_INLINE bool isYIELDMaskedAsIDENT(bool inGenerator) + { + return match(YIELD) && !strictMode() && !inGenerator; + } + + // http://ecma-international.org/ecma-262/6.0/#sec-generator-function-definitions-static-semantics-early-errors + ALWAYS_INLINE bool matchSpecIdentifier(bool inGenerator) + { + return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(inGenerator) || isSafeContextualKeyword(m_token); + } + + ALWAYS_INLINE bool matchSpecIdentifier() + { + return match(IDENT) || isLETMaskedAsIDENT() || isYIELDMaskedAsIDENT(currentScope()->isGenerator()) || isSafeContextualKeyword(m_token); + } + template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode); + template <class TreeBuilder> TreeSourceElements parseGeneratorFunctionSourceElements(TreeBuilder&, const Identifier& name, SourceElementsMode); + template <class TreeBuilder> TreeSourceElements parseAsyncFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode); + template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength); template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0); - template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&); - template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&); - template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&); + enum class ExportType { Exported, NotExported }; + template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard); + template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard); + template <class TreeBuilder> TreeStatement parseFunctionDeclarationStatement(TreeBuilder&, bool isAsync, bool parentAllowsFunctionDeclarationAsStatement); + template <class TreeBuilder> TreeStatement parseAsyncFunctionDeclaration(TreeBuilder&, ExportType = ExportType::NotExported, DeclarationDefaultContext = DeclarationDefaultContext::Standard); + template <class TreeBuilder> NEVER_INLINE bool maybeParseAsyncFunctionDeclarationStatement(TreeBuilder& context, TreeStatement& result, bool parentAllowsFunctionDeclarationAsStatement); + 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&); @@ -718,31 +1507,69 @@ private: 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 parseExpressionOrLabelStatement(TreeBuilder&, bool allowFunctionDeclarationAsStatement); template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&); template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&); template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&, ExpressionErrorClassifier&); template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseAssignmentExpressionOrPropagateErrorClass(TreeBuilder&); + template <class TreeBuilder> TreeExpression parseYieldExpression(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> NEVER_INLINE TreeExpression parseAwaitExpression(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> ALWAYS_INLINE TreeClassExpression parseClassExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseFunctionExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseAsyncFunctionExpression(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&); + template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArgument(TreeBuilder&, ArgumentType&); template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict); - template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&); - template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&); - template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd); - template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&); - - template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, DeconstructionKind, const Identifier&, int depth); - template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, DeconstructionKind, int depth = 0); - template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&); - template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn); + template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName, bool isGenerator, bool isAsyncMethod); + template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind, bool isClassProperty); + template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, SyntaxChecker&, const JSTokenLocation&, int, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, SuperBinding, FunctionBodyType, unsigned, SourceParseMode); + template <class TreeBuilder> ALWAYS_INLINE bool parseFormalParameters(TreeBuilder&, TreeFormalParameterList, bool isArrowFunction, 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&, bool isAsync); + template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, ExportType, const Identifier&, JSToken, AssignmentContext, const Identifier** duplicateIdentifier); + template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createAssignmentElement(TreeBuilder&, TreeExpression&, const JSTextPosition&, const JSTextPosition&); + template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseBindingOrAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth); + template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseAssignmentElement(TreeBuilder& context, DestructuringKind, ExportType, const Identifier** duplicateIdentifier, bool* hasDestructuringPattern, AssignmentContext bindingContext, int depth); + 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<std::pair<const Identifier*, const Identifier*>>& maybeExportedLocalNames, bool& hasKeywordForLocalBindings); + template <class TreeBuilder> TreeStatement parseExportDeclaration(TreeBuilder&); + + template <class TreeBuilder> ALWAYS_INLINE TreeExpression createResolveAndUseVariable(TreeBuilder&, const Identifier*, bool isEval, const JSTextPosition&, const JSTokenLocation&); + + enum class FunctionDefinitionType { Expression, Declaration, Method }; + template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionNameRequirements, SourceParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionDefinitionType); + + ALWAYS_INLINE bool isArrowFunctionParameters(); + + template <class TreeBuilder, class FunctionInfoType> NEVER_INLINE typename TreeBuilder::FormalParameterList parseFunctionParameters(TreeBuilder&, SourceParseMode, FunctionInfoType&); + template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::FormalParameterList createGeneratorParameters(TreeBuilder&, unsigned& parameterCount); + + template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionNameRequirements, ParserClassInfo<TreeBuilder>&); + + 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); + + template <class TreeBuilder> ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&); + ALWAYS_INLINE int isBinaryOperator(JSTokenType); bool allowAutomaticSemicolon(); @@ -770,82 +1597,179 @@ private: return !m_errorMessage.isNull(); } - struct SavePoint { + bool isDisallowedIdentifierAwait(const JSToken& token) + { + return token.m_type == AWAIT && (!m_parserState.allowAwait || currentScope()->isAsyncFunctionBoundary() || m_scriptMode == JSParserScriptMode::Module); + } + + ALWAYS_INLINE SuperBinding adjustSuperBindingForBaseConstructor(ConstructorKind constructorKind, SuperBinding superBinding, ScopeRef functionScope) + { + return adjustSuperBindingForBaseConstructor(constructorKind, superBinding, functionScope->needsSuperBinding(), functionScope->usesEval(), functionScope->innerArrowFunctionFeatures()); + } + + ALWAYS_INLINE SuperBinding adjustSuperBindingForBaseConstructor(ConstructorKind constructorKind, SuperBinding superBinding, bool scopeNeedsSuperBinding, bool currentScopeUsesEval, InnerArrowFunctionCodeFeatures innerArrowFunctionFeatures) + { + SuperBinding methodSuperBinding = superBinding; + + if (constructorKind == ConstructorKind::Base) { + bool isSuperUsedInInnerArrowFunction = innerArrowFunctionFeatures & SuperPropertyInnerArrowFunctionFeature; + methodSuperBinding = (scopeNeedsSuperBinding || isSuperUsedInInnerArrowFunction || currentScopeUsesEval) ? SuperBinding::Needed : SuperBinding::NotNeeded; + } + + return methodSuperBinding; + } + + const char* disallowedIdentifierAwaitReason() + { + if (!m_parserState.allowAwait || currentScope()->isAsyncFunctionBoundary()) + return "in an async function"; + if (m_scriptMode == JSParserScriptMode::Module) + return "in a module"; + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; + } + + enum class FunctionParsePhase { Parameters, Body }; + struct ParserState { + int assignmentCount { 0 }; + int nonLHSCount { 0 }; + int nonTrivialExpressionCount { 0 }; + FunctionParsePhase functionParsePhase { FunctionParsePhase::Body }; + const Identifier* lastIdentifier { nullptr }; + const Identifier* lastFunctionName { nullptr }; + bool allowAwait { true }; + }; + + // If you're using this directly, you probably should be using + // createSavePoint() instead. + ALWAYS_INLINE ParserState internalSaveParserState() + { + return m_parserState; + } + + ALWAYS_INLINE void restoreParserState(const ParserState& state) + { + m_parserState = state; + } + + struct LexerState { int startOffset; unsigned oldLineStartOffset; unsigned oldLastLineNumber; unsigned oldLineNumber; }; - - ALWAYS_INLINE SavePoint createSavePoint() + + // If you're using this directly, you probably should be using + // createSavePoint() instead. + // i.e, if you parse any kind of AssignmentExpression between + // saving/restoring, you should definitely not be using this directly. + ALWAYS_INLINE LexerState internalSaveLexerState() { - ASSERT(!hasError()); - SavePoint result; + LexerState 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(); + ASSERT(static_cast<unsigned>(result.startOffset) >= result.oldLineStartOffset); return result; } - - ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint) + + ALWAYS_INLINE void restoreLexerState(const LexerState& lexerState) { - m_errorMessage = String(); - m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset); + // setOffset clears lexer errors. + m_lexer->setOffset(lexerState.startOffset, lexerState.oldLineStartOffset); + m_lexer->setLineNumber(lexerState.oldLineNumber); next(); - m_lexer->setLastLineNumber(savePoint.oldLastLineNumber); - m_lexer->setLineNumber(savePoint.oldLineNumber); + m_lexer->setLastLineNumber(lexerState.oldLastLineNumber); } - struct ParserState { - int assignmentCount; - int nonLHSCount; - int nonTrivialExpressionCount; + struct SavePoint { + ParserState parserState; + LexerState lexerState; }; - ALWAYS_INLINE ParserState saveState() + struct SavePointWithError : public SavePoint { + bool lexerError; + String lexerErrorMessage; + String parserErrorMessage; + }; + + ALWAYS_INLINE void internalSaveState(SavePoint& savePoint) { - ParserState result; - result.assignmentCount = m_assignmentCount; - result.nonLHSCount = m_nonLHSCount; - result.nonTrivialExpressionCount = m_nonTrivialExpressionCount; - return result; + savePoint.parserState = internalSaveParserState(); + savePoint.lexerState = internalSaveLexerState(); } - ALWAYS_INLINE void restoreState(const ParserState& state) + ALWAYS_INLINE SavePointWithError createSavePointForError() { - m_assignmentCount = state.assignmentCount; - m_nonLHSCount = state.nonLHSCount; - m_nonTrivialExpressionCount = state.nonTrivialExpressionCount; - + SavePointWithError savePoint; + internalSaveState(savePoint); + savePoint.lexerError = m_lexer->sawError(); + savePoint.lexerErrorMessage = m_lexer->getErrorMessage(); + savePoint.parserErrorMessage = m_errorMessage; + return savePoint; } + ALWAYS_INLINE SavePoint createSavePoint() + { + ASSERT(!hasError()); + SavePoint savePoint; + internalSaveState(savePoint); + return savePoint; + } + + ALWAYS_INLINE void internalRestoreState(const SavePoint& savePoint) + { + restoreLexerState(savePoint.lexerState); + restoreParserState(savePoint.parserState); + } + + ALWAYS_INLINE void restoreSavePointWithError(const SavePointWithError& savePoint) + { + internalRestoreState(savePoint); + m_lexer->setSawError(savePoint.lexerError); + m_lexer->setErrorMessage(savePoint.lexerErrorMessage); + m_errorMessage = savePoint.parserErrorMessage; + } + + ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint) + { + internalRestoreState(savePoint); + m_errorMessage = String(); + } VM* m_vm; const SourceCode* m_source; - ParserArena* m_arena; - OwnPtr<LexerType> m_lexer; + ParserArena m_parserArena; + std::unique_ptr<LexerType> m_lexer; + FunctionParameters* m_parameters { nullptr }; + + ParserState m_parserState; 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; - ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; - ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; - IdentifierSet m_capturedVariables; + bool m_parsingBuiltin; + JSParserScriptMode m_scriptMode; + SuperBinding m_superBinding; + ConstructorKind m_defaultConstructorKind; + VariableEnvironment m_varDeclarations; + DeclarationStacks::FunctionStack m_funcDeclarations; + UniquedStringImplPtrSet m_sloppyModeHoistedFunctions; CodeFeatures m_features; int m_numConstants; - + ExpressionErrorClassifier* m_expressionErrorClassifier; + bool m_isEvalContext; + bool m_immediateParentAllowsFunctionDeclarationInStatement; + RefPtr<ModuleScopeData> m_moduleScopeData; + DebuggerParseData* m_debuggerParseData; + struct DepthManager { DepthManager(int* depth) : m_originalDepth(*depth) @@ -867,13 +1791,13 @@ private: template <typename LexerType> template <class ParsedNode> -PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error) +std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode) { int errLine; String errMsg; if (ParsedNode::scopeIsFunction) - m_lexer->setIsReparsing(); + m_lexer->setIsReparsingFunction(); m_sourceElements = 0; @@ -881,10 +1805,10 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error) errMsg = String(); JSTokenLocation startLocation(tokenLocation()); - ASSERT(m_source->startColumn() > 0); - unsigned startColumn = m_source->startColumn() - 1; + ASSERT(m_source->startColumn() > OrdinalNumber::beforeFirst()); + unsigned startColumn = m_source->startColumn().zeroBasedInt(); - String parseError = parseInner(); + String parseError = parseInner(calleeName, parseMode); int lineNumber = m_lexer->lineNumber(); bool lexError = m_lexer->sawError(); @@ -898,26 +1822,36 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error) m_sourceElements = 0; } - RefPtr<ParsedNode> result; + 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 = ParsedNode::create(m_vm, + result = std::make_unique<ParsedNode>(m_parserArena, startLocation, endLocation, startColumn, endColumn, m_sourceElements, - m_varDeclarations ? &m_varDeclarations->data : 0, - m_funcDeclarations ? &m_funcDeclarations->data : 0, - m_capturedVariables, + m_varDeclarations, + WTFMove(m_funcDeclarations), + currentScope()->finalizeLexicalEnvironment(), + WTFMove(m_sloppyModeHoistedFunctions), + m_parameters, *m_source, m_features, - m_numConstants); - result->setLoc(m_source->firstLine(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset()); + currentScope()->innerArrowFunctionFeatures(), + m_numConstants, + WTFMove(m_moduleScopeData)); + result->setLoc(m_source->firstLine().oneBasedInt(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset()); + result->setEndOffset(m_lexer->currentOffset()); + + if (!isFunctionParseMode(parseMode)) { + m_source->provider()->setSourceURLDirective(m_lexer->sourceURL()); + m_source->provider()->setSourceMappingURLDirective(m_lexer->sourceMappingURL()); + } } 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 @@ -925,14 +1859,19 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error) // 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 (isFunctionBodyNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow) + 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; + else if (m_token.m_type & UnterminatedErrorTokenFlag) { + // Treat multiline capable unterminated literals as recoverable. + if (m_token.m_type == UNTERMINATED_MULTILINE_COMMENT_ERRORTOK || m_token.m_type == UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK) + errorType = ParserError::SyntaxErrorRecoverable; + else + errorType = ParserError::SyntaxErrorUnterminatedLiteral; + } if (isEvalNode<ParsedNode>()) error = ParserError(ParserError::EvalError, errorType, m_token, errMsg, errLine); @@ -941,30 +1880,38 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error) } } - m_arena->reset(); - - return result.release(); + return result; } template <class ParsedNode> -PassRefPtr<ParsedNode> parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ParserError& error, JSTextPosition* positionBeforeLastNewline = 0) +std::unique_ptr<ParsedNode> parse( + VM* vm, const SourceCode& source, + const Identifier& name, JSParserBuiltinMode builtinMode, + JSParserStrictMode strictMode, JSParserScriptMode scriptMode, SourceParseMode parseMode, SuperBinding superBinding, + ParserError& error, JSTextPosition* positionBeforeLastNewline = nullptr, + ConstructorKind defaultConstructorKind = ConstructorKind::None, + DerivedContextType derivedContextType = DerivedContextType::None, + EvalContextType evalContextType = EvalContextType::None, + DebuggerParseData* debuggerParseData = nullptr) { - SamplingRegion samplingRegion("Parsing"); - ASSERT(!source.provider()->source().isNull()); if (source.provider()->source().is8Bit()) { - Parser<Lexer<LChar>> parser(vm, source, parameters, name, strictness, parserMode); - RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error); + Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData); + std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode); if (positionBeforeLastNewline) *positionBeforeLastNewline = parser.positionBeforeLastNewline(); - return result.release(); + if (builtinMode == JSParserBuiltinMode::Builtin) { + if (!result) + WTF::dataLog("Error compiling builtin: ", error.message(), "\n"); + } + return result; } - Parser<Lexer<UChar>> parser(vm, source, parameters, name, strictness, parserMode); - RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error); + ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string"); + Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKind, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData); + std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, name, parseMode); if (positionBeforeLastNewline) *positionBeforeLastNewline = parser.positionBeforeLastNewline(); - return result.release(); + return result; } } // namespace -#endif |