Untitled diff

Created Diff never expires
/*
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2006-2010, 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2003, 2006-2010, 2013, 2016 Apple Inc. All rights reserved.
*
*
* This library is free software; you can redistribute it and/or
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* version 2 of the License, or (at your option) any later version.
*
*
* This library is distributed in the hope that it will be useful,
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* Library General Public License for more details.
*
*
* You should have received a copy of the GNU Library General Public License
* 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
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
* Boston, MA 02110-1301, USA.
*
*
*/
*/


#include "config.h"
#include "config.h"
#include "Parser.h"
#include "Parser.h"


#include "ASTBuilder.h"
#include "ASTBuilder.h"
#include "DebuggerParseData.h"
#include "DebuggerParseData.h"
#include "JSCInlines.h"
#include "JSCInlines.h"
#include "VM.h"
#include "VM.h"
#include <utility>
#include <utility>
#include <wtf/SetForScope.h>
#include <wtf/SetForScope.h>
#include <wtf/StringPrintStream.h>
#include <wtf/StringPrintStream.h>


#define updateErrorMessage(shouldPrintToken, ...) do {\
#define updateErrorMessage(shouldPrintToken, ...) do {\
propagateError(); \
propagateError(); \
logError(shouldPrintToken, __VA_ARGS__); \
logError(shouldPrintToken, __VA_ARGS__); \
} while (0)
} while (0)


#define propagateError() do { if (UNLIKELY(hasError())) return 0; } while (0)
#define propagateError() do { if (UNLIKELY(hasError())) return 0; } while (0)
#define internalFailWithMessage(shouldPrintToken, ...) do { updateErrorMessage(shouldPrintToken, __VA_ARGS__); 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 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 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 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 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 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 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 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 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 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 matchOrFail(tokenType, ...) do { if (!match(tokenType)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0)
#define failIfStackOverflow() do { if (UNLIKELY(!canRecurse())) failWithStackOverflow(); } while (0)
#define failIfStackOverflow() do { if (UNLIKELY(!canRecurse())) failWithStackOverflow(); } while (0)
#define semanticFail(...) do { internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define semanticFail(...) do { internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define semanticFailIfTrue(cond, ...) do { if (UNLIKELY(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define semanticFailIfTrue(cond, ...) do { if (UNLIKELY(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define semanticFailIfFalse(cond, ...) do { if (UNLIKELY(!(cond))) internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define semanticFailIfFalse(cond, ...) do { if (UNLIKELY(!(cond))) internalFailWithMessage(false, __VA_ARGS__); } while (0)
#define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0)
#define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0)
#define failDueToUnexpectedToken() do {\
#define failDueToUnexpectedToken() do {\
logError(true);\
logError(true);\
return 0;\
return 0;\
} while (0)
} while (0)


#define handleProductionOrFail(token, tokenString, operation, production) do {\
#define handleProductionOrFail(token, tokenString, operation, production) do {\
consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " a ", production);\
consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " a ", production);\
} while (0)
} while (0)


#define handleProductionOrFail2(token, tokenString, operation, production) do {\
#define handleProductionOrFail2(token, tokenString, operation, production) do {\
consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " an ", production);\
consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " an ", production);\
} while (0)
} while (0)


#define semanticFailureDueToKeywordCheckingToken(token, ...) do { \
#define semanticFailureDueToKeywordCheckingToken(token, ...) do { \
if (strictMode() && token.m_type == RESERVED_IF_STRICT) \
if (strictMode() && token.m_type == RESERVED_IF_STRICT) \
semanticFail("Cannot use the reserved word '", getToken(token), "' as a ", __VA_ARGS__, " in strict mode"); \
semanticFail("Cannot use the reserved word '", getToken(token), "' as a ", __VA_ARGS__, " in strict mode"); \
if (token.m_type == RESERVED || token.m_type == RESERVED_IF_STRICT) \
if (token.m_type == RESERVED || token.m_type == RESERVED_IF_STRICT) \
semanticFail("Cannot use the reserved word '", getToken(token), "' as a ", __VA_ARGS__); \
semanticFail("Cannot use the reserved word '", getToken(token), "' as a ", __VA_ARGS__); \
if (token.m_type & KeywordTokenFlag) { \
if (token.m_type & KeywordTokenFlag) { \
if (!isAnyContextualKeyword(token)) \
if (!isAnyContextualKeyword(token)) \
semanticFail("Cannot use the keyword '", getToken(token), "' as a ", __VA_ARGS__); \
semanticFail("Cannot use the keyword '", getToken(token), "' as a ", __VA_ARGS__); \
if (isDisallowedIdentifierLet(token)) \
if (isDisallowedIdentifierLet(token)) \
semanticFail("Cannot use 'let' as a ", __VA_ARGS__, " ", disallowedIdentifierLetReason()); \
semanticFail("Cannot use 'let' as a ", __VA_ARGS__, " ", disallowedIdentifierLetReason()); \
if (isDisallowedIdentifierAwait(token)) \
if (isDisallowedIdentifierAwait(token)) \
semanticFail("Cannot use 'await' as a ", __VA_ARGS__, " ", disallowedIdentifierAwaitReason()); \
semanticFail("Cannot use 'await' as a ", __VA_ARGS__, " ", disallowedIdentifierAwaitReason()); \
if (isDisallowedIdentifierYield(token)) \
if (isDisallowedIdentifierYield(token)) \
semanticFail("Cannot use 'yield' as a ", __VA_ARGS__, " ", disallowedIdentifierYieldReason()); \
semanticFail("Cannot use 'yield' as a ", __VA_ARGS__, " ", disallowedIdentifierYieldReason()); \
} \
} \
} while (0)
} while (0)


#define semanticFailureDueToKeyword(...) semanticFailureDueToKeywordCheckingToken(m_token, __VA_ARGS__);
#define semanticFailureDueToKeyword(...) semanticFailureDueToKeywordCheckingToken(m_token, __VA_ARGS__);


using namespace std;
using namespace std;


namespace JSC {
namespace JSC {


template <typename LexerType>
template <typename LexerType>
void Parser<LexerType>::logError(bool)
void Parser<LexerType>::logError(bool)
{
{
if (hasError())
if (hasError())
return;
return;
StringPrintStream stream;
StringPrintStream stream;
printUnexpectedTokenText(stream);
printUnexpectedTokenText(stream);
setErrorMessage(stream.toStringWithLatin1Fallback());
setErrorMessage(stream.toStringWithLatin1Fallback());
}
}


template <typename LexerType> template <typename... Args>
template <typename LexerType> template <typename... Args>
void Parser<LexerType>::logError(bool shouldPrintToken, Args&&... args)
void Parser<LexerType>::logError(bool shouldPrintToken, Args&&... args)
{
{
if (hasError())
if (hasError())
return;
return;
StringPrintStream stream;
StringPrintStream stream;
if (shouldPrintToken) {
if (shouldPrintToken) {
printUnexpectedTokenText(stream);
printUnexpectedTokenText(stream);
stream.print(". ");
stream.print(". ");
}
}
stream.print(std::forward<Args>(args)..., ".");
stream.print(std::forward<Args>(args)..., ".");
setErrorMessage(stream.toStringWithLatin1Fallback());
setErrorMessage(stream.toStringWithLatin1Fallback());
}
}


template <typename LexerType>
template <typename LexerType>
Parser<LexerType>::Parser(VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, SourceParseMode parseMode, SuperBinding superBinding, ConstructorKind defaultConstructorKind, DerivedContextType derivedContextType, bool isEvalContext, EvalContextType evalContextType, DebuggerParseData* debuggerParseData)
Parser<LexerType>::Parser(VM* vm, const SourceCode& source, JSParserBuiltinMode builtinMode, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, SourceParseMode parseMode, SuperBinding superBinding, ConstructorKind defaultConstructorKind, DerivedContextType derivedContextType, bool isEvalContext, EvalContextType evalContextType, DebuggerParseData* debuggerParseData)
: m_vm(vm)
: m_vm(vm)
, m_source(&source)
, m_source(&source)
, m_hasStackOverflow(false)
, m_hasStackOverflow(false)
, m_allowsIn(true)
, m_allowsIn(true)
, m_syntaxAlreadyValidated(source.provider()->isValid())
, m_syntaxAlreadyValidated(source.provider()->isValid())
, m_statementDepth(0)
, m_statementDepth(0)
, m_sourceElements(0)
, m_sourceElements(0)
, m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
, m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin)
, m_scriptMode(scriptMode)
, m_scriptMode(scriptMode)
, m_superBinding(superBinding)
, m_superBinding(superBinding)
, m_defaultConstructorKind(defaultConstructorKind)
, m_defaultConstructorKind(defaultConstructorKind)
, m_immediateParentAllowsFunctionDeclarationInStatement(false)
, m_immediateParentAllowsFunctionDeclarationInStatement(false)
, m_debuggerParseData(debuggerParseData)
, m_debuggerParseData(debuggerParseData)
{
{
m_lexer = std::make_unique<LexerType>(vm, builtinMode, scriptMode);
m_lexer = std::make_unique<LexerType>(vm, builtinMode, scriptMode);
m_lexer->setCode(source, &m_parserArena);
m_lexer->setCode(source, &m_parserArena);
m_token.m_location.line = source.firstLine().oneBasedInt();
m_token.m_location.line = source.firstLine().oneBasedInt();
m_token.m_location.startOffset = source.startOffset();
m_token.m_location.startOffset = source.startOffset();
m_token.m_location.endOffset = source.startOffset();
m_token.m_location.endOffset = source.startOffset();
m_token.m_location.lineStartOffset = source.startOffset();
m_token.m_location.lineStartOffset = source.startOffset();
m_functionCache = vm->addSourceProviderCache(source.provider());
m_functionCache = vm->addSourceProviderCache(source.provider());
m_expressionErrorClassifier = nullptr;
m_expressionErrorClassifier = nullptr;


ScopeRef scope = pushScope();
ScopeRef scope = pushScope();
scope->setSourceParseMode(parseMode);
scope->setSourceParseMode(parseMode);
scope->setIsEvalContext(isEvalContext);
scope->setIsEvalContext(isEvalContext);
if (isEvalContext)
if (isEvalContext)
scope->setEvalContextType(evalContextType);
scope->setEvalContextType(evalContextType);
if (derivedContextType == DerivedContextType::DerivedConstructorContext) {
if (derivedContextType == DerivedContextType::DerivedConstructorContext) {
scope->setConstructorKind(ConstructorKind::Extends);
scope->setConstructorKind(ConstructorKind::Extends);
scope->setExpectedSuperBinding(SuperBinding::Needed);
scope->setExpectedSuperBinding(SuperBinding::Needed);
}
}
if (derivedContextType == DerivedContextType::DerivedMethodContext)
if (derivedContextType == DerivedContextType::DerivedMethodContext)
scope->setExpectedSuperBinding(SuperBinding::Needed);
scope->setExpectedSuperBinding(SuperBinding::Needed);


if (strictMode == JSParserStrictMode::Strict)
if (strictMode == JSParserStrictMode::Strict)
scope->setStrictMode();
scope->setStrictMode();


if (isModuleParseMode(parseMode))
if (isModuleParseMode(parseMode))
m_moduleScopeData = ModuleScopeData::create();
m_moduleScopeData = ModuleScopeData::create();


if (isProgramOrModuleParseMode(parseMode))
if (isProgramOrModuleParseMode(parseMode))
scope->setIsGlobalCodeScope();
scope->setIsGlobalCodeScope();


next();
next();
}
}


class Scope::MaybeParseAsGeneratorForScope : public SetForScope<bool> {
class Scope::MaybeParseAsGeneratorForScope : public SetForScope<bool> {
public:
public:
MaybeParseAsGeneratorForScope(ScopeRef& scope, bool shouldParseAsGenerator)
MaybeParseAsGeneratorForScope(ScopeRef& scope, bool shouldParseAsGenerator)
: SetForScope<bool>(scope->m_isGenerator, shouldParseAsGenerator) { }
: SetForScope<bool>(scope->m_isGenerator, shouldParseAsGenerator) { }
};
};


template <typename LexerType>
template <typename LexerType>
Parser<LexerType>::~Parser()
Parser<LexerType>::~Parser()
{
{
}
}


template <typename LexerType>
template <typename LexerType>
String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode)
String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode)
{
{
String parseError = String();
String parseError = String();


ASTBuilder context(const_cast<VM*>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source));
ASTBuilder context(const_cast<VM*>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source));
ScopeRef scope = currentScope();
ScopeRef scope = currentScope();
scope->setIsLexicalScope();
scope->setIsLexicalScope();
SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Body);
SetForScope<FunctionParsePhase> functionParsePhasePoisoner(m_parserState.functionParsePhase, FunctionParsePhase::Body);


bool isArrowFunctionBodyExpression = parseMode == SourceParseMode::AsyncArrowFunctionBodyMode && !match(OPENBRACE);
bool isArrowFunctionBodyExpression = parseMode == SourceParseMode::AsyncArrowFunctionBodyMode && !match(OPENBRACE);
if (m_lexer->isReparsingFunction()) {
if (m_lexer->isReparsingFunction()) {
ParserFunctionInfo<ASTBuilder> functionInfo;
ParserFunctionInfo<ASTBuilder> functionInfo;
if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
m_parameters = createGeneratorParameters(context, functionInfo.parameterCount);
m_parameters = createGeneratorParameters(context, functionInfo.parameterCount);
else
else
m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
m_parameters = parseFunctionParameters(context, parseMode, functionInfo);


if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && !hasError()) {
if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(parseMode) && !hasError()) {
// The only way we could have an error wile reparsing is if we run out of stack space.
// The only way we could have an error wile reparsing is if we run out of stack space.
RELEASE_ASSERT(match(ARROWFUNCTION));
RELEASE_ASSERT(match(ARROWFUNCTION));
next();
next();
isArrowFunctionBodyExpression = !match(OPENBRACE);
isArrowFunctionBodyExpression = !match(OPENBRACE);
}
}
}
}


if (!calleeName.isNull())
if (!calleeName.isNull())
scope->declareCallee(&calleeName);
scope->declareCallee(&calleeName);


if (m_lexer->isReparsingFunction())
if (m_lexer->isReparsingFunction())
m_statementDepth--;
m_statementDepth--;


SourceElements* sourceElements = nullptr;
SourceElements* sourceElements = nullptr;
// The only way we can error this early is if we reparse a function and we run out of stack space.
// The only way we can error this early is if we reparse a function and we run out of stack space.
if (!hasError()) {
if (!hasError()) {
if (isAsyncFunctionWrapperParseMode(parseMode))
if (isAsyncFunctionWrapperParseMode(parseMode))
sourceElements = parseAsyncFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
sourceElements = parseAsyncFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
else if (isArrowFunctionBodyExpression)
else if (isArrowFunctionBodyExpression)
sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
sourceElements = parseArrowFunctionSingleExpressionBodySourceElements(context);
else if (isModuleParseMode(parseMode))
else if (isModuleParseMode(parseMode))
sourceElements = parseModuleSourceElements(context, parseMode);
sourceElements = parseModuleSourceElements(context, parseMode);
else if (isGeneratorWrapperParseMode(parseMode))
else if (isGeneratorWrapperParseMode(parseMode))
sourceElements = parseGeneratorFunctionSourceElements(context, calleeName, CheckForStrictMode);
sourceElements = parseGeneratorFunctionSourceElements(context, calleeName, CheckForStrictMode);
else if (isAsyncGeneratorFunctionParseMode(parseMode))
else if (isAsyncGeneratorFunctionParseMode(parseMode))
sourceElements = parseAsyncGeneratorFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
sourceElements = parseAsyncGeneratorFunctionSourceElements(context, parseMode, isArrowFunctionBodyExpression, CheckForStrictMode);
else
else
sourceElements = parseSourceElements(context, CheckForStrictMode);
sourceElements = parseSourceElements(context, CheckForStrictMode);
}
}


bool validEnding = consume(EOFTOK);
bool validEnding = consume(EOFTOK);
if (!sourceElements || !validEnding) {
if (!sourceElements || !validEnding) {
if (hasError())
if (hasError())
parseError = m_errorMessage;
parseError = m_errorMessage;
else
else
parseError = ASCIILiteral("Parser error");
parseError = ASCIILiteral("Parser error");
}
}


IdentifierSet capturedVariables;
IdentifierSet capturedVariables;
UniquedStringImplPtrSet sloppyModeHoistedFunctions;
UniquedStringImplPtrSet sloppyModeHoistedFunctions;
scope->getSloppyModeHoistedFunctions(sloppyModeHoistedFunctions);
scope->getSloppyModeHoistedFunctions(sloppyModeHoistedFunctions);
scope->getCapturedVars(capturedVariables);
scope->getCapturedVars(capturedVariables);


VariableEnvironment& varDeclarations = scope->declaredVariables();
VariableEnvironment& varDeclarations = scope->declaredVariables();
for (auto& entry : capturedVariables)
for (auto& entry : capturedVariables)
varDeclarations.markVariableAsCaptured(entry);
varDeclarations.markVariableAsCaptured(entry);


if (isGeneratorWrapperParseMode(parseMode) || isAsyncFunctionOrAsyncGeneratorWrapperParseMode(parseMode)) {
if (isGeneratorWrapperParseMode(parseMode) || isAsyncFunctionOrAsyncGeneratorWrapperParseMode(parseMode)) {
if (scope->usedVariablesContains(m_vm->propertyNames->arguments.impl()))
if (scope->usedVariablesContains(m_vm->propertyNames->arguments.impl()))
context.propagateArgumentsUse();
context.propagateArgumentsUse();
}
}


CodeFeatures features = context.features();
CodeFeatures features = context.features();
if (scope->strictMode())
if (scope->strictMode())
features |= StrictModeFeature;
features |= StrictModeFeature;
if (scope->shadowsArguments())
if (scope->shadowsArguments())
features |= ShadowsArgumentsFeature;
features |= ShadowsArgumentsFeature;


#ifndef NDEBUG
#ifndef NDEBUG
if (m_parsingBuiltin && isProgramParseMode(parseMode)) {
if (m_parsingBuiltin && isProgramParseMode(parseMode)) {
VariableEnvironment& lexicalVariables = scope->lexicalVariables();
VariableEnvironment& lexicalVariables = scope->lexicalVariables();
const HashSet<UniquedStringImpl*>& closedVariableCandidates = scope->closedVariableCandidates();
const HashSet<UniquedStringImpl*>& closedVariableCandidates = scope->closedVariableCandidates();
for (UniquedStringImpl* candidate : closedVariableCandidates) {
for (UniquedStringImpl* candidate : closedVariableCandidates) {
if (!lexicalVariables.contains(candidate) && !varDeclarations.contains(candidate) && !candidate->isSymbol()) {
if (!lexicalVariables.contains(candidate) && !varDeclarations.contains(candidate) && !candidate->isSymbol()) {
dataLog("Bad global capture in builtin: '", candidate, "'\n");
dataLog("Bad global capture in builtin: '", candidate, "'\n");
dataLog(m_source->view());
dataLog(m_source->view());
CRASH();
CRASH();
}
}
}
}
}
}
#endif // NDEBUG
#endif // NDEBUG
didFinishParsing(sourceElements, scope->takeFunctionDeclarations(), varDeclarations, WTFMove(sloppyModeHoistedFunctions), features, context.numConstants());
didFinishParsing(sourceElements, scope->takeFunctionDeclarations(), varDeclarations, WTFMove(sloppyModeHoistedFunctions), features, context.numConstants());


return parseError;
return parseError;
}
}


template <typename LexerType>
template <typename LexerType>
void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::FunctionStack&& funcStack,
void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::FunctionStack&& funcStack,
VariableEnvironment& varDeclarations, UniquedStringImplPtrSet&& sloppyModeHoistedFunctions, CodeFeatures features, int numConstants)
VariableEnvironment& varDeclarations, UniquedStringImplPtrSet&& sloppyModeHoistedFunctions, CodeFeatures features, int numConstants)
{
{
m_sourceElements = sourceElements;
m_sourceElements = sourceElements;
m_funcDeclarations = WTFMove(funcStack);
m_funcDeclarations = WTFMove(funcStack);
m_varDeclarations.swap(varDeclarations);
m_varDeclarations.swap(varDeclarations);
m_features = features;
m_features = features;
m_sloppyModeHoistedFunctions = WTFMove(sloppyModeHoistedFunctions);
m_sloppyModeHoistedFunctions = WTFMove(sloppyModeHoistedFunctions);
m_numConstants = numConstants;
m_numConstants = numConstants;
}
}


template <typename LexerType>
template <typename LexerType>
bool Parser<LexerType>::isArrowFunctionParameters()
bool Parser<LexerType>::isArrowFunctionParameters()
{
{
if (match(OPENPAREN)) {
if (match(OPENPAREN)) {
SavePoint saveArrowFunctionPoint = createSavePoint();
SavePoint saveArrowFunctionPoint = createSavePoint();
next();
next();
bool isArrowFunction = false;
bool isArrowFunction = false;
if (match(CLOSEPAREN)) {
if (match(CLOSEPAREN)) {
next();
next();
isArrowFunction = match(ARROWFUNCTION);
isArrowFunction = match(ARROWFUNCTION);
} else {
} else {
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
// We make fake scope, otherwise parseFormalParameters will add variable to current scope that lead to errors
// We make fake scope, otherwise parseFormalParameters will add variable to current scope that lead to errors
AutoPopScopeRef fakeScope(this, pushScope());
AutoPopScopeRef fakeScope(this, pushScope());
fakeScope->setSourceParseMode(SourceParseMode::ArrowFunctionMode);
fakeScope->setSourceParseMode(SourceParseMode::ArrowFunctionMode);


unsigned parametersCount = 0;
unsigned parametersCount = 0;
bool isArrowFunctionParameterList = true;
bool isArrowFunctionParameterList = true;
bool isMethod = false;
bool isMethod = false;
isArrowFunction = parseFormalParameters(syntaxChecker, syntaxChecker.createFormalParameterList(), isArrowFunctionParameterList, isMethod, parametersCount) && consume(CLOSEPAREN) && match(ARROWFUNCTION);
isArrowFunction = parseFormalParameters(syntaxChecker, syntaxChecker.createFormalParameterList(), isArrowFunctionParameterList, isMethod, parametersCount) && consume(CLOSEPAREN) && match(ARROWFUNCTION);
propagateError();
propagateError();
popScope(fakeScope, syntaxChecker.NeedsFreeVariableInfo);
popScope(fakeScope, syntaxChecker.NeedsFreeVariableInfo);
}
}
restoreSavePoint(saveArrowFunctionPoint);
restoreSavePoint(saveArrowFunctionPoint);
return isArrowFunction;
return isArrowFunction;
}
}


if (matchSpecIdentifier()) {
if (matchSpecIdentifier()) {
SavePoint saveArrowFunctionPoint = createSavePoint();
SavePoint saveArrowFunctionPoint = createSavePoint();
next();
next();
bool isArrowFunction = match(ARROWFUNCTION);
bool isArrowFunction = match(ARROWFUNCTION);
restoreSavePoint(saveArrowFunctionPoint);
restoreSavePoint(saveArrowFunctionPoint);
return isArrowFunction;
return isArrowFunction;
}
}


return false;
return false;
}
}


template <typename LexerType>
template <typename LexerType>
bool Parser<LexerType>::allowAutomaticSemicolon()
bool Parser<LexerType>::allowAutomaticSemicolon()
{
{
return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
}
}


template <typename LexerType>
template <typename LexerType>
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context, SourceElementsMode mode)
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context, SourceElementsMode mode)
{
{
const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length
const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length
TreeSourceElements sourceElements = context.createSourceElements();
TreeSourceElements sourceElements = context.createSourceElements();
const Identifier* directive = 0;
const Identifier* directive = 0;
unsigned directiveLiteralLength = 0;
unsigned directiveLiteralLength = 0;
auto savePoint = createSavePoint();
auto savePoint = createSavePoint();
bool shouldCheckForUseStrict = mode == CheckForStrictMode;
bool shouldCheckForUseStrict = mode == CheckForStrictMode;
while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) {
if (shouldCheckForUseStrict) {
if (shouldCheckForUseStrict) {
if (directive) {
if (directive) {
// "use strict" must be the exact literal without escape sequences or line continuation.
// "use strict" must be the exact literal without escape sequences or line continuation.
if (directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) {
if (directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) {
setStrictMode();
setStrictMode();
shouldCheckForUseStrict = false; // We saw "use strict", there is no need to keep checking for it.
shouldCheckForUseStrict = false; // We saw "use strict", there is no need to keep checking for it.
if (!isValidStrictMode()) {
if (!isValidStrictMode()) {
if (m_parserState.lastFunctionName) {
if (m_parserState.lastFunctionName) {
if (m_vm->propertyNames->arguments == *m_parserState.lastFunctionName)
if (m_vm->propertyNames->arguments == *m_parserState.lastFunctionName)
semanticFail("Cannot name a function 'arguments' in strict mode");
semanticFail("Cannot name a function 'arguments' in strict mode");
if (m_vm->propertyNames->eval == *m_parserState.lastFunctionName)
if (m_vm->propertyNames->eval == *m_parserState.lastFunctionName)
semanticFail("Cannot name a function 'eval' in strict mode");
semanticFail("Cannot name a function 'eval' in strict mode");
}
}
if (hasDeclaredVariable(m_vm->propertyNames->arguments))
if (hasDeclaredVariable(m_vm->propertyNames->arguments))
semanticFail("Cannot declare a variable named 'arguments' in strict mode");
semanticFail("Cannot declare a variable named 'arguments' in strict mode");
if (hasDeclaredVariable(m_vm->propertyNames->eval))
if (hasDeclaredVariable(m_vm->propertyNames->eval))
semanticFail("Cannot declare a variable named 'eval' in strict mode");
semanticFail("Cannot declare a variable named 'eval' in strict mode");
semanticFailIfTrue(currentScope()->hasNonSimpleParameterList(), "'use strict' directive not allowed inside a function with a non-simple parameter list");
semanticFailIfTrue(currentScope()->hasNonSimpleParameterList(), "'use strict' directive not allowed inside a function with a non-simple parameter list");
semanticFailIfFalse(isValidStrictMode(), "Invalid parameters or function name in strict mode");
semanticFailIfFalse(isValidStrictMode(), "Invalid parameters or function name in strict mode");
}
}
// Since strict mode is changed, restoring lexer state by calling next() may cause errors.
// Since strict mode is changed, restoring lexer state by calling next() may cause errors.
restoreSavePoint(savePoint);
restoreSavePoint(savePoint);
propagateError();
propagateError();
continue;
continue;
}
}


// We saw a directive, but it wasn't "use strict". We reset our state to
// We saw a directive, but it wasn't "use strict". We reset our state to
// see if the next statement we parse is also a directive.
// see if the next statement we parse is also a directive.
directive = nullptr;
directive = nullptr;
} else {
} else {
// We saw a statement that wasn't in the form of a directive. The spec says that "use strict"
// We saw a statement that wasn't in the form of a directive. The spec says that "use strict"
// is only allowed as the first statement, or after a sequence of directives before it, but
// is only allowed as the first statement, or after a sequence of directives before it, but
// not after non-directive statements.
// not after non-directive statements.
shouldCheckForUseStrict = false;
shouldCheckForUseStrict = false;
}
}
}
}
context.appendStatement(sourceElements, statement);
context.appendStatement(sourceElements, statement);
}
}


propagateError();
propagateError();
return sourceElements;
return sourceElements;
}
}


template <typename LexerType>
template <typename LexerType>
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSourceElements(TreeBuilder& context, SourceParseMode parseMode)
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseModuleSourceElements(TreeBuilder& context, SourceParseMode parseMode)
{
{
TreeSourceElements sourceElements = context.createSourceElements();
TreeSourceElements sourceElements = context.createSourceElements();
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());


while (true) {
while (true) {
TreeStatement statement = 0;
TreeStatement statement = 0;
switch (m_token.m_type) {
switch (m_token.m_type) {
case EXPORT:
case EXPORT:
statement = parseExportDeclaration(context);
statement = parseExportDeclaration(context);
if (statement)
if (statement)
recordPauseLocation(context.breakpointLocation(statement));
recordPauseLocation(context.breakpointLocation(statement));
break;
break;


case IMPORT: {
case IMPORT: {
SavePoint savePoint = createSavePoint();
SavePoint savePoint = createSavePoint();
next();
next();
bool isImportDeclaration = !match(OPENPAREN);
bool isImportDeclaration = !match(OPENPAREN);
restoreSavePoint(savePoint);
restoreSavePoint(savePoint);
if (isImportDeclaration) {
if (isImportDeclaration) {
statement = parseImportDeclaration(context);
statement = parseImportDeclaration(context);
if (statement)
if (statement)
recordPauseLocation(context.breakpointLocation(statement));
recordPauseLocation(context.breakpointLocation(statement));
break;
break;
}
}


// This is `import("...")` call case.
// This is `import("...")` call case.
FALLTHROUGH;
FALLTHROUGH;
}
}


default: {
default: {
const Identifier* directive = 0;
const Identifier* directive = 0;
unsigned directiveLiteralLength = 0;
unsigned directiveLiteralLength = 0;
if (parseMode == SourceParseMode::ModuleAnalyzeMode) {
if (parseMode == SourceParseMode::ModuleAnalyzeMode) {
if (!parseStatementListItem(syntaxChecker, directive, &directiveLiteralLength))
if (!parseStatementListItem(syntaxChecker, directive, &directiveLiteralLength))
goto end;
goto end;
continue;
continue;
}
}
statement = parseStatementListItem(context, directive, &directiveLiteralLength);
statement = parseStatementListItem(context, directive, &directiveLiteralLength);
break;
break;
}
}
}
}


if (!statement)
if (!statement)
goto end;
goto end;
context.appendStatement(sourceElements, statement);
context.appendStatement(sourceElements, statement);
}
}


end:
end:
propagateError();
propagateError();


for (const auto& pair : m_moduleScopeData->exportedBindings()) {
for (const auto& pair : m_moduleScopeData->exportedBindings()) {
const auto& uid = pair.key;
const auto& uid = pair.key;
if (currentScope()->hasDeclaredVariable(uid)) {
if (currentScope()->hasDeclaredVariable(uid)) {
currentScope()->declaredVariables().markVariableAsExported(uid);
currentScope()->declaredVariables().markVariableAsExported(uid);
continue;
continue;
}
}


if (currentScope()->hasLexicallyDeclaredVariable(uid)) {
if (currentScope()->hasLexicallyDeclaredVariable(uid)) {
currentScope()->lexicalVariables().markVariableAsExported(uid);
currentScope()->lexicalVariables().markVariableAsExported(uid);
continue;
continue;
}
}


semanticFail("Exported binding '", uid.get(), "' needs to refer to a top-level declared variable");
semanticFail("Exported binding '", uid.get(), "' needs to refer to a top-level declared variable");
}
}


return sourceElements;
return sourceElements;
}
}


template <typename LexerType>
template <typename LexerType>
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, const Identifier& name, SourceElementsMode mode)
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseGeneratorFunctionSourceElements(TreeBuilder& context, const Identifier& name, SourceElementsMode mode)
{
{
auto sourceElements = context.createSourceElements();
auto sourceElements = context.createSourceElements();


unsigned functionKeywordStart = tokenStart();
unsigned functionKeywordStart = tokenStart();
JSTokenLocation startLocation(tokenLocation());
JSTokenLocation startLocation(tokenLocation());
JSTextPosition start = tokenStartPosition();
JSTextPosition start = tokenStartPosition();
unsigned startColumn = tokenColumn();
unsigned startColumn = tokenColumn();
int functionNameStart = m_token.m_location.startOffset;
int functionNameStart = m_token.m_location.startOffset;
int parametersStart = m_token.m_location.startOffset;
int parametersStart = m_token.m_location.startOffset;


ParserFunctionInfo<TreeBuilder> info;
ParserFunctionInfo<TreeBuilder> info;
info.name = &m_vm->propertyNames->nullIdentifier;
info.name = &m_vm->propertyNames->nullIdentifier;
createGeneratorParameters(context, info.parameterCount);
createGeneratorParameters(context, info.parameterCount);
info.startOffset = parametersStart;
info.startOffset = parametersStart;
info.startLine = tokenLine();
info.startLine = tokenLine();


{
{
AutoPopScopeRef generatorBodyScope(this, pushScope());
AutoPopScopeRef generatorBodyScope(this, pushScope());
generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
generatorBodyScope->setSourceParseMode(SourceParseMode::GeneratorBodyMode);
generatorBodyScope->setConstructorKind(ConstructorKind::None);
generatorBodyScope->setConstructorKind(ConstructorKind::None);
generatorBodyScope->setExpectedSuperBinding(m_superBinding);
generatorBodyScope->setExpectedSuperBinding(m_superBinding);


SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
SyntaxChecker generatorFunctionContext(const_cast<VM*>(m_vm), m_lexer.get());
failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
failIfFalse(parseSourceElements(generatorFunctionContext, mode), "Cannot parse the body of a generator");
popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
popScope(generatorBodyScope, TreeBuilder::NeedsFreeVariableInfo);
}
}
info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);
info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart, functionNameStart, parametersStart, strictMode(), ConstructorKind::None, m_superBinding, info.parameterCount, SourceParseMode::GeneratorBodyMode, false);


info.endLine = tokenLine();
info.endLine = tokenLine();
info.endOffset = m_token.m_data.offset;
info.endOffset = m_token.m_data.offset;
info.parametersStartColumn = startColumn;
info.parametersStartColumn = startColumn;


auto functionExpr = context.createGeneratorFunctionBody(startLocation, info, name);
auto functionExpr = context.createGeneratorFunctionBody(startLocation, info, name);
auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
auto statement = context.createExprStatement(startLocation, functionExpr, start, m_lastTokenEndPosition.line);
context.appendStatement(sourceElements, statement);
context.appendStatement(sourceElements, statement);


return sourceElements;
return sourceElements;
}
}


template <typename LexerType>
template <typename LexerType>
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseAsyncFunctionSourceElements(TreeBuilder& context, SourceParseMode parseMode, bool isArrowFunctionBodyExpression, SourceElementsMode mode)
template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseAsyncFunctionSourceElements(TreeBuilder& context, SourceParseMode parseMode, bool isArrowFunctionBodyExpression, SourceElementsMode mode)
{
{
ASSERT(isAsyncFunctionOrAsyncGeneratorWrapperParseMode(parseMode));
ASSERT(isAsyncFunctionOrAsyncGeneratorWrapperParseMode(parseMode));
auto sourceElements = context.createSourceElements();
auto sourceElements = context.createSourceElements();


unsigned functionKeywordStart = tokenStart();
unsigned functionKeywordStart = tokenStart();
JSTokenLocation startLocation(tokenLocation());
JSTokenLocation startLocation(tokenLocation());
JSTextPosition start = tokenStartPosition();
JSTextPosition start = tokenStartPosition();
unsigned startColumn = tokenColumn();
unsigned startColumn = tokenColumn();
int functionNameStart = m_token.m_location.startOffset;
int functionNameStart = m_token.m_location.startOffset;
int parametersStart = m_token.m_location.startOffset;
int parametersStart = m_token.m_location.startOffset;


ParserFunctionInfo<TreeBuilder> info;
ParserFunctionInfo<TreeBuilder> info;
info.name = &m_vm->propertyNames->nullIdentifier;
info.name = &m_vm->propertyNames->nullIdentifier;
createGeneratorParameters(context, info.parameterCount);
createGeneratorParameters(context, info.parameterCount);
info.startOffset = parametersStart;
info.startOffset = parametersStart;
info.startLine = tokenLine();
info.startLine = tokenLine();
SourceParseMode innerParseMode;
SourceParseMode innerParseMode;


if (isAsyncGeneratorFunctionParseMode(parseMode))
if (isAsyncGeneratorFunctionParseMode(parseMode))
innerParseMode = SourceParseMode::AsyncGeneratorBodyMode;
innerParseMode = SourceParseMode::AsyncGeneratorBodyMode;
else
else
innerParseMode = parseMode == SourceParseMode::AsyncArrowFunctionMode
innerParseMode = parseMode == SourceParseMode::AsyncArrowFunctionMode
? SourceParseMode::AsyncArrowFunctionBodyMode
? SourceParseMode::AsyncArrowFunctionBodyMode
: SourceParseMode::AsyncFunctionBodyMode;
: SourceParseMode::AsyncFunctionBodyMode;
{
{
AutoPopScopeRef asyncFunctionBodyScope(this, pushScope());
AutoPopScopeRef asyncFunctionBodyScope(this, pushScope());
asyncFunctionBodyScope->setSourceParseMode(innerParseMode);
asyncFunctionBodyScope->setSourceParseMode(innerParseMode);
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
SyntaxChecker syntaxChecker(const_cast<VM*>(m_vm), m_lexer.get());
if (isArrowFunctionBodyExpression) {
if (isArrowFunctionBodyExpression) {
if (m_debuggerParseData)
if (m_debuggerParseData)
failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(context), "Cannot parse the body of async arrow function");
failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(context), "Cannot parse the body of async arrow function");
else
else
failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(syntaxChecker), "Cannot parse the body of async arrow function");
failIfFalse(parseArrowFunctionSingleExpressionBodySourceElements(syntaxChecker), "Cannot parse the body of async arrow function");
} else {
} else {
if (m_debuggerParseData)
if (m_debuggerParseData)
failIfFalse(parseSourceElements(context, mode), "Cannot parse the body of async function");
failIfFalse(parseSourceElements(context, mode), "Cannot parse the body of async function");
else
else
failIfFalse(parseSourceElements(syntaxChecker, mode), "Cannot parse the body of async function");
failIfFalse(parseSourceElements(syntaxChecker, mode), "Cannot parse the body of async function");
}
}
popScope(asyncFunctionBodyScope, TreeBuilder::NeedsFreeVariableInfo);
popScope(asyncFunctionBodyScope, TreeBuilder::NeedsFreeVariableInfo);
}
}
info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart,
info.body = context.createFunctionMetadata(startLocation, tokenLocation(), startColumn, tokenColumn(), functionKeywordStart,