* Copyright (c) 2021-2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "parser/parserFlags.h"
#include "ir/astNode.h"
#include "ir/base/classDefinition.h"
#include "ir/base/decorator.h"
#include "ir/base/metaProperty.h"
#include "ir/base/methodDefinition.h"
#include "ir/base/property.h"
#include "ir/base/scriptFunction.h"
#include "ir/base/spreadElement.h"
#include "ir/base/templateElement.h"
#include "ir/expression.h"
#include "ir/expressions/arrayExpression.h"
#include "ir/expressions/arrowFunctionExpression.h"
#include "ir/expressions/assignmentExpression.h"
#include "ir/expressions/awaitExpression.h"
#include "ir/expressions/binaryExpression.h"
#include "ir/expressions/callExpression.h"
#include "ir/expressions/chainExpression.h"
#include "ir/expressions/classExpression.h"
#include "ir/expressions/conditionalExpression.h"
#include "ir/expressions/directEvalExpression.h"
#include "ir/expressions/functionExpression.h"
#include "ir/expressions/identifier.h"
#include "ir/expressions/importExpression.h"
#include "ir/expressions/literals/bigIntLiteral.h"
#include "ir/expressions/literals/booleanLiteral.h"
#include "ir/expressions/literals/nullLiteral.h"
#include "ir/expressions/literals/numberLiteral.h"
#include "ir/expressions/literals/regExpLiteral.h"
#include "ir/expressions/literals/charLiteral.h"
#include "ir/expressions/literals/stringLiteral.h"
#include "ir/expressions/literals/undefinedLiteral.h"
#include "ir/expressions/memberExpression.h"
#include "ir/expressions/newExpression.h"
#include "ir/expressions/objectExpression.h"
#include "ir/expressions/omittedExpression.h"
#include "ir/expressions/sequenceExpression.h"
#include "ir/expressions/superExpression.h"
#include "ir/expressions/taggedTemplateExpression.h"
#include "ir/expressions/templateLiteral.h"
#include "ir/expressions/thisExpression.h"
#include "ir/expressions/typeofExpression.h"
#include "ir/expressions/unaryExpression.h"
#include "ir/expressions/updateExpression.h"
#include "ir/expressions/yieldExpression.h"
#include "ir/statements/blockStatement.h"
#include "ir/statements/classDeclaration.h"
#include "ir/ts/tsAsExpression.h"
#include "ir/ts/tsNonNullExpression.h"
#include "ir/validationInfo.h"
#include "lexer/lexer.h"
#include "lexer/regexp/regexp.h"
#include "lexer/token/letters.h"
#include "lexer/token/sourceLocation.h"
#include "lexer/token/token.h"
#include "util/es2pandaMacros.h"
#include "util/errorRecovery.h"
#include "util/options.h"
#include "generated/diagnostic.h"
#include "generated/tokenType.h"
#include <memory>
#include "parser/parserStatusContext.h"
#include "parserImpl.h"
namespace ark::es2panda::parser {
static ir::ValidationInfo ValidateExpression(ir::ArrayExpression *arrExpr);
static ir::ValidationInfo ValidateExpression(ir::ObjectExpression *objExpr);
static ir::ValidationInfo ValidateExpression(ir::SpreadElement *spreadElement);
static ir::ValidationInfo ValidateExpression(ir::Identifier *ident)
{
if ((ident->IdFlags() & ir::IdentifierFlags::OPTIONAL) != 0U) {
return {diagnostic::UNEXPECTED_QUESTIONMARK.Message(), ident->Start()};
}
if (ident->TypeAnnotation() != nullptr) {
return {diagnostic::UNEXPECTED_TOKEN.Message(), ident->TypeAnnotation()->Start()};
}
ir::ValidationInfo info;
return info;
}
static ir::ValidationInfo ValidateExpression(ir::Property *prop)
{
ir::ValidationInfo info;
if (!prop->IsComputed() && !prop->IsMethod() && !prop->IsAccessor() && !prop->IsShorthand()) {
bool currentIsProto = false;
if (prop->Key()->IsIdentifier()) {
currentIsProto = prop->Key()->AsIdentifier()->Name().Is("__proto__");
} else if (prop->Key()->IsStringLiteral()) {
currentIsProto = prop->Key()->AsStringLiteral()->Str().Is("__proto__");
}
if (currentIsProto) {
prop->SetKind(ir::PropertyKind::PROTO);
}
}
if (prop->Value() != nullptr) {
if (prop->Value()->IsAssignmentPattern()) {
return {diagnostic::INVALID_SHORTHAND_PROPERTY_INITIALIZER.Message(), prop->Value()->Start()};
}
if (prop->Value()->IsObjectExpression()) {
info = ValidateExpression(prop->Value()->AsObjectExpression());
} else if (prop->Value()->IsArrayExpression()) {
info = ValidateExpression(prop->Value()->AsArrayExpression());
}
}
return info;
}
static std::pair<ir::ValidationInfo, bool> ValidateProperty(ir::Property *prop, bool &foundProto)
{
ir::ValidationInfo info = ValidateExpression(prop);
if (prop->Kind() == ir::PropertyKind::PROTO) {
if (foundProto) {
return {{diagnostic::DUPLICATE_PROTO_FIELDS.Message(), prop->Key()->Start()}, true};
}
foundProto = true;
}
return {info, false};
}
static ir::ValidationInfo ValidateExpression(ir::ObjectExpression *objExpr)
{
if (objExpr->IsOptional()) {
return {diagnostic::UNEXPECTED_QUESTIONMARK.Message(), objExpr->Start()};
}
if (objExpr->TypeAnnotation() != nullptr) {
return {diagnostic::UNEXPECTED_TOKEN.Message(), objExpr->TypeAnnotation()->Start()};
}
ir::ValidationInfo info;
bool foundProto = false;
for (auto *it : objExpr->Properties()) {
switch (it->Type()) {
case ir::AstNodeType::OBJECT_EXPRESSION:
case ir::AstNodeType::ARRAY_EXPRESSION: {
return {diagnostic::UNEXPECTED_TOKEN.Message(), it->Start()};
}
case ir::AstNodeType::SPREAD_ELEMENT: {
info = ValidateExpression(it->AsSpreadElement());
break;
}
case ir::AstNodeType::PROPERTY: {
auto *prop = it->AsProperty();
bool ret = false;
std::tie(info, ret) = ValidateProperty(prop, foundProto);
if (ret) {
return info;
}
break;
}
default: {
break;
}
}
if (info.Fail()) {
break;
}
}
return info;
}
static ir::ValidationInfo ValidateExpression(ir::SpreadElement *spreadElement)
{
ir::ValidationInfo info;
switch (spreadElement->Argument()->Type()) {
case ir::AstNodeType::OBJECT_EXPRESSION: {
info = ValidateExpression(spreadElement->Argument()->AsObjectExpression());
break;
}
case ir::AstNodeType::ARRAY_EXPRESSION: {
info = ValidateExpression(spreadElement->Argument()->AsArrayExpression());
break;
}
default: {
break;
}
}
return info;
}
static ir::ValidationInfo ValidateExpression(ir::ArrayExpression *arrExpr)
{
if (arrExpr->IsOptional()) {
return {diagnostic::UNEXPECTED_QUESTIONMARK.Message(), arrExpr->Start()};
}
if (arrExpr->TypeAnnotation() != nullptr) {
return {diagnostic::UNEXPECTED_TOKEN.Message(), arrExpr->TypeAnnotation()->Start()};
}
ir::ValidationInfo info;
for (auto *it : arrExpr->Elements()) {
switch (it->Type()) {
case ir::AstNodeType::OBJECT_EXPRESSION: {
info = ValidateExpression(it->AsObjectExpression());
break;
}
case ir::AstNodeType::ARRAY_EXPRESSION: {
info = ValidateExpression(it->AsArrayExpression());
break;
}
case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
auto *assignmentExpr = it->AsAssignmentExpression();
if (assignmentExpr->Left()->IsArrayExpression()) {
info = ValidateExpression(assignmentExpr->Left()->AsArrayExpression());
} else if (assignmentExpr->Left()->IsObjectExpression()) {
info = ValidateExpression(assignmentExpr->Left()->AsObjectExpression());
}
break;
}
case ir::AstNodeType::SPREAD_ELEMENT: {
info = ValidateExpression(it->AsSpreadElement());
break;
}
default: {
break;
}
}
if (info.Fail()) {
break;
}
}
return info;
}
ir::YieldExpression *ParserImpl::ParseYieldExpression()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_YIELD);
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
lexer::SourcePosition endLoc = lexer_->GetToken().End();
if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) != 0) {
LogError(diagnostic::UNEXPECTED_ID);
}
lexer_->NextToken();
bool isDelegate = false;
ir::Expression *argument = nullptr;
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY && !lexer_->GetToken().NewLine()) {
isDelegate = true;
lexer_->NextToken();
argument = ParseExpression();
endLoc = argument->End();
} else if (!lexer_->GetToken().NewLine() && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON &&
lexer_->GetToken().Type() != lexer::TokenType::EOS) {
argument = ParseExpression();
endLoc = argument->End();
}
auto *yieldNode = AllocNode<ir::YieldExpression>(argument, isDelegate);
ES2PANDA_ASSERT(yieldNode != nullptr);
yieldNode->SetRange({startLoc, endLoc});
return yieldNode;
}
ir::Expression *ParserImpl::ParsePotentialExpressionSequence(ir::Expression *expr, ExpressionParseFlags flags)
{
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA &&
(flags & ExpressionParseFlags::ACCEPT_COMMA) != 0) {
return ParseSequenceExpression(expr, (flags & ExpressionParseFlags::ACCEPT_REST) != 0);
}
return expr;
}
ir::Expression *ParserImpl::ParseExpression(ExpressionParseFlags flags)
{
if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_YIELD &&
(flags & ExpressionParseFlags::DISALLOW_YIELD) == 0U) {
ir::YieldExpression *yieldExpr = ParseYieldExpression();
return ParsePotentialExpressionSequence(yieldExpr, flags);
}
ir::Expression *unaryExpressionNode = ParseUnaryOrPrefixUpdateExpression(flags);
ir::Expression *assignmentExpression = ParseAssignmentExpression(unaryExpressionNode, flags);
if (lexer_->GetToken().NewLine()) {
return assignmentExpression;
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA &&
(flags & ExpressionParseFlags::ACCEPT_COMMA) != 0U) {
return ParseSequenceExpression(assignmentExpression, (flags & ExpressionParseFlags::ACCEPT_REST) != 0U);
}
return assignmentExpression;
}
bool ParserImpl::ParseArrayExpressionRightBracketHelper(bool containsRest, const lexer::SourcePosition &startLoc)
{
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
if (containsRest) {
LogError(diagnostic::REST_PARAM_NOT_LAST, {}, startLoc);
}
return true;
}
return false;
}
ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags, bool allowOmitted)
{
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
ArenaVector<ir::Expression *> elements(Allocator()->Adapter());
lexer_->NextToken();
bool trailingComma = false;
bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0;
lexer::SourcePosition endLoc;
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET, lexer::NextTokenFlags::NONE,
[this, inPattern, startLoc, allowOmitted, &elements, &trailingComma](bool &) {
if (allowOmitted && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
auto *omitted = AllocNode<ir::OmittedExpression>();
omitted->SetRange(lexer_->GetToken().Loc());
elements.push_back(omitted);
return true;
}
ir::Expression *element {};
if (inPattern) {
element = ParsePatternElement();
} else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
element = ParseSpreadElement(ExpressionParseFlags::POTENTIALLY_IN_PATTERN);
} else {
element = ParseExpression(ExpressionParseFlags::POTENTIALLY_IN_PATTERN);
}
bool containsRest = element->IsRestElement();
elements.push_back(element);
trailingComma = ParseArrayExpressionRightBracketHelper(containsRest, startLoc);
return true;
},
&endLoc, ParseListOptions::ALLOW_TRAILING_SEP);
auto nodeType = inPattern ? ir::AstNodeType::ARRAY_PATTERN : ir::AstNodeType::ARRAY_EXPRESSION;
auto *arrayExpressionNode =
AllocNode<ir::ArrayExpression>(nodeType, std::move(elements), Allocator(), trailingComma);
ES2PANDA_ASSERT(arrayExpressionNode != nullptr);
arrayExpressionNode->SetRange({startLoc, endLoc});
if (inPattern) {
arrayExpressionNode->SetDeclaration();
}
ParseArrayExpressionErrorCheck(arrayExpressionNode, flags, inPattern);
return arrayExpressionNode;
}
ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags)
{
return ParseArrayExpression(flags, true);
}
void ParserImpl::ParseArrayExpressionErrorCheck(ir::ArrayExpression *arrayExpressionNode,
const ExpressionParseFlags flags, const bool inPattern)
{
if ((flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) == 0) {
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION &&
!arrayExpressionNode->ConvertibleToArrayPattern()) {
LogError(diagnostic::INVALID_LEFT_SIDE_ARRAY_DESTRUCTURING, {}, arrayExpressionNode->Start());
} else if (!inPattern && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ir::ValidationInfo info = ValidateExpression(arrayExpressionNode);
if (info.Fail()) {
LogSyntaxError(info.msg.Utf8(), info.pos);
}
}
}
}
ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_unused]] bool *seenOptional)
{
switch (expr->Type()) {
case ir::AstNodeType::SPREAD_ELEMENT: {
if (!expr->AsSpreadElement()->ConvertibleToRest(true)) {
LogError(diagnostic::INVALID_REST_ELEMENT);
}
[[fallthrough]];
}
case ir::AstNodeType::REST_ELEMENT: {
ValidateArrowParameterBindings(expr->AsRestElement()->Argument());
return ParserStatus::HAS_COMPLEX_PARAM;
}
case ir::AstNodeType::IDENTIFIER: {
ValidateArrowParameterBindings(expr);
return ParserStatus::NO_OPTS;
}
case ir::AstNodeType::OBJECT_EXPRESSION: {
if (ir::ObjectExpression *objectPattern = expr->AsObjectExpression();
!objectPattern->ConvertibleToObjectPattern()) {
LogError(diagnostic::INVALID_DESTRUCTURING_TARGET);
}
ValidateArrowParameterBindings(expr);
return ParserStatus::HAS_COMPLEX_PARAM;
}
case ir::AstNodeType::ARRAY_EXPRESSION: {
if (ir::ArrayExpression *arrayPattern = expr->AsArrayExpression();
!arrayPattern->ConvertibleToArrayPattern()) {
LogError(diagnostic::INVALID_DESTRUCTURING_TARGET);
}
ValidateArrowParameterBindings(expr);
return ParserStatus::HAS_COMPLEX_PARAM;
}
case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
ValidateArrowParameterAssignment(expr->AsAssignmentExpression());
ValidateArrowParameterBindings(expr);
return ParserStatus::HAS_COMPLEX_PARAM;
}
default: {
break;
}
}
LogError(diagnostic::INSUFFICIENT_PARAM_IN_ARROW_FUN);
return ParserStatus::NO_OPTS;
}
void ParserImpl::ValidateArrowParameterAssignment(ir::AssignmentExpression *expr)
{
if (expr->Right()->IsYieldExpression()) {
LogError(diagnostic::YIELD_IN_ARROW_FUN_PARAM);
} else if (expr->Right()->IsAwaitExpression()) {
LogError(diagnostic::AWAIT_IN_ARROW_FUN_PARAM);
} else if (!expr->ConvertibleToAssignmentPattern()) {
LogError(diagnostic::INVALID_DESTRUCTURING_TARGET);
}
}
ir::ArrowFunctionExpression *ParserImpl::ParseArrowFunctionExpressionBody(ArrowFunctionContext *arrowFunctionContext,
ArrowFunctionDescriptor *desc,
ir::TSTypeParameterDeclaration *typeParamDecl,
ir::TypeNode *returnTypeAnnotation)
{
context_.Status() |= desc->newStatus;
lexer_->NextToken();
ir::ScriptFunction *funcNode {};
ir::AstNode *body = nullptr;
lexer::SourcePosition endLoc;
lexer::SourcePosition bodyStart = lexer_->GetToken().Start();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
body = ParseExpression();
endLoc = body->End();
arrowFunctionContext->AddFlag(ir::ScriptFunctionFlags::EXPRESSION);
} else {
lexer_->NextToken();
auto statements = ParseStatementList();
body = AllocNode<ir::BlockStatement>(Allocator(), std::move(statements));
ES2PANDA_ASSERT(body);
body->SetRange({bodyStart, lexer_->GetToken().End()});
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE);
endLoc = body->End();
}
funcNode = AllocNode<ir::ScriptFunction>(
Allocator(), ir::ScriptFunction::ScriptFunctionData {
body,
ir::FunctionSignature(typeParamDecl, std::move(desc->params), returnTypeAnnotation),
arrowFunctionContext->Flags(),
{},
context_.GetLanguage()});
ES2PANDA_ASSERT(funcNode != nullptr);
funcNode->SetRange({desc->startLoc, endLoc});
auto *arrowFuncNode = AllocNode<ir::ArrowFunctionExpression>(funcNode, Allocator());
ES2PANDA_ASSERT(arrowFuncNode != nullptr);
arrowFuncNode->SetRange(funcNode->Range());
return arrowFuncNode;
}
ArrowFunctionDescriptor ParserImpl::ConvertToArrowParameter(ir::Expression *expr, bool isAsync)
{
auto arrowStatus = isAsync ? ParserStatus::ASYNC_FUNCTION : ParserStatus::NO_OPTS;
ArenaVector<ir::Expression *> params(Allocator()->Adapter());
if (expr == nullptr) {
return ArrowFunctionDescriptor {std::move(params), lexer_->GetToken().Start(), arrowStatus};
}
bool seenOptional = false;
switch (expr->Type()) {
case ir::AstNodeType::REST_ELEMENT:
case ir::AstNodeType::IDENTIFIER:
case ir::AstNodeType::OBJECT_EXPRESSION:
case ir::AstNodeType::ASSIGNMENT_EXPRESSION:
case ir::AstNodeType::ARRAY_EXPRESSION: {
arrowStatus |= ValidateArrowParameter(expr, &seenOptional);
params.push_back(expr);
break;
}
case ir::AstNodeType::SEQUENCE_EXPRESSION: {
auto &sequence = expr->AsSequenceExpression()->Sequence();
for (auto *it : sequence) {
arrowStatus |= ValidateArrowParameter(it, &seenOptional);
}
params.swap(sequence);
break;
}
case ir::AstNodeType::CALL_EXPRESSION: {
if (isAsync) {
auto *callExpression = expr->AsCallExpression();
auto &arguments = callExpression->Arguments();
if (callExpression->HasTrailingComma()) {
ES2PANDA_ASSERT(!arguments.empty());
LogError(diagnostic::REST_PARAM_NOT_LAST, {}, arguments.back()->End());
}
for (auto *it : arguments) {
arrowStatus |= ValidateArrowParameter(it, &seenOptional);
}
params.swap(arguments);
break;
}
[[fallthrough]];
}
default: {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
}
return ArrowFunctionDescriptor {std::move(params), expr->Start(), arrowStatus};
}
ir::ArrowFunctionExpression *ParserImpl::ParseArrowFunctionExpression(ir::Expression *expr,
ir::TSTypeParameterDeclaration *typeParamDecl,
ir::TypeNode *returnTypeAnnotation, bool isAsync)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW);
if (lexer_->GetToken().NewLine()) {
LogError(diagnostic::EXPECTED_ARROW_SAME_LINE);
}
ArrowFunctionContext arrowFunctionContext(this, isAsync);
FunctionParameterContext functionParamContext(&context_);
ArrowFunctionDescriptor desc = ConvertToArrowParameter(expr, isAsync);
return ParseArrowFunctionExpressionBody(&arrowFunctionContext, &desc, typeParamDecl, returnTypeAnnotation);
}
bool ParserImpl::ValidateArrowFunctionRestParameter([[maybe_unused]] ir::SpreadElement *restElement)
{
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
LogError(diagnostic::REST_PARAM_NOT_LAST);
return false;
}
return true;
}
ir::Expression *ParserImpl::ParseCoverParenthesizedExpressionAndArrowParameterList(
[[maybe_unused]] ExpressionParseFlags flags)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
lexer::SourcePosition start = lexer_->GetToken().Start();
lexer_->NextToken();
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN);
restElement->SetGrouped();
restElement->SetStart(start);
if (ValidateArrowFunctionRestParameter(restElement)) {
lexer_->NextToken();
}
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_ARROW);
}
return ParseArrowFunctionExpression(restElement, nullptr, nullptr, false);
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
lexer_->NextToken();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_ARROW);
}
auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, nullptr, false);
arrowExpr->SetStart(start);
arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start);
return arrowExpr;
}
ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST |
ExpressionParseFlags::POTENTIALLY_IN_PATTERN);
expr->SetGrouped();
expr->SetRange({start, lexer_->GetToken().End()});
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
return expr;
}
void ParserImpl::ValidateGroupedExpression(ir::Expression *lhsExpression)
{
lexer::TokenType tokenType = lexer_->GetToken().Type();
if (lhsExpression->IsGrouped() && tokenType != lexer::TokenType::PUNCTUATOR_ARROW) {
if (lhsExpression->IsSequenceExpression()) {
for (auto *seq : lhsExpression->AsSequenceExpression()->Sequence()) {
ValidateParenthesizedExpression(seq);
}
} else {
ValidateParenthesizedExpression(lhsExpression);
}
}
}
void ParserImpl::ValidateParenthesizedExpression(ir::Expression *lhsExpression)
{
switch (lhsExpression->Type()) {
case ir::AstNodeType::IDENTIFIER: {
auto info = ValidateExpression(lhsExpression->AsIdentifier());
if (info.Fail()) {
LogSyntaxError(info.msg.Utf8(), info.pos);
}
break;
}
case ir::AstNodeType::MEMBER_EXPRESSION: {
break;
}
case ir::AstNodeType::ARRAY_EXPRESSION: {
auto info = ValidateExpression(lhsExpression->AsArrayExpression());
if (info.Fail()) {
LogSyntaxError(info.msg.Utf8(), info.pos);
}
break;
}
case ir::AstNodeType::OBJECT_EXPRESSION: {
auto info = ValidateExpression(lhsExpression->AsObjectExpression());
if (info.Fail()) {
LogSyntaxError(info.msg.Utf8(), info.pos);
}
break;
}
case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
if (lhsExpression->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false)) {
break;
}
[[fallthrough]];
}
case ir::AstNodeType::SPREAD_ELEMENT: {
LogError(diagnostic::INVALID_LEFT_SIDE_IN_ASSIGNMENT);
break;
}
default: {
break;
}
}
}
ir::Expression *ParserImpl::ParsePrefixAssertionExpression()
{
LogUnexpectedToken(lexer_->GetToken());
return AllocBrokenExpression(Lexer()->GetToken().Loc());
}
ir::Expression *ParserImpl::ParseAssignmentExpressionHelper()
{
lexer_->NextToken();
ir::Expression *consequent = ParseExpression();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
if (lexer::Token::IsPunctuatorToken(lexer_->GetToken().Type())) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_COLON);
lexer_->NextToken();
} else {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
} else {
lexer_->NextToken();
}
return consequent;
}
ir::Expression *ParserImpl::CreateBinaryAssignmentExpression(ir::Expression *assignmentExpression,
ir::Expression *lhsExpression, lexer::TokenType tokenType)
{
auto *binaryAssignmentExpression =
AllocNode<ir::AssignmentExpression>(lhsExpression, assignmentExpression, tokenType);
ES2PANDA_ASSERT(binaryAssignmentExpression != nullptr);
binaryAssignmentExpression->SetRange({lhsExpression->Start(), assignmentExpression->End()});
return binaryAssignmentExpression;
}
ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpression, ExpressionParseFlags flags)
{
ValidateGroupedExpression(lhsExpression);
lexer::TokenType tokenType = lexer_->GetToken().Type();
switch (tokenType) {
case lexer::TokenType::PUNCTUATOR_QUESTION_MARK: {
ir::Expression *consequent = ParseAssignmentExpressionHelper();
ir::Expression *alternate = ParseExpression();
auto *conditionalExpr = AllocNode<ir::ConditionalExpression>(lhsExpression, consequent, alternate);
ES2PANDA_ASSERT(conditionalExpr != nullptr);
conditionalExpr->SetRange({lhsExpression->Start(), alternate->End()});
return conditionalExpr;
}
case lexer::TokenType::PUNCTUATOR_ARROW:
if (lexer_->GetToken().NewLine()) {
LogError(diagnostic::EXPECTED_EXPRESSION_GOT_ARROW);
}
return ParseArrowFunctionExpression(lhsExpression, nullptr, nullptr, false);
case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
ValidateAssignmentTarget(flags, lhsExpression);
lexer_->NextToken();
ir::Expression *assignmentExpression = ParseExpression(CarryPatternFlags(flags));
return CreateBinaryAssignmentExpression(assignmentExpression, lhsExpression, tokenType);
}
case lexer::TokenType::KEYW_AS:
if (auto asExpression = ParsePotentialAsExpression(lhsExpression); asExpression != nullptr) {
return ParseAssignmentExpression(asExpression);
}
break;
default: {
auto expression = ParseAssignmentBinaryExpression(tokenType, lhsExpression, flags);
if (expression == nullptr) {
expression = ParseAssignmentEqualExpression(tokenType, lhsExpression, flags);
}
if (expression != nullptr) {
return expression;
}
break;
}
}
return lhsExpression;
}
ir::Expression *ParserImpl::ParseAssignmentBinaryExpression(const lexer::TokenType tokenType,
ir::Expression *lhsExpression,
const ExpressionParseFlags flags)
{
switch (tokenType) {
case lexer::TokenType::KEYW_IN: {
if ((flags & ExpressionParseFlags::STOP_AT_IN) != 0) {
break;
}
[[fallthrough]];
}
case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING:
case lexer::TokenType::PUNCTUATOR_LOGICAL_OR:
case lexer::TokenType::PUNCTUATOR_LOGICAL_AND:
case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
case lexer::TokenType::PUNCTUATOR_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL:
case lexer::TokenType::PUNCTUATOR_LESS_THAN:
case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
case lexer::TokenType::PUNCTUATOR_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS:
case lexer::TokenType::PUNCTUATOR_MULTIPLY:
case lexer::TokenType::PUNCTUATOR_DIVIDE:
case lexer::TokenType::PUNCTUATOR_MOD:
case lexer::TokenType::KEYW_INSTANCEOF:
case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
return ParseAssignmentExpression(ParseBinaryExpression(lhsExpression));
}
default:
break;
}
return nullptr;
}
ir::Expression *ParserImpl::ParseAssignmentEqualExpression(const lexer::TokenType tokenType,
ir::Expression *lhsExpression,
const ExpressionParseFlags flags)
{
switch (tokenType) {
case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL:
case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL:
case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL: {
ValidateLvalueAssignmentTarget(lhsExpression);
lexer_->NextToken();
ir::Expression *assignmentExpression = ParseExpression(CarryPatternFlags(flags));
auto *binaryAssignmentExpression =
AllocNode<ir::AssignmentExpression>(lhsExpression, assignmentExpression, tokenType);
ES2PANDA_ASSERT(binaryAssignmentExpression != nullptr);
binaryAssignmentExpression->SetRange({lhsExpression->Start(), assignmentExpression->End()});
return binaryAssignmentExpression;
}
case lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL:
case lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL:
case lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL: {
LogUnexpectedToken(tokenType);
lexer_->NextToken();
ParseExpression();
[[fallthrough]];
}
default:
break;
}
return nullptr;
}
ir::TemplateLiteral *ParserImpl::ParseTemplateLiteral()
{
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
auto startPos = lexer_->Save();
auto multilineStr = Lexer()->ScanMultilineString();
lexer_->Rewind(startPos);
ArenaVector<ir::TemplateElement *> quasis(Allocator()->Adapter());
ArenaVector<ir::Expression *> expressions(Allocator()->Adapter());
while (true) {
lexer_->ResetTokenEnd();
startPos = lexer_->Save();
lexer_->ScanString<lexer::LEX_CHAR_BACK_TICK>();
const util::StringView cooked = lexer_->GetToken().String();
lexer_->Rewind(startPos);
const auto templateStr = lexer_->ScanTemplateString();
if (templateStr.validSequence) {
auto *const element = AllocNode<ir::TemplateElement>(templateStr.str.View(), cooked);
ES2PANDA_ASSERT(element != nullptr);
element->SetRange({lexer::SourcePosition {startPos.Iterator().Index(), startPos.Line(), GetProgram()},
lexer::SourcePosition {templateStr.end, lexer_->Line(), GetProgram()}});
quasis.push_back(element);
}
if (!templateStr.scanExpression) {
lexer_->ScanTemplateStringEnd();
break;
}
ir::Expression *expression = nullptr;
{
lexer::TemplateLiteralParserContext ctx(lexer_);
lexer_->PushTemplateContext(&ctx);
lexer_->NextToken();
expression = ParseExpression();
}
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, false);
expressions.push_back(expression);
}
auto *templateNode = AllocNode<ir::TemplateLiteral>(std::move(quasis), std::move(expressions), multilineStr);
ES2PANDA_ASSERT(templateNode != nullptr);
templateNode->SetRange({startLoc, lexer_->GetToken().End()});
lexer_->NextToken();
return templateNode;
}
ir::Expression *ParserImpl::ParseNewExpression()
{
lexer::SourcePosition start = lexer_->GetToken().Start();
lexer_->NextToken();
ir::Expression *callee = ParseMemberExpression(true);
if (callee->IsImportExpression() && !callee->IsGrouped()) {
LogError(diagnostic::NEW_WITH_IMPORT);
}
ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
lexer::SourcePosition endLoc = callee->End();
auto *newExprNode = AllocNode<ir::NewExpression>(callee, std::move(arguments));
ES2PANDA_ASSERT(newExprNode != nullptr);
newExprNode->SetRange({start, endLoc});
return newExprNode;
}
lexer_->NextToken();
lexer::SourcePosition endLoc;
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE,
[this, &arguments](bool &) {
ir::Expression *argument = nullptr;
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
argument = ParseSpreadElement();
} else {
argument = ParseExpression();
}
arguments.push_back(argument);
return true;
},
&endLoc, ParseListOptions::ALLOW_TRAILING_SEP);
auto *newExprNode = AllocNode<ir::NewExpression>(callee, std::move(arguments));
ES2PANDA_ASSERT(newExprNode != nullptr);
newExprNode->SetRange({start, endLoc});
return newExprNode;
}
ir::Expression *ParserImpl::ParseLeftHandSideExpression(ExpressionParseFlags flags)
{
return ParseMemberExpression(false, flags);
}
ir::MetaProperty *ParserImpl::ParsePotentialNewTarget()
{
lexer::SourceRange loc = lexer_->GetToken().Loc();
if (lexer_->Lookahead() == lexer::LEX_CHAR_DOT) {
lexer_->NextToken();
lexer_->NextToken();
if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_TARGET) {
if ((context_.Status() & ParserStatus::ALLOW_NEW_TARGET) == 0) {
LogError(diagnostic::NEW_TARGET_IS_NOT_ALLOWED);
}
auto *metaProperty = AllocNode<ir::MetaProperty>(ir::MetaProperty::MetaPropertyKind::NEW_TARGET);
ES2PANDA_ASSERT(metaProperty != nullptr);
metaProperty->SetRange(loc);
lexer_->NextToken();
return metaProperty;
}
}
return nullptr;
}
ir::Identifier *ParserImpl::ParsePrimaryExpressionIdent([[maybe_unused]] ExpressionParseFlags flags)
{
auto *identNode = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(identNode != nullptr);
identNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return identNode;
}
ir::BooleanLiteral *ParserImpl::ParseBooleanLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_TRUE ||
lexer_->GetToken().Type() == lexer::TokenType::LITERAL_FALSE);
auto *booleanNode = AllocNode<ir::BooleanLiteral>(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_TRUE);
ES2PANDA_ASSERT(booleanNode != nullptr);
booleanNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return booleanNode;
}
ir::NullLiteral *ParserImpl::ParseNullLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_NULL);
auto *nullNode = AllocNode<ir::NullLiteral>();
ES2PANDA_ASSERT(nullNode != nullptr);
nullNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return nullNode;
}
ir::Literal *ParserImpl::ParseNumberLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_NUMBER);
ir::Literal *numberNode {};
if ((lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0U) {
numberNode = AllocNode<ir::BigIntLiteral>(lexer_->GetToken().BigInt());
} else {
numberNode = AllocNode<ir::NumberLiteral>(lexer_->GetToken().GetNumber());
}
ES2PANDA_ASSERT(numberNode != nullptr);
numberNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return numberNode;
}
ir::CharLiteral *ParserImpl::ParseCharLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_CHAR);
auto *charNode = AllocNode<ir::CharLiteral>(lexer_->GetToken().Utf16());
ES2PANDA_ASSERT(charNode != nullptr);
charNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return charNode;
}
ir::StringLiteral *ParserImpl::ParseStringLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING);
auto *stringNode = AllocNode<ir::StringLiteral>(lexer_->GetToken().String());
ES2PANDA_ASSERT(stringNode != nullptr);
stringNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return stringNode;
}
ir::UndefinedLiteral *ParserImpl::ParseUndefinedLiteral()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_UNDEFINED);
auto *undefinedNode = AllocNode<ir::UndefinedLiteral>();
ES2PANDA_ASSERT(undefinedNode != nullptr);
undefinedNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return undefinedNode;
}
ir::ThisExpression *ParserImpl::ParseThisExpression()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_THIS);
auto *thisExprNode = AllocNode<ir::ThisExpression>();
ES2PANDA_ASSERT(thisExprNode);
thisExprNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return thisExprNode;
}
ir::RegExpLiteral *ParserImpl::ParseRegularExpression()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_DIVIDE ||
lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL);
lexer_->ResetTokenEnd();
auto regexp = lexer_->ScanRegExp();
lexer::RegExpParser reParser(regexp, Allocator(), this);
reParser.ParsePattern();
auto *regexpNode = AllocNode<ir::RegExpLiteral>(regexp.patternStr, regexp.flags, regexp.flagsStr);
ES2PANDA_ASSERT(regexpNode != nullptr);
regexpNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return regexpNode;
}
ir::SuperExpression *ParserImpl::ParseSuperExpression()
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_SUPER);
auto *superExprNode = AllocNode<ir::SuperExpression>();
ES2PANDA_ASSERT(superExprNode != nullptr);
superExprNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
if ((lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD ||
lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) &&
(context_.Status() & ParserStatus::ALLOW_SUPER) != 0U) {
return superExprNode;
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
(context_.Status() & ParserStatus::ALLOW_SUPER_CALL) != 0U) {
return superExprNode;
}
LogError(diagnostic::UNEXPECTED_SUPER);
return superExprNode;
}
ir::Expression *ParserImpl::ParsePrimaryExpressionWithLiterals(ExpressionParseFlags flags)
{
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::LITERAL_IDENT:
return ParsePrimaryExpressionIdent(flags);
case lexer::TokenType::LITERAL_TRUE:
case lexer::TokenType::LITERAL_FALSE:
return ParseBooleanLiteral();
case lexer::TokenType::LITERAL_NULL:
return ParseNullLiteral();
case lexer::TokenType::KEYW_UNDEFINED:
return ParseUndefinedLiteral();
case lexer::TokenType::LITERAL_NUMBER:
return ParseNumberLiteral();
case lexer::TokenType::LITERAL_STRING:
return ParseStringLiteral();
default:
LogUnexpectedToken(lexer_->GetToken());
return AllocBrokenExpression(Lexer()->GetToken().Loc());
}
}
ir::Expression *ParserImpl::ParseHashMaskOperator()
{
if (!ValidatePrivateIdentifier()) {
return AllocBrokenExpression(Lexer()->GetToken().Loc());
}
auto *privateIdent = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(privateIdent != nullptr);
privateIdent->SetPrivate(true);
lexer_->NextToken();
if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_IN) {
LogError(diagnostic::UNEXPECTED_PRIVATE);
lexer_->GetToken().SetTokenType(lexer::TokenType::KEYW_IN);
}
return privateIdent;
}
ir::Expression *ParserImpl::ParseClassExpression()
{
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
ir::ClassDefinition *classDefinition = ParseClassDefinition(ir::ClassDefinitionModifiers::ID_REQUIRED);
if (classDefinition == nullptr) {
return AllocBrokenExpression(startLoc);
}
auto *classExpr = AllocNode<ir::ClassExpression>(classDefinition);
ES2PANDA_ASSERT(classExpr != nullptr);
classExpr->SetRange({startLoc, classDefinition->End()});
return classExpr;
}
ir::Expression *ParserImpl::ParsePunctuators(ExpressionParseFlags flags)
{
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_DIVIDE:
case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
return ParseRegularExpression();
}
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
return ParseArrayExpression(CarryPatternFlags(flags));
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
return ParseCoverParenthesizedExpressionAndArrowParameterList();
}
case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: {
return ParseObjectExpression(CarryPatternFlags(flags));
}
case lexer::TokenType::PUNCTUATOR_BACK_TICK: {
return ParseTemplateLiteral();
}
case lexer::TokenType::PUNCTUATOR_HASH_MARK: {
return ParseHashMaskOperator();
}
case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
return ParsePrefixAssertionExpression();
}
default: {
ES2PANDA_UNREACHABLE();
}
}
}
ir::Expression *ParserImpl::ParsePrimaryExpression(ExpressionParseFlags flags)
{
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::KEYW_IMPORT:
return ParseImportExpression();
case lexer::TokenType::PUNCTUATOR_DIVIDE:
case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET:
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS:
case lexer::TokenType::PUNCTUATOR_LEFT_BRACE:
case lexer::TokenType::PUNCTUATOR_BACK_TICK:
case lexer::TokenType::PUNCTUATOR_HASH_MARK:
case lexer::TokenType::PUNCTUATOR_LESS_THAN:
return ParsePunctuators(flags);
case lexer::TokenType::KEYW_FUNCTION:
return ParseFunctionExpression();
case lexer::TokenType::KEYW_CLASS:
return ParseClassExpression();
case lexer::TokenType::KEYW_THIS:
return ParseThisExpression();
case lexer::TokenType::KEYW_TYPEOF:
return ParseUnaryOrPrefixUpdateExpression();
case lexer::TokenType::KEYW_SUPER:
return ParseSuperExpression();
case lexer::TokenType::KEYW_NEW: {
ir::MetaProperty *newTarget = ParsePotentialNewTarget();
if (newTarget != nullptr) {
return newTarget;
}
return ParseNewExpression();
}
default:
return ParsePrimaryExpressionWithLiterals(flags);
}
}
static constexpr size_t GetOperatorPrecedenceArithmeticAndComparison(const lexer::TokenType operatorType)
{
switch (operatorType) {
case lexer::TokenType::PUNCTUATOR_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_EQUAL:
case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL:
case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: {
constexpr auto PRECEDENCE = 8;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_LESS_THAN:
case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL:
case lexer::TokenType::KEYW_INSTANCEOF:
case lexer::TokenType::KEYW_IN: {
constexpr auto PRECEDENCE = 9;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_PLUS:
case lexer::TokenType::PUNCTUATOR_MINUS: {
constexpr auto PRECEDENCE = 12;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_MULTIPLY:
case lexer::TokenType::PUNCTUATOR_DIVIDE:
case lexer::TokenType::PUNCTUATOR_MOD: {
constexpr auto PRECEDENCE = 13;
return PRECEDENCE;
}
default: {
ES2PANDA_UNREACHABLE();
}
}
}
static constexpr size_t GetOperatorPrecedence(const lexer::TokenType operatorType)
{
ES2PANDA_ASSERT(operatorType == lexer::TokenType::KEYW_AS || lexer::Token::IsBinaryToken(operatorType));
switch (operatorType) {
case lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING: {
constexpr auto PRECEDENCE = 1;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: {
constexpr auto PRECEDENCE = 2;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: {
constexpr auto PRECEDENCE = 4;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_BITWISE_OR: {
constexpr auto PRECEDENCE = 5;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: {
constexpr auto PRECEDENCE = 6;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_BITWISE_AND: {
constexpr auto PRECEDENCE = 7;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: {
constexpr auto PRECEDENCE = 10;
return PRECEDENCE;
}
case lexer::TokenType::KEYW_AS: {
constexpr auto PRECEDENCE = 11;
return PRECEDENCE;
}
case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: {
constexpr auto PRECEDENCE = 14;
return PRECEDENCE;
}
default: {
return GetOperatorPrecedenceArithmeticAndComparison(operatorType);
}
}
}
static inline bool ShouldBinaryExpressionBeAmended(const ir::BinaryExpression *const binaryExpression,
const lexer::TokenType operatorType)
{
return GetOperatorPrecedence(binaryExpression->OperatorType()) <= GetOperatorPrecedence(operatorType) &&
!binaryExpression->IsGrouped() &&
(operatorType != lexer::TokenType::PUNCTUATOR_EXPONENTIATION ||
binaryExpression->OperatorType() != lexer::TokenType::PUNCTUATOR_EXPONENTIATION);
}
static inline bool ShouldAsExpressionBeAmended(const ir::TSAsExpression *const asExpression,
const lexer::TokenType operatorType)
{
return GetOperatorPrecedence(lexer::TokenType::KEYW_AS) <= GetOperatorPrecedence(operatorType) &&
!asExpression->IsGrouped() && operatorType != lexer::TokenType::PUNCTUATOR_EXPONENTIATION;
}
static inline bool ShouldExpressionBeAmended(const ir::Expression *const expression,
const lexer::TokenType operatorType)
{
bool shouldBeAmended = false;
if (expression->IsBinaryExpression()) {
shouldBeAmended = ShouldBinaryExpressionBeAmended(expression->AsBinaryExpression(), operatorType);
} else if (expression->IsTSAsExpression()) {
shouldBeAmended = ShouldAsExpressionBeAmended(expression->AsTSAsExpression(), operatorType);
}
return shouldBeAmended;
}
static inline bool AreLogicalAndNullishMixedIncorrectly(const ir::Expression *const expression,
const lexer::TokenType operatorType)
{
return ((operatorType == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
operatorType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) &&
expression->IsBinaryExpression() &&
expression->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING &&
!expression->IsGrouped()) ||
(operatorType == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING && expression->IsBinaryExpression() &&
(expression->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
expression->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) &&
!expression->IsGrouped());
}
static inline ir::Expression *GetAmendedChildExpression(ir::Expression *const expression)
{
ir::Expression *amendedChild = nullptr;
if (expression->IsBinaryExpression()) {
amendedChild = expression->AsBinaryExpression()->Left();
} else if (expression->IsTSAsExpression()) {
amendedChild = expression->AsTSAsExpression()->Expr();
} else {
ES2PANDA_UNREACHABLE();
}
return amendedChild;
}
static inline void SetAmendedChildExpression(ir::Expression *const parent, ir::Expression *const amended)
{
if (parent->IsBinaryExpression()) {
parent->AsBinaryExpression()->SetLeft(amended);
amended->SetParent(parent);
} else if (parent->IsTSAsExpression()) {
parent->AsTSAsExpression()->SetExpr(amended);
amended->SetParent(parent);
} else {
ES2PANDA_UNREACHABLE();
}
}
void ParserImpl::CreateAmendedBinaryExpression(ir::Expression *const left, ir::Expression *const right,
const lexer::TokenType operatorType)
{
auto *amended = GetAmendedChildExpression(right);
amended->SetParent(nullptr);
auto *binaryExpr = AllocNode<ir::BinaryExpression>(left, amended, operatorType);
ES2PANDA_ASSERT(binaryExpr != nullptr);
binaryExpr->SetRange({left->Start(), amended->End()});
SetAmendedChildExpression(right, binaryExpr);
}
ir::Expression *ParserImpl::ParseExpressionOrTypeAnnotation([[maybe_unused]] lexer::TokenType type,
[[maybe_unused]] ExpressionParseFlags flags)
{
return ParseExpression(ExpressionParseFlags::DISALLOW_YIELD);
}
static ir::Expression *FindAndAmendChildExpression(ir::Expression *expression, const ir::Expression *left,
lexer::TokenType operatorType)
{
bool shouldBeAmended = true;
ir::Expression *parentExpression = nullptr;
while (shouldBeAmended && GetAmendedChildExpression(expression)->IsBinaryExpression()) {
parentExpression = expression;
parentExpression->SetStart(left->Start());
expression = GetAmendedChildExpression(expression);
shouldBeAmended = ShouldExpressionBeAmended(expression, operatorType);
}
return shouldBeAmended ? expression : parentExpression;
}
ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left, ExpressionParseFlags flags)
{
lexer::TokenType operatorType = lexer_->GetToken().Type();
ES2PANDA_ASSERT(lexer::Token::IsBinaryToken(operatorType));
if (operatorType == lexer::TokenType::PUNCTUATOR_EXPONENTIATION) {
if ((left->IsUnaryExpression() || left->IsTypeofExpression()) && !left->IsGrouped()) {
LogError(diagnostic::ILLEGAL_EXPRESSION_WRAP);
}
}
lexer_->NextToken();
ExpressionParseFlags newFlags = ExpressionParseFlags::DISALLOW_YIELD;
if ((operatorType == lexer::TokenType::KEYW_INSTANCEOF) || ((flags & ExpressionParseFlags::INSTANCEOF) != 0)) {
newFlags |= ExpressionParseFlags::INSTANCEOF;
}
ir::Expression *rightExpr = ParseExpressionOrTypeAnnotation(operatorType, ExpressionParseFlags::DISALLOW_YIELD);
if (operatorType == lexer::TokenType::KEYW_IN && !IsInOperatorTypeSupported()) {
LogError(diagnostic::UNSUPPORTED_IN_OPERATOR_TYPE);
return AllocBrokenExpression(lexer::SourceRange {left->Start(), rightExpr->End()});
}
ir::ConditionalExpression *conditionalExpr = nullptr;
if (rightExpr->IsConditionalExpression() && !rightExpr->IsGrouped()) {
conditionalExpr = rightExpr->AsConditionalExpression();
rightExpr = conditionalExpr->Test();
}
if (ShouldExpressionBeAmended(rightExpr, operatorType)) {
if (AreLogicalAndNullishMixedIncorrectly(rightExpr, operatorType)) {
LogError(diagnostic::NULLISH_COALESCING_MISSING_PARENS);
}
ir::Expression *expression = FindAndAmendChildExpression(rightExpr, left, operatorType);
CreateAmendedBinaryExpression(left, expression, operatorType);
} else {
if (AreLogicalAndNullishMixedIncorrectly(rightExpr, operatorType)) {
LogError(diagnostic::NULLISH_COALESCING_MISSING_PARENS);
}
const lexer::SourcePosition &endPos = rightExpr->End();
rightExpr = AllocNode<ir::BinaryExpression>(left, rightExpr, operatorType);
ES2PANDA_ASSERT(rightExpr != nullptr);
rightExpr->SetRange({left->Start(), endPos});
}
if (conditionalExpr != nullptr) {
conditionalExpr->SetStart(rightExpr->Start());
conditionalExpr->SetTest(rightExpr);
return conditionalExpr;
}
return rightExpr;
}
ArenaVector<ir::Expression *> ParserImpl::ParseCallExpressionArguments(bool &trailingComma,
lexer::SourcePosition &endLoc)
{
ArenaVector<ir::Expression *> arguments(Allocator()->Adapter());
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
arguments = std::move(ParseExpressionsArrayFormatPlaceholder());
endLoc = Lexer()->GetToken().End();
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
} else {
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE,
[this, &trailingComma, &arguments](bool &) {
trailingComma = false;
ir::Expression *argument {};
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
argument = ParseSpreadElement();
} else {
argument = ParseExpression();
}
arguments.push_back(argument);
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
trailingComma = true;
}
return true;
},
&endLoc, ParseListOptions::ALLOW_TRAILING_SEP);
}
return arguments;
}
ir::CallExpression *ParserImpl::ParseCallExpression(ir::Expression *callee, bool isOptionalChain, bool handleEval)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
bool trailingComma {};
while (true) {
lexer_->NextToken();
lexer::SourcePosition endLoc;
ArenaVector<ir::Expression *> arguments = ParseCallExpressionArguments(trailingComma, endLoc);
ir::CallExpression *callExpr {};
if (!isOptionalChain && handleEval && callee->IsIdentifier() && callee->AsIdentifier()->Name().Is("eval")) {
auto parserStatus = static_cast<uint32_t>(context_.Status() | ParserStatus::DIRECT_EVAL);
callExpr = AllocNode<ir::DirectEvalExpression>(callee, std::move(arguments), nullptr, isOptionalChain,
parserStatus);
} else {
callExpr =
AllocNode<ir::CallExpression>(callee, std::move(arguments), nullptr, isOptionalChain, trailingComma);
}
ES2PANDA_ASSERT(callExpr != nullptr);
callExpr->SetEnd(endLoc);
callExpr->SetStart(callee->Start());
isOptionalChain = false;
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
ParseTrailingBlock(callExpr);
if (callExpr->TrailingBlock() != nullptr) {
callExpr->SetRange({callee->Start(), callExpr->TrailingBlock()->End()});
}
return callExpr;
}
callee = callExpr;
}
ES2PANDA_UNREACHABLE();
}
ir::Expression *ParserImpl::ParseOptionalChain(ir::Expression *leftSideExpr)
{
ir::Expression *returnExpression = nullptr;
bool isPrivate = false;
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) {
isPrivate = true;
ValidatePrivateIdentifier();
}
const auto tokenType = lexer_->GetToken().Type();
if (tokenType == lexer::TokenType::LITERAL_IDENT) {
auto *identNode = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(identNode != nullptr);
identNode->SetPrivate(isPrivate);
identNode->SetRange(lexer_->GetToken().Loc());
returnExpression = AllocNode<ir::MemberExpression>(leftSideExpr, identNode,
ir::MemberExpressionKind::PROPERTY_ACCESS, false, true);
ES2PANDA_ASSERT(returnExpression != nullptr);
returnExpression->SetRange({leftSideExpr->Start(), identNode->End()});
lexer_->NextToken();
}
if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
lexer_->NextToken();
ir::Expression *propertyNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
auto endLoc = lexer_->GetToken().End();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
}
returnExpression = AllocNode<ir::MemberExpression>(leftSideExpr, propertyNode,
ir::MemberExpressionKind::ELEMENT_ACCESS, true, true);
ES2PANDA_ASSERT(returnExpression != nullptr);
returnExpression->SetRange({leftSideExpr->Start(), endLoc});
lexer_->NextToken();
}
if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
returnExpression = ParseCallExpression(leftSideExpr, true);
}
if (tokenType == lexer::TokenType::PUNCTUATOR_BACK_TICK ||
lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BACK_TICK) {
LogError(diagnostic::TAGGED_TEMPLATE_LITERALS_IN_OPTIONALCHAIN);
return AllocBrokenExpression(lexer_->GetToken().Loc());
}
return returnExpression;
}
ir::ArrowFunctionExpression *ParserImpl::ParsePotentialArrowExpression(ir::Expression **returnExpression,
const lexer::SourcePosition &startLoc)
{
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::KEYW_FUNCTION: {
*returnExpression = ParseFunctionExpression(ParserStatus::ASYNC_FUNCTION);
ES2PANDA_ASSERT(returnExpression != nullptr);
(*returnExpression)->SetStart(startLoc);
break;
}
case lexer::TokenType::LITERAL_IDENT: {
ir::Expression *identRef = ParsePrimaryExpression();
ES2PANDA_ASSERT(identRef->IsIdentifier());
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_ARROW);
}
ir::ArrowFunctionExpression *arrowFuncExpr = ParseArrowFunctionExpression(identRef, nullptr, nullptr, true);
arrowFuncExpr->SetStart(startLoc);
return arrowFuncExpr;
}
case lexer::TokenType::PUNCTUATOR_ARROW: {
ir::ArrowFunctionExpression *arrowFuncExpr =
ParseArrowFunctionExpression(*returnExpression, nullptr, nullptr, true);
arrowFuncExpr->SetStart(startLoc);
return arrowFuncExpr;
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
ir::CallExpression *callExpression = ParseCallExpression(*returnExpression, false);
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) {
ir::ArrowFunctionExpression *arrowFuncExpr =
ParseArrowFunctionExpression(callExpression, nullptr, nullptr, true);
arrowFuncExpr->SetStart(startLoc);
return arrowFuncExpr;
}
*returnExpression = callExpression;
break;
}
default: {
break;
}
}
return nullptr;
}
bool ParserImpl::ParsePotentialGenericFunctionCall([[maybe_unused]] ir::Expression *primaryExpr,
[[maybe_unused]] ir::Expression **returnExpression,
[[maybe_unused]] const lexer::SourcePosition &startLoc,
[[maybe_unused]] bool ignoreCallExpression)
{
return true;
}
bool ParserImpl::ParsePotentialNonNullExpression([[maybe_unused]] ir::Expression **returnExpression,
[[maybe_unused]] lexer::SourcePosition startLoc)
{
return true;
}
ir::Expression *ParserImpl::ParsePotentialAsExpression([[maybe_unused]] ir::Expression *primaryExpression)
{
return nullptr;
}
ir::MemberExpression *ParserImpl::ParseElementAccess(ir::Expression *primaryExpr, bool isOptional)
{
lexer_->NextToken();
ir::Expression *propertyNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
}
auto *memberExpr = AllocNode<ir::MemberExpression>(primaryExpr, propertyNode,
ir::MemberExpressionKind::ELEMENT_ACCESS, true, isOptional);
ES2PANDA_ASSERT(memberExpr != nullptr);
memberExpr->SetRange({primaryExpr->Start(), lexer_->GetToken().End()});
lexer_->NextToken();
return memberExpr;
}
ir::MemberExpression *ParserImpl::ParsePrivatePropertyAccess(ir::Expression *primaryExpr)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK);
lexer::SourcePosition memberStart = lexer_->GetToken().Start();
ValidatePrivateIdentifier();
auto *privateIdent = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(privateIdent != nullptr);
if (program_->Extension() == util::gen::extension::ETS && privateIdent->Name().Is("prototype")) {
LogError(diagnostic::PROTOTYPE_ACCESS);
}
privateIdent->SetRange({memberStart, lexer_->GetToken().End()});
privateIdent->SetPrivate(true);
lexer_->NextToken();
auto *memberExpr = AllocNode<ir::MemberExpression>(primaryExpr, privateIdent,
ir::MemberExpressionKind::PROPERTY_ACCESS, false, false);
ES2PANDA_ASSERT(memberExpr != nullptr);
memberExpr->SetRange({primaryExpr->Start(), privateIdent->End()});
return memberExpr;
}
ir::MemberExpression *ParserImpl::ParsePropertyAccess(ir::Expression *primaryExpr, lexer::SourcePosition periodPos,
bool isOptional)
{
ir::Identifier *ident = ExpectIdentifier(true);
ident->SetRange({periodPos, ident->Range().end});
if (program_->Extension() == util::gen::extension::ETS && ident->Name().Is("prototype")) {
LogError(diagnostic::PROTOTYPE_ACCESS);
}
auto *memberExpr = AllocNode<ir::MemberExpression>(primaryExpr, ident, ir::MemberExpressionKind::PROPERTY_ACCESS,
false, isOptional);
ES2PANDA_ASSERT(memberExpr != nullptr);
memberExpr->SetRange({primaryExpr->Start(), ident->End()});
return memberExpr;
}
ir::Expression *ParserImpl::ParsePostPrimaryExpression(ir::Expression *primaryExpr, lexer::SourcePosition startLoc,
bool ignoreCallExpression, bool *isChainExpression)
{
ir::Expression *returnExpr = primaryExpr;
while (true) {
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
returnExpr = ParseElementAccess(returnExpr);
continue;
}
case lexer::TokenType::LITERAL_IDENT: {
if (auto *asExpression = ParsePotentialAsExpression(returnExpr); asExpression != nullptr) {
return asExpression;
}
break;
}
case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
if (ParsePotentialGenericFunctionCall(primaryExpr, &returnExpr, startLoc, ignoreCallExpression)) {
break;
}
continue;
}
case lexer::TokenType::PUNCTUATOR_BACK_TICK: {
returnExpr = ParsePostPrimaryExpressionBackTick(returnExpr, startLoc);
continue;
}
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
if (ignoreCallExpression) {
break;
}
returnExpr = ParseCallExpression(returnExpr, false);
continue;
}
case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: {
if (ParsePotentialNonNullExpression(&returnExpr, startLoc)) {
break;
}
continue;
}
default: {
auto tmp = ParsePostPrimaryExpressionDot(returnExpr, lexer_->GetToken().Type(), isChainExpression);
if (tmp != nullptr) {
returnExpr = tmp;
continue;
}
}
}
break;
}
return returnExpr;
}
ir::Expression *ParserImpl::ParsePostPrimaryExpressionBackTick(ir::Expression *returnExpression,
const lexer::SourcePosition startLoc)
{
ir::TemplateLiteral *propertyNode = ParseTemplateLiteral();
ES2PANDA_ASSERT(propertyNode != nullptr);
lexer::SourcePosition endLoc = propertyNode->End();
returnExpression = AllocNode<ir::TaggedTemplateExpression>(returnExpression, propertyNode, nullptr);
ES2PANDA_ASSERT(returnExpression != nullptr);
returnExpression->SetRange({startLoc, endLoc});
return returnExpression;
}
ir::Expression *ParserImpl::ParsePostPrimaryExpressionDot(ir::Expression *returnExpression,
const lexer::TokenType tokenType, bool *isChainExpression)
{
switch (tokenType) {
case lexer::TokenType::PUNCTUATOR_QUESTION_DOT: {
*isChainExpression = true;
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
return ParseOptionalChain(returnExpression);
}
case lexer::TokenType::PUNCTUATOR_PERIOD: {
auto periodPos = Lexer()->GetToken().End();
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) {
return ParsePrivatePropertyAccess(returnExpression);
}
return ParsePropertyAccess(returnExpression, periodPos);
}
default: {
return nullptr;
}
}
}
void ParserImpl::ValidateUpdateExpression(ir::Expression *returnExpression, bool isChainExpression)
{
if ((!returnExpression->IsMemberExpression() && !returnExpression->IsIdentifier() &&
!returnExpression->IsTSNonNullExpression()) ||
isChainExpression) {
LogError(diagnostic::INVALID_LEFT_SITE_OPERATOR);
}
if (returnExpression->IsIdentifier()) {
const util::StringView &returnExpressionStr = returnExpression->AsIdentifier()->Name();
if (returnExpressionStr.Is("eval")) {
LogError(diagnostic::ASSIGN_TO_EVAL_INVALID);
}
if (returnExpressionStr.Is("arguments")) {
LogError(diagnostic::ASSIGN_TO_ARGS_INVALID);
}
}
}
ir::Expression *ParserImpl::SetupChainExpr(ir::Expression *const top, lexer::SourcePosition startLoc)
{
auto expr = top;
while (expr->IsTSNonNullExpression()) {
expr = expr->AsTSNonNullExpression()->Expr();
}
auto chainParent = expr->Parent();
lexer::SourcePosition endLoc = expr->End();
auto chain = AllocNode<ir::ChainExpression>(expr);
ES2PANDA_ASSERT(chain != nullptr);
chain->SetRange({startLoc, endLoc});
if (expr == top) {
return chain;
}
chainParent->AsTSNonNullExpression()->SetExpr(chain);
chain->SetParent(chainParent);
return top;
}
ir::Expression *ParserImpl::ParseMemberExpression(bool ignoreCallExpression, ExpressionParseFlags flags)
{
bool isAsync = lexer_->GetToken().IsAsyncModifier();
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
ir::Expression *returnExpression = ParsePrimaryExpression(flags);
if (lexer_->GetToken().NewLine() && returnExpression->IsArrowFunctionExpression()) {
return returnExpression;
}
if (isAsync && !lexer_->GetToken().NewLine()) {
context_.Status() |= ParserStatus::ASYNC_FUNCTION;
ir::ArrowFunctionExpression *arrow = ParsePotentialArrowExpression(&returnExpression, startLoc);
if (arrow != nullptr) {
return arrow;
}
}
bool isChainExpression;
ir::Expression *prevExpression;
do {
isChainExpression = false;
prevExpression = returnExpression;
returnExpression =
ParsePostPrimaryExpression(returnExpression, startLoc, ignoreCallExpression, &isChainExpression);
if (isChainExpression) {
returnExpression = SetupChainExpr(returnExpression, startLoc);
}
} while (prevExpression != returnExpression);
if (!lexer_->GetToken().NewLine() && lexer::Token::IsUpdateToken(lexer_->GetToken().Type())) {
lexer::SourcePosition start = returnExpression->Start();
ValidateUpdateExpression(returnExpression, isChainExpression);
returnExpression = AllocNode<ir::UpdateExpression>(returnExpression, lexer_->GetToken().Type(), false);
ES2PANDA_ASSERT(returnExpression != nullptr);
returnExpression->SetRange({start, lexer_->GetToken().End()});
lexer_->NextToken();
}
return returnExpression;
}
ir::Expression *ParserImpl::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault)
{
ir::Expression *returnNode = nullptr;
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
returnNode = ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN);
break;
}
case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: {
if ((flags & ExpressionParseFlags::IN_REST) != 0) {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
returnNode = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN);
break;
}
case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: {
returnNode =
ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN | ExpressionParseFlags::OBJECT_PATTERN);
break;
}
case lexer::TokenType::LITERAL_IDENT: {
returnNode = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
returnNode->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
break;
}
default: {
LogError(diagnostic::UNEXPECTED_TOKEN);
returnNode = AllocBrokenExpression(Lexer()->GetToken().Loc());
}
}
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
return returnNode;
}
ParsePatternElementErrorCheck(flags, allowDefault);
ir::Expression *rightNode = ParseExpression();
auto *assignmentExpression = AllocNode<ir::AssignmentExpression>(
ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
ES2PANDA_ASSERT(assignmentExpression != nullptr);
assignmentExpression->SetRange({returnNode->Start(), rightNode->End()});
return assignmentExpression;
}
void ParserImpl::ParsePatternElementErrorCheck(const ExpressionParseFlags flags, const bool allowDefault)
{
if ((flags & ExpressionParseFlags::IN_REST) != 0) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
}
if (!allowDefault) {
LogError(diagnostic::INVALID_DESTRUCTURING_TARGET);
}
lexer_->NextToken();
if (context_.IsGenerator() && lexer_->GetToken().Type() == lexer::TokenType::KEYW_YIELD) {
LogError(diagnostic::YIELD_IN_GENERATOR_PARAM);
}
if (context_.IsAsync() && lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT) {
LogError(diagnostic::ILLEGAL_AWAIT_IN_ASYNC_FUN);
}
}
void ParserImpl::CheckPropertyKeyAsyncModifier(ParserStatus *methodStatus)
{
const auto asyncPos = lexer_->Save();
lexer_->NextToken();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
if (lexer_->GetToken().NewLine()) {
LogError(diagnostic::ASYNC_METHOD_LINE_TERM);
}
*methodStatus |= ParserStatus::ASYNC_FUNCTION;
} else {
lexer_->Rewind(asyncPos);
}
}
static bool IsAccessorDelimiter(char32_t cp)
{
switch (cp) {
case lexer::LEX_CHAR_LEFT_PAREN:
case lexer::LEX_CHAR_COLON:
case lexer::LEX_CHAR_COMMA:
case lexer::LEX_CHAR_RIGHT_BRACE: {
return true;
}
default: {
return false;
}
}
}
static bool IsShorthandDelimiter(char32_t cp)
{
switch (cp) {
case lexer::LEX_CHAR_EQUALS:
case lexer::LEX_CHAR_COMMA:
case lexer::LEX_CHAR_RIGHT_BRACE: {
return true;
}
default: {
return false;
}
}
}
void ParserImpl::ValidateAccessor(ExpressionParseFlags flags)
{
if ((flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0) {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
}
ir::Property *ParserImpl::ParseShorthandProperty(const lexer::LexerPosition *startPos)
{
char32_t nextCp = lexer_->Lookahead();
lexer::TokenType keywordType = lexer_->GetToken().KeywordType();
* identifier */
lexer_->Rewind(*startPos);
lexer_->NextToken();
lexer::SourcePosition start = lexer_->GetToken().Start();
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
const util::StringView &ident = lexer_->GetToken().Ident();
auto *key = AllocNode<ir::Identifier>(ident, Allocator());
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(lexer_->GetToken().Loc());
ir::Expression *value = AllocNode<ir::Identifier>(ident, Allocator());
value->SetRange(lexer_->GetToken().Loc());
lexer::SourcePosition end;
if (nextCp == lexer::LEX_CHAR_EQUALS) {
CheckRestrictedBinding(keywordType);
lexer_->NextToken();
lexer_->NextToken();
ir::Expression *rightNode = ParseExpression();
auto *assignmentExpression = AllocNode<ir::AssignmentExpression>(
ir::AstNodeType::ASSIGNMENT_PATTERN, value, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
ES2PANDA_ASSERT(assignmentExpression != nullptr);
assignmentExpression->SetRange({value->Start(), rightNode->End()});
end = rightNode->End();
value = assignmentExpression;
} else {
end = lexer_->GetToken().End();
lexer_->NextToken();
}
auto *returnProperty = AllocNode<ir::Property>(key, value);
ES2PANDA_ASSERT(returnProperty != nullptr);
returnProperty->SetRange({start, end});
return returnProperty;
}
bool ParserImpl::ParsePropertyModifiers(ExpressionParseFlags flags, ir::PropertyKind *propertyKind,
ParserStatus *methodStatus)
{
if (lexer_->GetToken().IsAsyncModifier()) {
CheckPropertyKeyAsyncModifier(methodStatus);
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
if ((flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0) {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
lexer_->NextToken();
*methodStatus |= ParserStatus::GENERATOR_FUNCTION;
}
char32_t nextCp = lexer_->Lookahead();
lexer::TokenType keywordType = lexer_->GetToken().KeywordType();
if (keywordType == lexer::TokenType::KEYW_GET && !IsAccessorDelimiter(nextCp)) {
ValidateAccessor(flags);
*propertyKind = ir::PropertyKind::GET;
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
return false;
}
if (keywordType == lexer::TokenType::KEYW_SET && !IsAccessorDelimiter(nextCp)) {
ValidateAccessor(flags);
*propertyKind = ir::PropertyKind::SET;
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
return false;
}
return (IsShorthandDelimiter(nextCp) && (*methodStatus & ParserStatus::ASYNC_FUNCTION) == 0);
}
void ParserImpl::ParseGeneratorPropertyModifier(ExpressionParseFlags flags, ParserStatus *methodStatus)
{
if ((flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0) {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
*methodStatus |= ParserStatus::GENERATOR_FUNCTION;
}
ir::Expression *ParserImpl::ParsePropertyKey(ExpressionParseFlags flags)
{
ir::Expression *key = nullptr;
switch (lexer_->GetToken().Type()) {
case lexer::TokenType::LITERAL_IDENT: {
const util::StringView &ident = lexer_->GetToken().Ident();
key = AllocNode<ir::Identifier>(ident, Allocator());
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return key;
}
case lexer::TokenType::LITERAL_STRING: {
const util::StringView &string = lexer_->GetToken().String();
key = AllocNode<ir::StringLiteral>(string);
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return key;
}
case lexer::TokenType::LITERAL_NUMBER: {
if ((lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0) {
key = AllocNode<ir::BigIntLiteral>(lexer_->GetToken().BigInt());
} else {
key = AllocNode<ir::NumberLiteral>(lexer_->GetToken().GetNumber());
}
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return key;
}
case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: {
lexer_->NextToken();
key = ParseExpression(flags | ExpressionParseFlags::ACCEPT_COMMA);
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET);
}
lexer_->NextToken();
return key;
}
default: {
const auto &rangeToken = Lexer()->GetToken().Loc();
LogError(diagnostic::UNEXPECTED_TOKEN);
lexer_->NextToken();
return AllocBrokenExpression(rangeToken);
}
}
}
ir::Expression *ParserImpl::ParsePropertyValue(const ir::PropertyKind propertyKind, const ParserStatus methodStatus,
ExpressionParseFlags flags)
{
bool isMethod = (methodStatus & ParserStatus::FUNCTION) != 0U;
bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0U;
if (!isMethod && !ir::Property::IsAccessorKind(propertyKind)) {
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
if (lexer::Token::IsPunctuatorToken(lexer_->GetToken().Type())) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_COLON);
lexer_->NextToken();
} else {
LogError(diagnostic::UNEXPECTED_TOKEN);
}
} else {
lexer_->NextToken();
}
if (!inPattern) {
return ParseExpression(flags);
}
return ParsePatternElement();
}
if (inPattern) {
LogError(diagnostic::OBJECT_PATTER_CONTAIN_METHODS);
}
ParserStatus newStatus = methodStatus | ParserStatus::FUNCTION | ParserStatus::ALLOW_SUPER;
if (propertyKind != ir::PropertyKind::SET) {
newStatus |= ParserStatus::NEED_RETURN_TYPE;
}
ir::ScriptFunction *methodDefinitonNode = ParseFunction(newStatus);
ES2PANDA_ASSERT(methodDefinitonNode != nullptr);
methodDefinitonNode->AddFlag(ir::ScriptFunctionFlags::METHOD);
size_t paramsSize = methodDefinitonNode->Params().size();
auto *value = AllocNode<ir::FunctionExpression>(methodDefinitonNode);
ES2PANDA_ASSERT(value != nullptr);
value->SetRange(methodDefinitonNode->Range());
if (propertyKind == ir::PropertyKind::SET && paramsSize != 1) {
LogError(diagnostic::SETTER_FORMAL_PARAMS);
}
if (propertyKind == ir::PropertyKind::GET && paramsSize != 0) {
LogError(diagnostic::GETTER_FORMAL_PARAMS);
}
return value;
}
ir::Expression *ParserImpl::ParsePropertyDefinition(ExpressionParseFlags const flags)
{
ir::PropertyKind propertyKind = ir::PropertyKind::INIT;
ParserStatus methodStatus = ParserStatus::NO_OPTS;
const auto startPos = lexer_->Save();
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
lexer::SourcePosition start = lexer_->GetToken().Start();
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
return ParseSpreadElement(flags);
}
if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
if (ParsePropertyModifiers(flags, &propertyKind, &methodStatus)) {
return ParseShorthandProperty(&startPos);
}
} else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseGeneratorPropertyModifier(flags, &methodStatus);
}
bool isComputed = lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET;
ir::Expression *key = ParsePropertyKey(flags);
if ((lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) &&
!ir::Property::IsAccessorKind(propertyKind)) {
methodStatus |= ParserStatus::FUNCTION | ParserStatus::ALLOW_SUPER;
propertyKind = ir::PropertyKind::INIT;
} else if ((methodStatus & (ParserStatus::GENERATOR_FUNCTION | ParserStatus::ASYNC_FUNCTION)) != 0) {
LogError(diagnostic::UNEXPECTED_ID);
}
ir::Expression *value = ParsePropertyValue(propertyKind, methodStatus, flags);
ES2PANDA_ASSERT(value != nullptr);
lexer::SourcePosition end = value->End();
auto *returnProperty =
AllocNode<ir::Property>(propertyKind, key, value, methodStatus != ParserStatus::NO_OPTS, isComputed);
ES2PANDA_ASSERT(returnProperty != nullptr);
returnProperty->SetRange({start, end});
return returnProperty;
}
void ParserImpl::ParsePropertyEndErrorHendler()
{
const auto pos = lexer_->Save();
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
lexer_->NextToken();
if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
lexer_->Rewind(pos);
lexer_->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_COMMA);
} else {
lexer_->Rewind(pos);
if (lexer::Token::IsPunctuatorToken(lexer_->GetToken().Type())) {
lexer_->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE);
}
}
} else {
lexer_->NextToken();
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
lexer_->GetToken().SetTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE);
}
}
}
bool ParserImpl::ParsePropertyEnd()
{
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA &&
lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) {
LogError(diagnostic::UNEXPECTED_TOKEN);
ParsePropertyEndErrorHendler();
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA &&
lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_BRACE) {
lexer_->NextToken();
return true;
}
return false;
}
ir::ObjectExpression *ParserImpl::ParseObjectExpression(ExpressionParseFlags flags)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
lexer::SourcePosition start = lexer_->GetToken().Start();
ArenaVector<ir::Expression *> properties(Allocator()->Adapter());
bool trailingComma = false;
bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN) != 0;
if (lexer_->Lookahead() == lexer::LEX_CHAR_RIGHT_BRACE) {
lexer_->NextToken();
}
while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE &&
lexer_->GetToken().Type() != lexer::TokenType::EOS) {
util::ErrorRecursionGuard infiniteLoopBlocker(lexer_);
ir::Expression *property = ParsePropertyDefinition(flags | ExpressionParseFlags::POTENTIALLY_IN_PATTERN);
if (property != nullptr) {
properties.push_back(property);
}
trailingComma = ParsePropertyEnd();
}
auto nodeType = inPattern ? ir::AstNodeType::OBJECT_PATTERN : ir::AstNodeType::OBJECT_EXPRESSION;
auto *objectExpression =
AllocNode<ir::ObjectExpression>(nodeType, Allocator(), std::move(properties), trailingComma);
ES2PANDA_ASSERT(objectExpression != nullptr);
objectExpression->SetRange({start, lexer_->GetToken().End()});
lexer_->NextToken();
if (inPattern) {
objectExpression->SetDeclaration();
}
if ((flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) == 0) {
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION &&
!objectExpression->ConvertibleToObjectPattern()) {
LogError(diagnostic::INVALID_LEFT_SIDE_ARRAY_DESTRUCTURING, {}, objectExpression->Start());
} else if (!inPattern && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ir::ValidationInfo info = ValidateExpression(objectExpression);
if (info.Fail()) {
LogSyntaxError(info.msg.Utf8(), info.pos);
}
}
}
return objectExpression;
}
ir::SequenceExpression *ParserImpl::ParseSequenceExpression(ir::Expression *startExpr, bool acceptRest)
{
lexer::SourcePosition start = startExpr->Start();
ArenaVector<ir::Expression *> sequence(Allocator()->Adapter());
sequence.push_back(startExpr);
while (lexer_->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COMMA)) {
if (acceptRest && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
ir::SpreadElement *expr = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN);
sequence.push_back(expr);
break;
}
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS && lexer_->CheckArrow()) {
break;
}
auto expr = ParseExpression();
sequence.push_back(expr);
}
lexer::SourcePosition end = sequence.back()->End();
auto *sequenceNode = AllocNode<ir::SequenceExpression>(std::move(sequence));
ES2PANDA_ASSERT(sequenceNode != nullptr);
sequenceNode->SetRange({start, end});
return sequenceNode;
}
ir::Expression *ParserImpl::ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags flags)
{
if (!lexer_->GetToken().IsUnary()) {
return ParseLeftHandSideExpression(flags);
}
lexer::TokenType operatorType = lexer_->GetToken().Type();
lexer::SourcePosition start = lexer_->GetToken().Start();
lexer_->NextToken();
ir::Expression *argument =
lexer_->GetToken().IsUnary() ? ParseUnaryOrPrefixUpdateExpression() : ParseLeftHandSideExpression();
if (lexer::Token::IsUpdateToken(operatorType)) {
if (!argument->IsIdentifier() && !argument->IsMemberExpression() && !argument->IsTSNonNullExpression()) {
LogError(diagnostic::INVALID_LEFT_IN_PREFIX);
}
if (argument->IsIdentifier()) {
const util::StringView &argumentStr = argument->AsIdentifier()->Name();
if (argumentStr.Is("eval")) {
LogError(diagnostic::ASSIGN_TO_EVAL_INVALID);
} else if (argumentStr.Is("arguments")) {
LogError(diagnostic::ASSIGN_TO_ARGS_INVALID);
}
}
}
if (operatorType == lexer::TokenType::KEYW_DELETE) {
if (argument->IsIdentifier()) {
LogError(diagnostic::DELETING_LOCAL_VAR);
}
if (argument->IsMemberExpression() && argument->AsMemberExpression()->Property()->IsIdentifier() &&
argument->AsMemberExpression()->Property()->AsIdentifier()->IsPrivateIdent()) {
LogError(diagnostic::DELETING_PRIVATE_FIELDS);
}
}
lexer::SourcePosition end = argument->End();
ir::Expression *returnExpr = nullptr;
if (lexer::Token::IsUpdateToken(operatorType)) {
returnExpr = AllocNode<ir::UpdateExpression>(argument, operatorType, true);
} else if (operatorType == lexer::TokenType::KEYW_AWAIT) {
returnExpr = AllocNode<ir::AwaitExpression>(argument);
} else if (operatorType == lexer::TokenType::KEYW_TYPEOF) {
returnExpr = AllocNode<ir::TypeofExpression>(argument);
} else {
returnExpr = AllocNode<ir::UnaryExpression>(argument, operatorType);
}
ES2PANDA_ASSERT(returnExpr != nullptr);
returnExpr->SetRange({start, end});
return returnExpr;
}
ir::Expression *ParserImpl::ParseImportExpression()
{
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
lexer::SourcePosition endLoc = lexer_->GetToken().End();
lexer_->NextToken();
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
if (!context_.IsModule()) {
LogError(diagnostic::IMPORT_META_ONLY_MODULE);
} else if (GetOptions().IsDirectEval()) {
LogError(diagnostic::IMPORT_META_DIRECT_EVAL);
}
lexer_->NextToken();
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT ||
lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_META) {
LogError(diagnostic::META_PROP_FOR_IMPORT);
lexer_->GetToken().SetTokenType(lexer::TokenType::KEYW_META);
}
auto *metaProperty = AllocNode<ir::MetaProperty>(ir::MetaProperty::MetaPropertyKind::IMPORT_META);
ES2PANDA_ASSERT(metaProperty != nullptr);
metaProperty->SetRange({startLoc, endLoc});
lexer_->NextToken();
return metaProperty;
}
ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
ir::Expression *source = ParseExpression();
lexer::SourcePosition endImportLoc = lexer_->GetToken().End();
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
auto *importExpression = AllocNode<ir::ImportExpression>(source);
ES2PANDA_ASSERT(importExpression != nullptr);
importExpression->SetRange({startLoc, endImportLoc});
return importExpression;
}
bool ParserImpl::IsNamedFunctionExpression()
{
return lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS;
}
ir::FunctionExpression *ParserImpl::ParseFunctionExpression(ParserStatus newStatus)
{
lexer::SourcePosition startLoc = lexer_->GetToken().Start();
ir::Identifier *ident = nullptr;
if ((newStatus & ParserStatus::ARROW_FUNCTION) == 0) {
ParserStatus savedStatus = context_.Status();
context_.Status() |= static_cast<ParserStatus>(newStatus & ParserStatus::ASYNC_FUNCTION);
lexer_->NextToken();
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
newStatus |= ParserStatus::GENERATOR_FUNCTION;
lexer_->NextToken();
}
if (IsNamedFunctionExpression()) {
CheckRestrictedBinding(lexer_->GetToken().KeywordType());
ident = ExpectIdentifier(false, true);
}
context_.Status() = savedStatus;
}
ir::ScriptFunction *functionNode = ParseFunction(newStatus);
ES2PANDA_ASSERT(functionNode != nullptr);
functionNode->SetStart(startLoc);
auto *funcExpr = AllocNode<ir::FunctionExpression>(ident, functionNode);
ES2PANDA_ASSERT(funcExpr != nullptr);
funcExpr->SetRange(functionNode->Range());
return funcExpr;
}
}