* Copyright (c) 2021-2026 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 "ASparser.h"
#include "parser/parserStatusContext.h"
#include "parserFlags.h"
#include "util/helpers.h"
#include "varbinder/privateBinding.h"
#include "varbinder/scope.h"
#include "varbinder/tsBinding.h"
#include "lexer/ASLexer.h"
#include "ir/base/decorator.h"
#include "ir/base/property.h"
#include "ir/base/spreadElement.h"
#include "ir/base/classElement.h"
#include "ir/base/classDefinition.h"
#include "ir/base/methodDefinition.h"
#include "ir/base/scriptFunction.h"
#include "ir/module/importDefaultSpecifier.h"
#include "ir/module/exportDefaultDeclaration.h"
#include "ir/module/exportNamedDeclaration.h"
#include "ir/module/importDeclaration.h"
#include "ir/expressions/arrowFunctionExpression.h"
#include "ir/expressions/templateLiteral.h"
#include "ir/expressions/callExpression.h"
#include "ir/expressions/taggedTemplateExpression.h"
#include "ir/expressions/assignmentExpression.h"
#include "ir/expressions/identifier.h"
#include "ir/expressions/memberExpression.h"
#include "ir/expressions/functionExpression.h"
#include "ir/expressions/sequenceExpression.h"
#include "ir/expressions/literals/stringLiteral.h"
#include "ir/expressions/literals/numberLiteral.h"
#include "ir/expressions/literals/bigIntLiteral.h"
#include "ir/statements/emptyStatement.h"
#include "ir/statements/blockStatement.h"
#include "ir/statements/ifStatement.h"
#include "ir/statements/doWhileStatement.h"
#include "ir/statements/whileStatement.h"
#include "ir/statements/tryStatement.h"
#include "ir/statements/breakStatement.h"
#include "ir/statements/continueStatement.h"
#include "ir/statements/throwStatement.h"
#include "ir/statements/switchStatement.h"
#include "ir/statements/returnStatement.h"
#include "ir/statements/debuggerStatement.h"
#include "ir/statements/classDeclaration.h"
#include "ir/statements/labelledStatement.h"
#include "ir/statements/variableDeclarator.h"
#include "ir/statements/functionDeclaration.h"
#include "ir/as/namedType.h"
#include "ir/as/prefixAssertionExpression.h"
#include "ir/ts/tsFunctionType.h"
#include "ir/ts/tsNonNullExpression.h"
#include "ir/ts/tsAsExpression.h"
#include "ir/ts/tsEnumDeclaration.h"
#include "ir/ts/tsInterfaceDeclaration.h"
#include "ir/ts/tsTypeAliasDeclaration.h"
#include "ir/ts/tsModuleDeclaration.h"
#include "ir/ts/tsInterfaceHeritage.h"
#include "ir/base/tsIndexSignature.h"
#include "ir/base/tsMethodSignature.h"
#include "ir/base/tsPropertySignature.h"
#include "ir/ts/tsClassImplements.h"
#include "ir/ts/tsTypeParameterInstantiation.h"
namespace ark::es2panda::parser {
std::unique_ptr<lexer::Lexer> ASParser::InitLexer()
{
ES2PANDA_ASSERT(GetContext().GetProgram() == GetProgram());
auto lexer = std::make_unique<lexer::ASLexer>(&GetContext(), DiagnosticEngine());
SetLexer(lexer.get());
return lexer;
}
ir::Decorator *ASParser::ParseDecorator()
{
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT);
lexer::SourcePosition start = Lexer()->GetToken().Start();
Lexer()->NextToken();
auto *expr = ParseLeftHandSideExpression();
auto *decorator = AllocNode<ir::Decorator>(expr);
ES2PANDA_ASSERT(decorator != nullptr);
decorator->SetRange({start, expr->End()});
return decorator;
}
void ASParser::AddDecorators(ir::AstNode *node, ArenaVector<ir::Decorator *> &decorators)
{
if (decorators.empty()) {
return;
}
if (!node->CanHaveDecorator(false)) {
ThrowSyntaxError("Decorators are not valid here", decorators.front()->Start());
}
node->AddDecorators(std::move(decorators));
}
ir::TSTypeAliasDeclaration *ASParser::ParseTypeAliasDeclaration()
{
ES2PANDA_ASSERT(Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE);
lexer::SourcePosition typeStart = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
const util::StringView &ident = Lexer()->GetToken().Ident();
auto *id = AllocNode<ir::Identifier>(ident, Allocator());
ES2PANDA_ASSERT(id != nullptr);
id->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::TSTypeParameterDeclaration *typeParamDecl = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options = TypeAnnotationParsingOptions::REPORT_ERROR;
typeParamDecl = ParseTypeParameterDeclaration(&options);
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowSyntaxError("'=' expected");
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
Lexer()->NextToken();
}
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
auto *typeAliasDecl = AllocNode<ir::TSTypeAliasDeclaration>(Allocator(), id, typeParamDecl, typeAnnotation);
typeAliasDecl->SetRange({typeStart, Lexer()->GetToken().End()});
return typeAliasDecl;
}
ir::Statement *ASParser::ParseStatement(StatementParsingFlags flags)
{
return ParseDeclareAndDecorators(flags);
}
void ASParser::ParseOptionalFunctionParameter(ir::AnnotatedExpression *returnNode, bool inRest)
{
bool isOptional = false;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
if (inRest) {
ThrowSyntaxError("A rest parameter cannot be optional");
}
ES2PANDA_ASSERT(returnNode->IsIdentifier());
returnNode->AsIdentifier()->SetOptional(true);
isOptional = true;
Lexer()->NextToken();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options));
} else if (!isOptional) {
ThrowSyntaxError("':' expected");
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
return;
}
if (inRest) {
ThrowSyntaxError("A rest parameter cannot have an initializer");
}
if (returnNode->IsIdentifier() && isOptional) {
ThrowSyntaxError("Parameter cannot have question mark and initializer");
}
}
ParserStatus ASParser::ValidateArrowExprIdentifier(ir::Expression *expr, bool *seenOptional)
{
const util::StringView &identifier = expr->AsIdentifier()->Name();
bool isOptional = expr->AsIdentifier()->IsOptional();
if ((*seenOptional) != isOptional) {
ThrowSyntaxError("A required parameter cannot follow an optional parameter.", expr->Start());
}
(*seenOptional) |= isOptional;
if (expr->AsIdentifier()->TypeAnnotation() == nullptr) {
ThrowSyntaxError("':' expected", expr->End());
}
if (identifier.Is("arguments")) {
ThrowSyntaxError("Binding 'arguments' in strict mode is invalid");
} else if (identifier.Is("eval")) {
ThrowSyntaxError("Binding 'eval' in strict mode is invalid");
}
ValidateArrowParameterBindings(expr);
return ParserStatus::NO_OPTS;
}
ParserStatus ASParser::ValidateArrowAssignmentExpr(ir::Expression *expr)
{
auto *assignmentExpr = expr->AsAssignmentExpression();
if (assignmentExpr->Right()->IsYieldExpression()) {
ThrowSyntaxError("yield is not allowed in arrow function parameters");
}
if (assignmentExpr->Right()->IsAwaitExpression()) {
ThrowSyntaxError("await is not allowed in arrow function parameters");
}
if (!assignmentExpr->ConvertibleToAssignmentPattern()) {
ThrowSyntaxError("Invalid destructuring assignment target");
}
if (assignmentExpr->Left()->IsIdentifier() && assignmentExpr->Left()->AsIdentifier()->IsOptional()) {
ThrowSyntaxError("Parameter cannot have question mark and initializer.", expr->Start());
}
ValidateArrowParameterBindings(expr);
return ParserStatus::HAS_COMPLEX_PARAM;
}
ParserStatus ASParser::ValidateArrowParameter(ir::Expression *expr, bool *seenOptional)
{
switch (expr->Type()) {
case ir::AstNodeType::SPREAD_ELEMENT: {
if (!expr->AsSpreadElement()->ConvertibleToRest(true)) {
ThrowSyntaxError("Invalid rest element.");
}
[[fallthrough]];
}
case ir::AstNodeType::REST_ELEMENT: {
if (expr->AsRestElement()->IsOptional()) {
ThrowSyntaxError("A rest parameter cannot be optional.", expr->Start());
}
ValidateArrowParameterBindings(expr->AsRestElement()->Argument());
return ParserStatus::HAS_COMPLEX_PARAM;
}
case ir::AstNodeType::IDENTIFIER: {
return ValidateArrowExprIdentifier(expr, seenOptional);
}
case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
return ValidateArrowAssignmentExpr(expr);
}
default: {
break;
}
}
ThrowSyntaxError("Insufficient formal parameter in arrow function.");
return ParserStatus::NO_OPTS;
}
ArrowFunctionDescriptor ASParser::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::ASSIGNMENT_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 &arguments = expr->AsCallExpression()->Arguments();
for (auto *it : arguments) {
arrowStatus |= ValidateArrowParameter(it, &seenOptional);
}
params.swap(arguments);
break;
}
[[fallthrough]];
}
default: {
ThrowSyntaxError("Unexpected token, arrow (=>)");
}
}
return ArrowFunctionDescriptor {std::move(params), expr->Start(), arrowStatus};
}
std::tuple<ir::AnnotatedExpression *, bool> ASParser::ParsePatternElementToken(ExpressionParseFlags flags)
{
ir::AnnotatedExpression *returnNode = nullptr;
bool isOptional = false;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: {
if ((flags & ExpressionParseFlags::IN_REST) != 0) {
ThrowSyntaxError("Unexpected token");
}
returnNode = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN);
break;
}
case lexer::TokenType::LITERAL_IDENT: {
returnNode = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(returnNode != nullptr);
returnNode->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
bool questionMark = Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK;
if (questionMark && ((flags & ExpressionParseFlags::IN_REST) != 0)) {
ThrowSyntaxError("A rest parameter cannot be optional");
}
if (questionMark) {
isOptional = true;
returnNode->AsIdentifier()->SetOptional(true);
Lexer()->NextToken();
}
if (!isOptional && Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("':' expected");
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options));
}
break;
}
default: {
ThrowSyntaxError("Identifier expected");
}
}
return {returnNode, isOptional};
}
ir::Expression *ASParser::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault)
{
ir::AnnotatedExpression *returnNode = nullptr;
bool isOptional = false;
std::tie(returnNode, isOptional) = ParsePatternElementToken(flags);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
return returnNode;
}
if ((flags & ExpressionParseFlags::IN_REST) != 0) {
ThrowSyntaxError("A rest parameter cannot have an initializer.");
}
if (!allowDefault) {
ThrowSyntaxError("Invalid destructuring assignment target");
}
if (isOptional) {
ThrowSyntaxError("Parameter cannot have question mark and initializer");
}
Lexer()->NextToken();
if (((GetContext().Status() & ParserStatus::GENERATOR_FUNCTION) != 0) &&
Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD) {
ThrowSyntaxError("Yield is not allowed in generator parameters");
}
ir::Expression *rightNode = ParseExpression();
auto *assignmentExpression = AllocNode<ir::AssignmentExpression>(
ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
assignmentExpression->SetRange({returnNode->Start(), rightNode->End()});
return assignmentExpression;
}
ir::Expression *ASParser::ParsePropertyDefinition([[maybe_unused]] ExpressionParseFlags flags)
{
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
ir::Expression *key = nullptr;
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
ThrowSyntaxError("Identifier expected");
}
key = AllocNode<ir::StringLiteral>(Lexer()->GetToken().String());
} else {
key = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
}
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::Expression *value = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
value = ParseExpression();
} else if (!key->IsStringLiteral()) {
value = key;
} else {
ThrowSyntaxError("':' expected");
}
auto *property = AllocNode<ir::Property>(key, value);
ES2PANDA_ASSERT(property != nullptr);
property->SetRange({key->Start(), value->End()});
return property;
}
bool ASParser::CurrentIsBasicType()
{
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::LITERAL_STRING:
case lexer::TokenType::LITERAL_FALSE:
case lexer::TokenType::LITERAL_TRUE:
case lexer::TokenType::LITERAL_NULL:
case lexer::TokenType::KEYW_VOID: {
return true;
}
case lexer::TokenType::LITERAL_IDENT: {
switch (Lexer()->GetToken().KeywordType()) {
case lexer::TokenType::KEYW_I8:
case lexer::TokenType::KEYW_I16:
case lexer::TokenType::KEYW_I32:
case lexer::TokenType::KEYW_I64:
case lexer::TokenType::KEYW_ISIZE:
case lexer::TokenType::KEYW_U8:
case lexer::TokenType::KEYW_U16:
case lexer::TokenType::KEYW_U32:
case lexer::TokenType::KEYW_U64:
case lexer::TokenType::KEYW_USIZE:
case lexer::TokenType::KEYW_F32:
case lexer::TokenType::KEYW_F64:
case lexer::TokenType::KEYW_V128:
case lexer::TokenType::KEYW_FUNCREF:
case lexer::TokenType::KEYW_EXTERNREF:
case lexer::TokenType::KEYW_ANYREF:
case lexer::TokenType::KEYW_EQREF:
case lexer::TokenType::KEYW_I31REF:
case lexer::TokenType::KEYW_DATAREF: {
return true;
}
default: {
break;
}
}
break;
}
default: {
break;
}
}
return false;
}
ir::TypeNode *ASParser::ParseFunctionType(lexer::SourcePosition startLoc)
{
auto params = ParseFunctionParams();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
ThrowSyntaxError("'=>' expected");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE;
ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options);
auto signature = ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation);
auto funcType = AllocNode<ir::TSFunctionType>(std::move(signature), Allocator());
funcType->SetRange({startLoc, returnTypeAnnotation->End()});
return funcType;
}
ir::TypeNode *ASParser::ParseParenthesizedOrFunctionType(bool throwError)
{
lexer::SourcePosition typeStart = Lexer()->GetToken().Start();
const auto startPos = Lexer()->Save();
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::NO_OPTS;
ir::TypeNode *type = ParseTypeAnnotation(&options);
if (type == nullptr) {
Lexer()->Rewind(startPos);
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
if (throwError) {
ThrowSyntaxError("Identifier expected");
}
return nullptr;
}
return ParseFunctionType(typeStart);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->Rewind(startPos);
return ParseFunctionType(typeStart);
}
if (throwError && Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
ThrowSyntaxError("')' expected");
}
lexer::SourcePosition endLoc = Lexer()->GetToken().End();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) {
Lexer()->Rewind(startPos);
return ParseFunctionType(typeStart);
}
type->SetRange({typeStart, endLoc});
return type;
}
ir::TypeNode *ASParser::ParseTypeAnnotationLiteralIdentHelper(ir::TypeNode *type, TypeAnnotationParsingOptions *options)
{
auto *typeName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(typeName != nullptr);
typeName->SetRange(Lexer()->GetToken().Loc());
type = AllocNode<ir::NamedType>(typeName, Allocator());
ES2PANDA_ASSERT(type != nullptr);
type->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::NamedType *current = type->AsNamedType();
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
typeName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(typeName != nullptr);
typeName->SetRange(Lexer()->GetToken().Loc());
auto *next = AllocNode<ir::NamedType>(typeName, Allocator());
current->SetRange(Lexer()->GetToken().Loc());
current->SetNext(next);
current = next;
Lexer()->NextToken();
}
ir::TSTypeParameterInstantiation *typeParams = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
typeParams = ParseTypeParameterInstantiation(options);
if (typeParams == nullptr) {
return nullptr;
}
type->AsNamedType()->SetTypeParams(typeParams);
}
return type;
}
ir::TypeNode *ASParser::ParseTypeAnnotationTokens(ir::TypeNode *type, bool throwError,
TypeAnnotationParsingOptions *options)
{
util::StringView name = "";
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: {
return ParseParenthesizedOrFunctionType(throwError);
}
case lexer::TokenType::KEYW_VOID: {
name = "void";
break;
}
case lexer::TokenType::KEYW_THIS: {
name = "this";
break;
}
case lexer::TokenType::LITERAL_FALSE:
case lexer::TokenType::LITERAL_TRUE: {
name = "bool";
break;
}
case lexer::TokenType::LITERAL_NULL: {
name = "null";
break;
}
case lexer::TokenType::LITERAL_STRING: {
name = "string";
break;
}
case lexer::TokenType::LITERAL_IDENT: {
return ParseTypeAnnotationLiteralIdentHelper(type, options);
}
default: {
if (throwError) {
ThrowSyntaxError("Type expected");
}
return nullptr;
}
}
auto *typeName = AllocNode<ir::Identifier>(name, Allocator());
ES2PANDA_ASSERT(typeName != nullptr);
typeName->SetRange(Lexer()->GetToken().Loc());
type = AllocNode<ir::NamedType>(typeName, Allocator());
ES2PANDA_ASSERT(type != nullptr);
type->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
return type;
}
ir::TypeNode *ASParser::ParseTypeAnnotationTokensBitwiseOr(ir::TypeNode *type, bool throwError, bool isNullable)
{
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NULL) {
if (throwError) {
ThrowSyntaxError("'null' expected");
}
return nullptr;
}
if (!isNullable) {
isNullable = true;
if (type->IsTSFunctionType()) {
type->AsTSFunctionType()->SetNullable(isNullable);
} else {
ES2PANDA_ASSERT(type->IsNamedType());
type->AsNamedType()->SetNullable(isNullable);
}
}
type->SetEnd(Lexer()->GetToken().End());
Lexer()->NextToken();
}
return type;
}
ir::TypeNode *ASParser::ParseTypeAnnotationTokenLeftSquareBracket(ir::TypeNode *type, bool throwError, bool isNullable)
{
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
if (throwError) {
ThrowSyntaxError("']' expected");
}
return nullptr;
}
Lexer()->NextToken();
isNullable = false;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) {
Lexer()->NextToken();
bool isLiteralNull = Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NULL;
if (isLiteralNull && throwError) {
ThrowSyntaxError("'null' expected");
}
if (isLiteralNull) {
return nullptr;
}
isNullable = true;
}
const lexer::SourcePosition &startPos = type->Start();
util::StringView name = "Array";
auto *typeName = AllocNode<ir::Identifier>(name, Allocator());
ES2PANDA_ASSERT(typeName != nullptr);
typeName->SetRange(Lexer()->GetToken().Loc());
ArenaVector<ir::TypeNode *> params(Allocator()->Adapter());
params.push_back(type);
auto *typeParamInst = AllocNode<ir::TSTypeParameterInstantiation>(std::move(params));
type = AllocNode<ir::NamedType>(typeName, Allocator());
type->AsNamedType()->SetTypeParams(typeParamInst);
type->AsNamedType()->SetNullable(isNullable);
type->SetRange({startPos, Lexer()->GetToken().End()});
if (isNullable) {
Lexer()->NextToken();
break;
}
}
return type;
}
ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options)
{
bool reportError = (((*options) & TypeAnnotationParsingOptions::REPORT_ERROR) != 0);
ir::TypeNode *type = ParseTypeAnnotationTokens(nullptr, reportError, options);
if (type == nullptr) {
return nullptr;
}
bool isNullable = false;
type = ParseTypeAnnotationTokensBitwiseOr(type, reportError, isNullable);
if (type == nullptr) {
return nullptr;
}
type = ParseTypeAnnotationTokenLeftSquareBracket(type, reportError, isNullable);
return type;
}
ir::ArrowFunctionExpression *ASParser::ParsePotentialArrowExpression(
[[maybe_unused]] ir::Expression **returnExpression, [[maybe_unused]] const lexer::SourcePosition &startLoc)
{
return nullptr;
}
bool ASParser::ParsePotentialNonNullExpression(ir::Expression **returnExpression, lexer::SourcePosition startLoc)
{
if (returnExpression == nullptr || Lexer()->GetToken().NewLine()) {
return true;
}
*returnExpression = AllocNode<ir::TSNonNullExpression>(*returnExpression);
ES2PANDA_ASSERT(*returnExpression != nullptr);
(*returnExpression)->SetRange({startLoc, Lexer()->GetToken().End()});
Lexer()->NextToken();
return false;
}
bool ASParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression,
const lexer::SourcePosition &startLoc, bool ignoreCallExpression)
{
if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN ||
(!primaryExpr->IsIdentifier() && !primaryExpr->IsMemberExpression())) {
return true;
}
const auto savedPos = Lexer()->Save();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::NO_OPTS;
ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options);
if (typeParams == nullptr) {
Lexer()->Rewind(savedPos);
return true;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::EOS) {
ThrowSyntaxError("'(' or '`' expected");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) {
if (!ignoreCallExpression) {
*returnExpression = ParseCallExpression(*returnExpression, false);
(*returnExpression)->AsCallExpression()->SetTypeParams(typeParams);
return false;
}
return true;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BACK_TICK) {
ir::TemplateLiteral *propertyNode = ParseTemplateLiteral();
lexer::SourcePosition endLoc = propertyNode->End();
*returnExpression = AllocNode<ir::TaggedTemplateExpression>(*returnExpression, propertyNode, typeParams);
ES2PANDA_ASSERT(returnExpression != nullptr);
(*returnExpression)->SetRange({startLoc, endLoc});
return false;
}
Lexer()->Rewind(savedPos);
return true;
}
bool ASParser::IsNamedFunctionExpression()
{
return Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LESS_THAN;
}
ir::Expression *ASParser::ParsePotentialAsExpression(ir::Expression *primaryExpression)
{
if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_AS) {
return nullptr;
}
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
Lexer()->NextToken();
ir::TypeNode *type = ParseTypeAnnotation(&options);
auto *asExpression = AllocNode<ir::TSAsExpression>(primaryExpression, type, false);
return asExpression;
}
ir::Identifier *ASParser::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();
ParsePotentialOptionalFunctionParameter(identNode);
return identNode;
}
bool ASParser::ValidateArrowFunctionRestParameter([[maybe_unused]] ir::SpreadElement *restElement)
{
ParseOptionalFunctionParameter(restElement, true);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
ThrowSyntaxError("')' expected");
}
return true;
}
ArenaVector<ir::TSInterfaceHeritage *> ASParser::ParseInterfaceExtendsClause()
{
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
const lexer::SourcePosition &heritageStart = Lexer()->GetToken().Start();
lexer::SourcePosition heritageEnd = Lexer()->GetToken().End();
auto *extendsName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(extendsName != nullptr);
extendsName->SetRange(Lexer()->GetToken().Loc());
auto *extendsClause = AllocNode<ir::NamedType>(extendsName, Allocator());
ES2PANDA_ASSERT(extendsClause != nullptr);
extendsClause->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::NamedType *current = extendsClause->AsNamedType();
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
extendsName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
extendsName->SetRange(Lexer()->GetToken().Loc());
auto *next = AllocNode<ir::NamedType>(extendsName, Allocator());
current->SetRange(Lexer()->GetToken().Loc());
current->SetNext(next);
current = next;
heritageEnd = Lexer()->GetToken().End();
Lexer()->NextToken();
}
if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN) {
Lexer()->ForwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
} else {
Lexer()->NextToken();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
extendsClause->AsNamedType()->SetTypeParams(ParseTypeParameterInstantiation(&options));
heritageEnd = Lexer()->GetToken().End();
}
extendsClause->SetRange({heritageStart, heritageEnd});
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPLEMENTS) {
ThrowSyntaxError("Interface declaration cannot have 'implements' clause");
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ThrowSyntaxError("'{' expected");
}
ArenaVector<ir::TSInterfaceHeritage *> extends(Allocator()->Adapter());
auto *heritage = AllocNode<ir::TSInterfaceHeritage>(extendsClause);
heritage->SetRange(extendsClause->Range());
extends.push_back(heritage);
return extends;
}
ir::TSIndexSignature *ASParser::ParseIndexSignature(const lexer::SourcePosition &startLoc, bool isReadonly)
{
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected.");
}
if (!Lexer()->GetToken().Ident().Is("key")) {
ThrowSyntaxError("'key' expected.");
}
auto *key = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(key != nullptr);
key->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("':' expected.");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *keyType = ParseTypeAnnotation(&options);
key->SetTsTypeAnnotation(keyType);
if (!keyType->IsNamedType()) {
ThrowSyntaxError("Type expected.");
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
ThrowSyntaxError("']' expected.");
}
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("':' expected.");
}
Lexer()->NextToken();
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
if (!typeAnnotation->IsNamedType()) {
ThrowSyntaxError("Identifier expected.");
}
auto *indexSignature = AllocNode<ir::TSIndexSignature>(key, typeAnnotation, isReadonly);
indexSignature->SetRange({startLoc, Lexer()->GetToken().End()});
return indexSignature;
}
std::tuple<ir::Expression *, bool> ASParser::ParseInterfacePropertyKey()
{
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());
break;
}
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());
break;
}
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());
break;
}
default: {
ThrowSyntaxError("Unexpected token in property key");
}
}
Lexer()->NextToken();
return {key, false};
}
ir::AstNode *ASParser::ParsePropertyOrMethodSignature(const lexer::SourcePosition &startLoc, bool isReadonly)
{
auto [key, isComputed] = ParseInterfacePropertyKey();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) {
ThrowSyntaxError("Optional properties are not supported.");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
ir::TSTypeParameterDeclaration *typeParamDecl = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) {
auto options = TypeAnnotationParsingOptions::REPORT_ERROR;
typeParamDecl = ParseTypeParameterDeclaration(&options);
}
FunctionParameterContext funcParamContext(&GetContext());
auto params = ParseFunctionParams();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("Type expected.");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE;
ir::TypeNode *returnType = ParseTypeAnnotation(&options);
auto signature = ir::FunctionSignature(typeParamDecl, std::move(params), returnType);
auto *methodSignature = AllocNode<ir::TSMethodSignature>(key, std::move(signature), isComputed, false);
methodSignature->SetRange({startLoc, Lexer()->GetToken().End()});
return methodSignature;
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("Type expected.");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::BREAK_AT_NEW_LINE;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
auto *propertySignature = AllocNode<ir::TSPropertySignature>(key, typeAnnotation, isComputed, false, isReadonly);
propertySignature->SetRange({startLoc, Lexer()->GetToken().End()});
return propertySignature;
}
ir::AstNode *ASParser::ParseTypeLiteralOrInterfaceMember()
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) {
ThrowSyntaxError("Decorators are not allowed here");
}
char32_t nextCp = Lexer()->Lookahead();
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
bool isReadonly = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_READONLY &&
nextCp != lexer::LEX_CHAR_LEFT_PAREN && nextCp != lexer::LEX_CHAR_COLON;
if (isReadonly) {
Lexer()->NextToken();
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) {
return ParseIndexSignature(startLoc, isReadonly);
}
return ParsePropertyOrMethodSignature(startLoc, isReadonly);
}
ArenaVector<ir::TSClassImplements *> ASParser::ParseClassImplementClause()
{
ArenaVector<ir::TSClassImplements *> implements(Allocator()->Adapter());
while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
const lexer::SourcePosition &implementStart = Lexer()->GetToken().Start();
auto *implementsName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(implementsName != nullptr);
implementsName->SetRange(Lexer()->GetToken().Loc());
auto *implementsClause = AllocNode<ir::NamedType>(implementsName, Allocator());
ES2PANDA_ASSERT(implementsClause != nullptr);
implementsClause->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
ir::NamedType *current = implementsClause->AsNamedType();
while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) {
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
implementsName = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(implementsName != nullptr);
implementsName->SetRange(Lexer()->GetToken().Loc());
auto *next = AllocNode<ir::NamedType>(implementsName, Allocator());
current->SetRange(Lexer()->GetToken().Loc());
current->SetNext(next);
current = next;
Lexer()->NextToken();
}
ir::TSTypeParameterInstantiation *implTypeParams = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) {
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
implTypeParams = ParseTypeParameterInstantiation(&options);
}
auto *impl = AllocNode<ir::TSClassImplements>(current, implTypeParams);
ES2PANDA_ASSERT(impl != nullptr);
impl->SetRange({implementStart, Lexer()->GetToken().End()});
implements.push_back(impl);
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
Lexer()->NextToken();
continue;
}
ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false);
}
if (implements.empty()) {
ThrowSyntaxError("Implements clause can not be empty");
}
return implements;
}
ir::TypeNode *ASParser::ParseClassKeyAnnotation()
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options =
TypeAnnotationParsingOptions::REPORT_ERROR | TypeAnnotationParsingOptions::BREAK_AT_NEW_LINE;
return ParseTypeAnnotation(&options);
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS &&
Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LESS_THAN) {
ThrowSyntaxError("Type expected");
}
return nullptr;
}
void ASParser::ValidateClassMethodStart(ClassElementDescriptor *desc, ir::TypeNode *typeAnnotation)
{
if (typeAnnotation == nullptr && (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS ||
Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN)) {
if ((desc->modifiers & ir::ModifierFlags::DECLARE) != 0) {
ThrowSyntaxError("'declare' modifier cannot appear on class elements of this kind");
}
desc->classMethod = true;
} else {
if (((desc->modifiers & ir::ModifierFlags::ASYNC) != 0) || desc->isGenerator) {
ThrowSyntaxError("Expected '('");
}
desc->classField = true;
if (desc->invalidComputedProperty) {
ThrowSyntaxError(
"Computed property name must refer to a symbol or "
"literal expression whose value is "
"number or string");
}
}
if ((desc->modifiers & ir::ModifierFlags::ASYNC) != 0) {
desc->newStatus |= ParserStatus::ASYNC_FUNCTION;
}
if (desc->isGenerator) {
desc->newStatus |= ParserStatus::GENERATOR_FUNCTION;
}
}
void ASParser::ValidateClassSetter(ClassElementDescriptor *desc, const ArenaVector<ir::AstNode *> &properties,
ir::Expression *propName, ir::ScriptFunction *func)
{
ValidateGetterSetter(ir::MethodDefinitionKind::SET, func);
if ((desc->modifiers & ir::ModifierFlags::STATIC) == 0) {
ir::ModifierFlags access = GetAccessability(desc->modifiers);
CheckAccessorPair(properties, propName, ir::MethodDefinitionKind::GET, access);
}
}
void ASParser::ValidateClassGetter(ClassElementDescriptor *desc, const ArenaVector<ir::AstNode *> &properties,
ir::Expression *propName, [[maybe_unused]] ir::ScriptFunction *func)
{
if ((desc->modifiers & ir::ModifierFlags::STATIC) != 0) {
ir::ModifierFlags access = GetAccessability(desc->modifiers);
CheckAccessorPair(properties, propName, ir::MethodDefinitionKind::SET, access);
}
}
ir::ClassElement *ASParser::ParseClassStaticBlock()
{
ThrowSyntaxError("Unexpected token");
return nullptr;
}
void ASParser::ParseOptionalClassElement([[maybe_unused]] ClassElementDescriptor *desc)
{
ThrowSyntaxError("Optional properties are not supported");
}
void ASParser::ValidateIndexSignatureTypeAnnotation(ir::TypeNode *typeAnnotation)
{
if (typeAnnotation == nullptr) {
ThrowSyntaxError("':' expected");
}
if (!typeAnnotation->IsNamedType()) {
ThrowSyntaxError("Identifier expected");
}
}
bool ASParser::IsModifierKind(const lexer::Token &token)
{
switch (token.KeywordType()) {
case lexer::TokenType::KEYW_PUBLIC:
case lexer::TokenType::KEYW_PRIVATE:
case lexer::TokenType::KEYW_PROTECTED:
case lexer::TokenType::KEYW_STATIC:
case lexer::TokenType::KEYW_ASYNC:
case lexer::TokenType::KEYW_DECLARE:
case lexer::TokenType::KEYW_READONLY:
return true;
default:
break;
}
return false;
}
void ASParser::ConsumeClassPrivateIdentifier([[maybe_unused]] ClassElementDescriptor *desc,
[[maybe_unused]] char32_t *nextCp)
{
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) {
ThrowSyntaxError("Invalid character");
}
}
std::tuple<bool, bool, bool> ASParser::ParseComputedClassFieldOrIndexSignature(ir::Expression **propName)
{
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT &&
Lexer()->Lookahead() == lexer::LEX_CHAR_COLON) {
if (!Lexer()->GetToken().Ident().Is("key")) {
ThrowSyntaxError("'key' expected.");
}
auto id = AllocNode<ir::Identifier>(Lexer()->GetToken().Ident(), Allocator());
ES2PANDA_ASSERT(id != nullptr);
id->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError("':' expected");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options);
if (!typeAnnotation->IsNamedType()) {
ThrowSyntaxError("Type expected");
}
id->SetTsTypeAnnotation(typeAnnotation);
*propName = id;
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
ThrowSyntaxError("']' expected");
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
return {false, false, true};
}
*propName = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
bool invalidComputedProperty =
!(*propName)->IsNumberLiteral() && !(*propName)->IsStringLiteral() &&
!((*propName)->IsMemberExpression() && (*propName)->AsMemberExpression()->Object()->IsIdentifier() &&
(*propName)->AsMemberExpression()->Object()->AsIdentifier()->Name().Is("Symbol"));
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) {
ThrowSyntaxError("Unexpected token, expected ']'");
}
return {true, invalidComputedProperty, false};
}
std::tuple<bool, ir::BlockStatement *, lexer::SourcePosition, bool> ASParser::ParseFunctionBody(
[[maybe_unused]] const ArenaVector<ir::Expression *> ¶ms, [[maybe_unused]] ParserStatus newStatus,
ParserStatus contextStatus)
{
bool isDeclare = InAmbientContext();
bool isOverload = false;
bool letDeclare = true;
ir::BlockStatement *body = nullptr;
lexer::SourcePosition endLoc = Lexer()->GetToken().End();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
if (!isDeclare && ((contextStatus & ParserStatus::IN_METHOD_DEFINITION) == 0)) {
ThrowSyntaxError("Unexpected token, expected '{'");
} else {
letDeclare = false;
}
isOverload = true;
} else if (isDeclare) {
ThrowSyntaxError("An implementation cannot be declared in ambient contexts.");
} else {
body = ParseBlockStatement();
ES2PANDA_ASSERT(body != nullptr);
endLoc = body->End();
}
return {letDeclare, body, endLoc, isOverload};
}
ir::AstNode *ASParser::ParseImportDefaultSpecifier(ArenaVector<ir::AstNode *> *specifiers)
{
ir::Identifier *local = ParseNamedImport(&Lexer()->GetToken());
Lexer()->NextToken();
auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange(specifier->Local()->Range());
specifiers->push_back(specifier);
return nullptr;
}
ir::Expression *ASParser::ParseArrowFunctionRestParameter(lexer::SourcePosition start)
{
ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN);
restElement->SetGrouped();
restElement->SetStart(start);
ValidateArrowFunctionRestParameter(restElement);
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError(":' expected");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
ThrowSyntaxError("'=>' expected");
}
return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false);
}
ir::Expression *ASParser::ParseArrowFunctionNoParameter(lexer::SourcePosition start)
{
Lexer()->NextToken();
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
ThrowSyntaxError(":' expected");
}
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
ThrowSyntaxError("'=>' expected");
}
auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false);
arrowExpr->SetStart(start);
arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start);
return arrowExpr;
}
ir::Expression *ASParser::ParseCoverParenthesizedExpressionAndArrowParameterList(
[[maybe_unused]] ExpressionParseFlags flags)
{
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS);
lexer::SourcePosition start = Lexer()->GetToken().Start();
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) {
return ParseArrowFunctionRestParameter(start);
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
return ParseArrowFunctionNoParameter(start);
}
ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST |
ExpressionParseFlags::POTENTIALLY_IN_PATTERN);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) {
ThrowSyntaxError("')' expected");
}
expr->SetGrouped();
expr->SetRange({start, Lexer()->GetToken().End()});
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) {
ThrowSyntaxError("':' expected.");
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
auto savedPos = Lexer()->Save();
Lexer()->NextToken();
options = TypeAnnotationParsingOptions::NO_OPTS;
ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options);
if (returnTypeAnnotation == nullptr) {
Lexer()->Rewind(savedPos);
return expr;
}
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) {
Lexer()->Rewind(savedPos);
return expr;
}
return ParseArrowFunctionExpression(expr, nullptr, returnTypeAnnotation, false);
}
return expr;
}
ir::Expression *ASParser::ParsePrefixAssertionExpression()
{
lexer::SourcePosition startPos = Lexer()->GetToken().Start();
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
ir::TypeNode *type = ParseTypeAnnotation(&options);
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_GREATER_THAN) {
ThrowSyntaxError("'>' expected");
}
Lexer()->NextToken();
ir::Expression *expr = ParseExpression();
auto *node = AllocNode<ir::PrefixAssertionExpression>(expr, type);
node->SetRange({startPos, Lexer()->GetToken().End()});
return node;
}
ir::Statement *ASParser::ParseConstStatement(StatementParsingFlags flags)
{
lexer::SourcePosition constVarStar = Lexer()->GetToken().Start();
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM) {
return ParseEnumDeclaration(true);
}
if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) {
ThrowSyntaxError("Lexical declaration is not allowed in single statement context");
}
auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::CONST | VariableParsingFlags::NO_SKIP_VAR_KIND);
ES2PANDA_ASSERT(variableDecl != nullptr);
variableDecl->SetStart(constVarStar);
ConsumeSemicolon(variableDecl);
return variableDecl;
}
ir::Expression *ASParser::ParseVariableDeclaratorKey(VariableParsingFlags flags)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
ThrowSyntaxError("Identifier expected");
}
ValidateDeclaratorId();
const util::StringView &identStr = Lexer()->GetToken().Ident();
auto init = AllocNode<ir::Identifier>(identStr, Allocator());
ES2PANDA_ASSERT(init != nullptr);
init->SetRange(Lexer()->GetToken().Loc());
Lexer()->NextToken();
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
init->SetTsTypeAnnotation(ParseTypeAnnotation(&options));
} else if (((flags & VariableParsingFlags::IN_FOR) == 0) &&
Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
ThrowSyntaxError("Type expected");
}
return init;
}
ir::Statement *ASParser::ParsePotentialConstEnum(VariableParsingFlags flags)
{
if ((flags & VariableParsingFlags::CONST) == 0) {
ThrowSyntaxError("Variable declaration expected.");
}
return ParseEnumDeclaration(true);
}
ir::ExportDefaultDeclaration *ASParser::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc,
bool isExportEquals)
{
Lexer()->NextToken();
ir::AstNode *declNode = nullptr;
bool eatSemicolon = false;
switch (Lexer()->GetToken().Type()) {
case lexer::TokenType::KEYW_FUNCTION: {
declNode = ParseFunctionDeclaration(true);
break;
}
case lexer::TokenType::KEYW_CLASS: {
declNode = ParseClassDeclaration(ir::ClassDefinitionModifiers::ID_REQUIRED);
break;
}
case lexer::TokenType::KEYW_INTERFACE: {
declNode = ParseInterfaceDeclaration(false);
break;
}
case lexer::TokenType::KEYW_NAMESPACE: {
Lexer()->NextToken();
declNode = ParseModuleOrNamespaceDeclaration(startLoc);
break;
}
case lexer::TokenType::KEYW_ENUM: {
declNode = ParseEnumDeclaration();
break;
}
case lexer::TokenType::KEYW_ASYNC: {
if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) {
Lexer()->NextToken();
declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION);
break;
}
[[fallthrough]];
}
default: {
declNode = ParseExpression();
eatSemicolon = true;
break;
}
}
lexer::SourcePosition endLoc = declNode->End();
auto *exportDeclaration = AllocNode<ir::ExportDefaultDeclaration>(declNode, isExportEquals);
ES2PANDA_ASSERT(exportDeclaration != nullptr);
exportDeclaration->SetRange({startLoc, endLoc});
if (eatSemicolon) {
ConsumeSemicolon(exportDeclaration);
}
return exportDeclaration;
}
class ASParser::ParseNamedExportDeclarationHelper {
friend ir::Statement *ASParser::ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc);
private:
static ir::Statement *GetParsedDeclaration(ASParser *parser, lexer::TokenType type)
{
ir::ModifierFlags flags = ir::ModifierFlags::NONE;
if (parser->Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT) {
parser->Lexer()->NextToken();
flags = ir::ModifierFlags::ABSTRACT;
}
switch (type) {
case lexer::TokenType::KEYW_VAR: {
return parser->ParseVariableDeclaration(VariableParsingFlags::VAR);
}
case lexer::TokenType::KEYW_CONST: {
return parser->ParseVariableDeclaration(VariableParsingFlags::CONST);
}
case lexer::TokenType::KEYW_LET: {
return parser->ParseVariableDeclaration(VariableParsingFlags::LET);
}
case lexer::TokenType::KEYW_FUNCTION: {
return parser->ParseFunctionDeclaration(false, ParserStatus::NO_OPTS);
}
case lexer::TokenType::KEYW_CLASS: {
return parser->ParseClassDeclaration(ir::ClassDefinitionModifiers::ID_REQUIRED, flags);
}
case lexer::TokenType::KEYW_ENUM: {
return parser->ParseEnumDeclaration();
}
case lexer::TokenType::KEYW_INTERFACE: {
return parser->ParseInterfaceDeclaration(false);
}
case lexer::TokenType::KEYW_TYPE: {
return parser->ParseTypeAliasDeclaration();
}
case lexer::TokenType::KEYW_GLOBAL:
case lexer::TokenType::KEYW_MODULE:
case lexer::TokenType::KEYW_NAMESPACE: {
return parser->ParseModuleDeclaration();
}
default: {
parser->ExpectToken(lexer::TokenType::KEYW_ASYNC);
return parser->ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION);
}
}
}
};
ir::Statement *ASParser::ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc)
{
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) {
CheckDeclare();
}
ir::Statement *decl =
ParseNamedExportDeclarationHelper::GetParsedDeclaration(this, Lexer()->GetToken().KeywordType());
if (decl->IsVariableDeclaration()) {
ConsumeSemicolon(decl);
}
ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
auto *exportDeclaration = AllocNode<ir::ExportNamedDeclaration>(Allocator(), decl, std::move(specifiers));
ES2PANDA_ASSERT(exportDeclaration != nullptr);
exportDeclaration->SetRange({startLoc, decl->End()});
return exportDeclaration;
}
ir::AstNode *ASParser::ParseImportSpecifiers(ArenaVector<ir::AstNode *> *specifiers)
{
ES2PANDA_ASSERT(specifiers->empty());
if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) {
ParseImportDefaultSpecifier(specifiers);
return nullptr;
}
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) {
ParseNameSpaceImport(specifiers);
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) {
ParseNamedImportSpecifiers(specifiers);
}
return nullptr;
}
ir::Statement *ASParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags)
{
char32_t nextChar = Lexer()->Lookahead();
if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) {
return ParseExpressionStatement();
}
lexer::SourcePosition startLoc = Lexer()->GetToken().Start();
Lexer()->NextToken();
ArenaVector<ir::AstNode *> specifiers(Allocator()->Adapter());
ir::StringLiteral *source = nullptr;
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
ParseImportSpecifiers(&specifiers);
source = ParseFromClause(true);
} else {
source = ParseFromClause(false);
}
ES2PANDA_ASSERT(source != nullptr);
lexer::SourcePosition endLoc = source->End();
auto *importDeclaration = AllocNode<ir::ImportDeclaration>(source, std::move(specifiers));
ES2PANDA_ASSERT(importDeclaration != nullptr);
importDeclaration->SetRange({startLoc, endLoc});
ConsumeSemicolon(importDeclaration);
return importDeclaration;
}
void ASParser::ReportIllegalBreakError(const lexer::SourcePosition &pos)
{
ThrowSyntaxError("A 'break' statement can only be used within an enclosing iteration or switch statement", pos);
}
void ASParser::ReportIllegalContinueError()
{
ThrowSyntaxError("A 'continue' statement can only be used within an enclosing iteration statement");
}
}