/** * Copyright (c) 2021 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 "parserImpl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace panda::es2panda::parser { ParserImpl::ParserImpl(ScriptExtension extension) : program_(extension), context_(&program_) {} std::unique_ptr ParserImpl::InitLexer(const std::string &fileName, const std::string &source) { bool isDtsFile = false; if (Extension() == ScriptExtension::TS) { isDtsFile = util::Helpers::FileExtensionIs(fileName, ".d.ts"); } program_.SetSource(source, fileName, isDtsFile); auto lexer = std::make_unique(&context_); lexer_ = lexer.get(); return lexer; } Program ParserImpl::Parse(const SourceFile &sourceFile, const CompilerOptions &options) { program_.SetKind(sourceFile.scriptKind); program_.SetRecordName(sourceFile.recordName); program_.SetDebug(options.isDebug); program_.SetTargetApiVersion(options.targetApiVersion); program_.SetTargetApiSubVersion(options.targetApiSubVersion); program_.SetEnableAnnotations(options.enableAnnotations); program_.SetShared(sourceFile.isSharedModule); program_.SetModuleRecordFieldName(options.moduleRecordFieldName); if (Extension() == ScriptExtension::TS) { program_.SetDefineSemantic(options.useDefineSemantic); } /* * In order to make the lexer's memory alive, the return value 'lexer' can not be omitted. */ auto lexer = InitLexer(sourceFile.fileName, std::string {sourceFile.source}); switch (sourceFile.scriptKind) { case ScriptKind::SCRIPT: { ParseScript(); break; } case ScriptKind::MODULE: { ParseModule(); break; } case ScriptKind::COMMONJS: { ParseCommonjs(); break; } default: { UNREACHABLE(); } } binder::ResolveBindingFlags bindFlags = binder::ResolveBindingFlags::ALL; if (Extension() == ScriptExtension::TS) { bindFlags = binder::ResolveBindingFlags::TS_BEFORE_TRANSFORM; } Binder()->IdentifierAnalysis(bindFlags); return std::move(program_); } void ParserImpl::ParseScript() { ParseProgram(ScriptKind::SCRIPT); } void ParserImpl::ParseModule() { context_.Status() |= (ParserStatus::MODULE); ParseProgram(ScriptKind::MODULE); } void ParserImpl::ParseProgram(ScriptKind kind) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); auto statements = ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL); // For close-source har, check 'use shared' when parsing its transformed js code after obfuscation. for (auto statement : statements) { if (program_.IsShared()) { break; } program_.SetShared(util::Helpers::IsUseShared(statement)); } if (IsDtsFile() && !CheckTopStatementsForRequiredDeclare(statements)) { ThrowSyntaxError( "Top-level declarations in .d.ts files must start with either a 'declare' or 'export' modifier."); } auto *blockStmt = AllocNode(Binder()->GetScope(), std::move(statements)); Binder()->GetScope()->BindNode(blockStmt); blockStmt->SetRange({startLoc, lexer_->GetToken().End()}); program_.SetAst(blockStmt); } bool ParserImpl::CheckTopStatementsForRequiredDeclare(const ArenaVector &statements) { for (auto *statement : statements) { switch (statement->Type()) { case ir::AstNodeType::TS_INTERFACE_DECLARATION: case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: case ir::AstNodeType::IMPORT_DECLARATION: case ir::AstNodeType::TS_IMPORT_EQUALS_DECLARATION: case ir::AstNodeType::EXPORT_ALL_DECLARATION: case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: case ir::AstNodeType::EXPORT_NAMED_DECLARATION: case ir::AstNodeType::TS_NAMESPACE_EXPORT_DECLARATION: continue; case ir::AstNodeType::CLASS_DECLARATION: { if (!statement->AsClassDeclaration()->Definition()->Declare()) { return false; } break; } case ir::AstNodeType::FUNCTION_DECLARATION: { if (!statement->AsFunctionDeclaration()->Function()->Declare() && !statement->AsFunctionDeclaration()->Function()->IsOverload()) { return false; } break; } case ir::AstNodeType::VARIABLE_DECLARATION: { if (!statement->AsVariableDeclaration()->Declare()) { return false; } break; } case ir::AstNodeType::TS_MODULE_DECLARATION: { if (!statement->AsTSModuleDeclaration()->Declare()) { return false; } break; } case ir::AstNodeType::TS_ENUM_DECLARATION: { if (!statement->AsTSEnumDeclaration()->IsDeclare()) { return false; } break; } default: ThrowSyntaxError("Statements are not allowed in ambient contexts."); UNREACHABLE(); } } return true; } /* * Definitions of private methods */ ExpressionParseFlags ParserImpl::CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry) { return static_cast(origin & carry); } ExpressionParseFlags ParserImpl::CarryPatternFlags(ExpressionParseFlags flags) { return CarryExpressionParserFlag(flags, ExpressionParseFlags::POTENTIALLY_IN_PATTERN | ExpressionParseFlags::OBJECT_PATTERN); } ExpressionParseFlags ParserImpl::CarryAllowTsParamAndPatternFlags(ExpressionParseFlags flags) { return CarryExpressionParserFlag(flags, ExpressionParseFlags::ALLOW_TS_PARAM_TOKEN | ExpressionParseFlags::POTENTIALLY_IN_PATTERN | ExpressionParseFlags::OBJECT_PATTERN); } bool ParserImpl::CurrentLiteralIsBasicType() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS); switch (lexer_->GetToken().KeywordType()) { case lexer::TokenType::KEYW_ANY: case lexer::TokenType::KEYW_BOOLEAN: case lexer::TokenType::KEYW_NUMBER: case lexer::TokenType::KEYW_STRING: case lexer::TokenType::KEYW_SYMBOL: case lexer::TokenType::KEYW_UNKNOWN: case lexer::TokenType::KEYW_UNDEFINED: case lexer::TokenType::KEYW_NEVER: case lexer::TokenType::KEYW_OBJECT: case lexer::TokenType::KEYW_BIGINT: { return true; } default: { break; } } return false; } bool ParserImpl::CurrentIsBasicType() { switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::LITERAL_NUMBER: 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: { return CurrentLiteralIsBasicType(); } default: { break; } } return false; } ir::TSTypeReference *ParserImpl::ParseTsConstExpression() { auto *identRef = AllocNode(lexer_->GetToken().Ident()); identRef->SetReference(); identRef->SetRange(lexer_->GetToken().Loc()); auto *typeReference = AllocNode(identRef, nullptr); typeReference->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return typeReference; } ir::Expression *ParserImpl::ParseTsIdentifierReference(TypeAnnotationParsingOptions options) { if (CurrentLiteralIsBasicType() && lexer_->Lookahead() != LEX_CHAR_DOT) { return ParseTsBasicType(options); } return ParseTsTypeReferenceOrQuery(options, false); } bool ParserImpl::IsStartOfMappedType() const { auto pos = lexer_->Save(); lexer_->NextToken(); bool result = false; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) { lexer_->NextToken(); result = lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_READONLY; lexer_->Rewind(pos); return result; } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_READONLY) { lexer_->NextToken(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { lexer_->Rewind(pos); return false; } lexer_->NextToken(); if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { lexer_->Rewind(pos); return false; } lexer_->NextToken(); result = lexer_->GetToken().Type() == lexer::TokenType::KEYW_IN; lexer_->Rewind(pos); return result; } bool ParserImpl::IsStartOfTsTypePredicate() const { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || lexer_->GetToken().Type() == lexer::TokenType::KEYW_THIS); auto pos = lexer_->Save(); bool isAsserts = lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ASSERTS; if (isAsserts) { lexer_->NextToken(); } if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && lexer_->GetToken().Type() != lexer::TokenType::KEYW_THIS) { lexer_->Rewind(pos); return false; } if (isAsserts) { lexer_->Rewind(pos); return true; } lexer_->NextToken(); bool result = !lexer_->GetToken().NewLine() && (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IS); lexer_->Rewind(pos); return result; } bool ParserImpl::IsStartOfAbstractConstructorType() const { if (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_ABSTRACT) { return false; } lexer::LexerPosition pos = lexer_->Save(); lexer_->NextToken(); // eat 'abstract' bool result = lexer_->GetToken().Type() == lexer::TokenType::KEYW_NEW; lexer_->Rewind(pos); return result; } ir::Expression *ParserImpl::ParseTsTypeLiteralOrTsMappedType(ir::Expression *typeAnnotation) { if (typeAnnotation) { return nullptr; } if (IsStartOfMappedType()) { return ParseTsMappedType(); } lexer::SourcePosition bodyStart = lexer_->GetToken().Start(); auto members = ParseTsTypeLiteralOrInterface(); lexer::SourcePosition bodyEnd = lexer_->GetToken().End(); lexer_->NextToken(); auto *literalType = AllocNode(std::move(members)); auto *typeVar = binder::Scope::CreateVar(Allocator(), "__type", binder::VariableFlags::TYPE, literalType); literalType->SetVariable(typeVar); literalType->SetRange({bodyStart, bodyEnd}); return literalType; } ir::Expression *ParserImpl::ParseTsTypeReferenceOrTsTypePredicate(ir::Expression *typeAnnotation, bool canBeTsTypePredicate, bool throwError) { if (typeAnnotation) { return nullptr; } if (canBeTsTypePredicate && IsStartOfTsTypePredicate()) { return ParseTsTypePredicate(); } return ParseTsTypeOperatorOrTypeReference(throwError); } ir::Expression *ParserImpl::ParseTsThisTypeOrTsTypePredicate(ir::Expression *typeAnnotation, bool canBeTsTypePredicate, bool throwError) { if (typeAnnotation) { return nullptr; } if (canBeTsTypePredicate && IsStartOfTsTypePredicate()) { return ParseTsTypePredicate(); } return ParseTsThisType(throwError); } ir::Expression *ParserImpl::ParseTsTemplateLiteralType(bool throwError) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BACK_TICK); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ArenaVector quasis(Allocator()->Adapter()); ArenaVector references(Allocator()->Adapter()); while (true) { lexer_->ResetTokenEnd(); const auto startPos = lexer_->Save(); lexer_->ScanString(); util::StringView cooked = lexer_->GetToken().String(); lexer_->Rewind(startPos); auto [raw, end, scanExpression] = lexer_->ScanTemplateString(); auto *element = AllocNode(raw.View(), cooked); element->SetRange({lexer::SourcePosition{startPos.iterator.Index(), startPos.line}, lexer::SourcePosition{end, lexer_->Line()}}); quasis.push_back(element); if (!scanExpression) { lexer_->ScanTemplateStringEnd(); break; } ir::Expression *reference = nullptr; { lexer::TemplateLiteralParserContext ctx(lexer_); lexer_->PushTemplateContext(&ctx); lexer_->NextToken(); TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; reference = ParseTsTypeAnnotation(&options); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (throwError) { ThrowSyntaxError("Unexpected token, expected '}'."); } return nullptr; } references.push_back(reference); } ir::Expression *typeAnnotation = AllocNode(std::move(quasis), std::move(references)); typeAnnotation->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); return typeAnnotation; } ir::Expression *ParserImpl::ParseTsTypeAnnotationElement(ir::Expression *typeAnnotation, TypeAnnotationParsingOptions *options) { switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { if (*options & (TypeAnnotationParsingOptions::IN_MODIFIER | TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) { break; } return ParseTsUnionType(typeAnnotation, *options & TypeAnnotationParsingOptions::RESTRICT_EXTENDS, *options & TypeAnnotationParsingOptions::THROW_ERROR); } case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { if (*options & (TypeAnnotationParsingOptions::IN_MODIFIER | TypeAnnotationParsingOptions::IN_INTERSECTION)) { break; } return ParseTsIntersectionType(typeAnnotation, *options & TypeAnnotationParsingOptions::IN_UNION, *options & TypeAnnotationParsingOptions::RESTRICT_EXTENDS, *options & TypeAnnotationParsingOptions::THROW_ERROR); } case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::LITERAL_NUMBER: 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: { if (typeAnnotation) { break; } return ParseTsBasicType(*options); } case lexer::TokenType::KEYW_TYPEOF: { if (typeAnnotation) { break; } return ParseTsTypeReferenceOrQuery(*options, true); } case lexer::TokenType::KEYW_IMPORT: { if (typeAnnotation) { break; } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); return ParseTsImportType(startLoc); } case lexer::TokenType::KEYW_CONST: { if (!(*options & TypeAnnotationParsingOptions::ALLOW_CONST)) { break; } *options &= ~TypeAnnotationParsingOptions::ALLOW_CONST; return ParseTsConstExpression(); } case lexer::TokenType::LITERAL_IDENT: { if (IsStartOfAbstractConstructorType()) { return ParseTsParenthesizedOrFunctionType(typeAnnotation, *options & TypeAnnotationParsingOptions::THROW_ERROR); } return ParseTsTypeReferenceOrTsTypePredicate( typeAnnotation, *options & TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE, *options & TypeAnnotationParsingOptions::THROW_ERROR); } case lexer::TokenType::KEYW_EXTENDS: { if (*options & (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) { break; } if (!typeAnnotation) { return ParseTsIdentifierReference(*options); } if (InDisallowConditionalTypesContext()) { break; } return ParseTsConditionalType(typeAnnotation, *options & TypeAnnotationParsingOptions::RESTRICT_EXTENDS); } case lexer::TokenType::KEYW_THIS: { return ParseTsThisTypeOrTsTypePredicate(typeAnnotation, *options & TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE, *options & TypeAnnotationParsingOptions::THROW_ERROR); } case lexer::TokenType::PUNCTUATOR_BACK_TICK: { return ParseTsTemplateLiteralType(*options & TypeAnnotationParsingOptions::THROW_ERROR); } default: { auto type = DoOutsideOfDisallowConditinalTypesContext(&ParserImpl::ParsePostfixTypeOrHigher, typeAnnotation, options); if (type) { return type; } } } if (!typeAnnotation && (*options & TypeAnnotationParsingOptions::THROW_ERROR)) { ThrowSyntaxError("Type expected"); } return nullptr; } ir::Expression *ParserImpl::ParsePostfixTypeOrHigher(ir::Expression *typeAnnotation, TypeAnnotationParsingOptions *options) { switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_LESS_THAN: case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: case lexer::TokenType::KEYW_NEW: { return ParseTsParenthesizedOrFunctionType(typeAnnotation, *options & TypeAnnotationParsingOptions::THROW_ERROR); } case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { if (typeAnnotation) { if (lexer_->GetToken().NewLine()) { break; } if (lexer_->Lookahead() == LEX_CHAR_RIGHT_SQUARE) { return ParseTsArrayType(typeAnnotation); } return ParseTsIndexAccessType(typeAnnotation, *options & TypeAnnotationParsingOptions::THROW_ERROR); } return ParseTsTupleType(); } case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { return ParseTsTypeLiteralOrTsMappedType(typeAnnotation); } default: { break; } } return nullptr; } ir::TSImportType *ParserImpl::ParseTsImportType(const lexer::SourcePosition &startLoc, bool isTypeof) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_IMPORT); lexer_->NextToken(); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { ThrowSyntaxError("'(' expected"); } lexer_->NextToken(); TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; ir::Expression *param = ParseTsTypeAnnotation(&options); if (!param->IsTSLiteralType() || !param->AsTSLiteralType()->Literal()->IsStringLiteral()) { ThrowSyntaxError("String literal expected"); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { ThrowSyntaxError("')' expected"); } lexer_->NextToken(); ir::Expression *qualifier = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { lexer_->NextToken(); if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { ThrowSyntaxError("Identifier expected"); } qualifier = AllocNode(lexer_->GetToken().Ident()); qualifier->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { qualifier = ParseTsQualifiedReference(qualifier); } } ir::TSTypeParameterInstantiation *typeParams = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) { lexer_->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); } typeParams = ParseTsTypeParameterInstantiation(); } auto *importType = AllocNode(param, typeParams, qualifier, isTypeof); importType->SetRange({startLoc, lexer_->GetToken().End()}); return importType; } ir::Expression *ParserImpl::ParseTsThisType(bool throwError) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_THIS); if (throwError && !(context_.Status() & ParserStatus::ALLOW_THIS_TYPE)) { ThrowSyntaxError( "A 'this' type is available only in a non-static member " "of a class or interface."); } auto *returnType = AllocNode(); returnType->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return returnType; } ir::Expression *ParserImpl::ParseTsConditionalType(ir::Expression *checkType, bool restrictExtends) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS); if (restrictExtends) { ThrowSyntaxError("'?' expected."); } lexer::SourcePosition startLoc = checkType->Start(); lexer_->NextToken(); // eat 'extends' ParserStatus savedStatus = context_.Status(); context_.Status() |= ParserStatus::IN_EXTENDS; TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::RESTRICT_EXTENDS; ir::Expression *extendsType = DoInsideOfDisallowConditinalTypesContext(&ParserImpl::ParseTsTypeAnnotation, &options); context_.Status() = savedStatus; if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { ThrowSyntaxError("'?' expected."); } lexer_->NextToken(); // eat '?' options &= ~TypeAnnotationParsingOptions::RESTRICT_EXTENDS; auto *trueType = DoOutsideOfDisallowConditinalTypesContext(&ParserImpl::ParseTsTypeAnnotation, &options); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { ThrowSyntaxError("':' expected."); } lexer_->NextToken(); // eat ':' auto *falseType = DoOutsideOfDisallowConditinalTypesContext(&ParserImpl::ParseTsTypeAnnotation, &options); lexer::SourcePosition endLoc = falseType->End(); auto *conditionalType = AllocNode(checkType, extendsType, trueType, falseType); conditionalType->SetRange({startLoc, endLoc}); return conditionalType; } ir::Expression *ParserImpl::ParseTsTypeAnnotation(TypeAnnotationParsingOptions *options) { ir::Expression *typeAnnotation = nullptr; while (true) { ir::Expression *element = ParseTsTypeAnnotationElement(typeAnnotation, options); *options &= ~TypeAnnotationParsingOptions::ALLOW_CONST; *options &= ~TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE; if (!element) { break; } typeAnnotation = element; if (((*options & TypeAnnotationParsingOptions::BREAK_AT_NEW_LINE) && lexer_->GetToken().NewLine()) && !(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_AND || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR)) { break; } } return typeAnnotation; } ir::Expression *ParserImpl::ParseTsTypeOperatorOrTypeReference(bool throwError) { TypeAnnotationParsingOptions options = throwError ? TypeAnnotationParsingOptions::THROW_ERROR : TypeAnnotationParsingOptions::NO_OPTS; if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_READONLY) { lexer::SourcePosition typeOperatorStart = lexer_->GetToken().Start(); lexer_->NextToken(); options |= TypeAnnotationParsingOptions::IN_MODIFIER; ir::Expression *type = ParseTsTypeAnnotation(&options); ASSERT(type != nullptr); if (!type->IsTSArrayType() && !type->IsTSTupleType()) { ThrowSyntaxError( "'readonly' type modifier is only permitted on array " "and tuple literal types."); } auto *typeOperator = AllocNode(type, ir::TSOperatorType::READONLY); typeOperator->SetRange({typeOperatorStart, type->End()}); return typeOperator; } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_KEYOF) { lexer::SourcePosition typeOperatorStart = lexer_->GetToken().Start(); lexer_->NextToken(); options |= TypeAnnotationParsingOptions::IN_MODIFIER; ir::Expression *type = ParseTsTypeAnnotation(&options); ASSERT(type != nullptr); auto *typeOperator = AllocNode(type, ir::TSOperatorType::KEYOF); typeOperator->SetRange({typeOperatorStart, type->End()}); return typeOperator; } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_UNIQUE) { lexer::SourcePosition typeOperatorStart = lexer_->GetToken().Start(); lexer_->NextToken(); ir::Expression *type = ParseTsTypeAnnotation(&options); ASSERT(type != nullptr); auto *typeOperator = AllocNode(type, ir::TSOperatorType::UNIQUE); typeOperator->SetRange({typeOperatorStart, type->End()}); return typeOperator; } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_INFER) { if (!(context_.Status() & ParserStatus::IN_EXTENDS)) { ThrowSyntaxError( "'infer' declarations are only permitted in the " "'extends' clause of a conditional type."); } lexer::SourcePosition inferStart = lexer_->GetToken().Start(); lexer_->NextToken(); ir::TSTypeParameter *typeParam = ParseTsTypeParameter(true); auto *inferType = AllocNode(typeParam); inferType->SetRange({inferStart, lexer_->GetToken().End()}); return inferType; } return ParseTsIdentifierReference(options); } bool ParserImpl::IsTSNamedTupleMember() { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { return false; } const auto savePos = lexer_->Save(); bool isNamedMember = false; lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON || (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK && lexer_->Lookahead() == LEX_CHAR_COLON)) { isNamedMember = true; } lexer_->Rewind(savePos); return isNamedMember; } void ParserImpl::HandleRestType(ir::AstNodeType elementType, bool *hasRestType) const { if (elementType == ir::AstNodeType::TS_ARRAY_TYPE && *hasRestType) { ThrowSyntaxError("A rest element cannot follow another rest element"); } if (elementType == ir::AstNodeType::TS_ARRAY_TYPE) { *hasRestType = true; } } ir::Expression *ParserImpl::ParseTsTupleElement(ir::TSTupleKind *kind, bool *seenOptional, bool *hasRestType) { lexer::SourcePosition startPos = lexer_->GetToken().Start(); ir::Expression *element = nullptr; bool isRestType = false; TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { isRestType = true; lexer_->NextToken(); // eat '...' } if (IsTSNamedTupleMember()) { if (*kind == ir::TSTupleKind::DEFAULT) { ThrowSyntaxError("Tuple members must all have or haven't names"); } *kind = ir::TSTupleKind::NAMED; auto *elementIdent = AllocNode(lexer_->GetToken().Ident()); elementIdent->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); // eat identifier bool isOptional = false; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { lexer_->NextToken(); // eat '?' isOptional = true; *seenOptional = true; } else if (*seenOptional && !isRestType) { ThrowSyntaxError("A required element cannot follow an optional element"); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { ThrowSyntaxError("':' expected"); } lexer_->NextToken(); // eat ':' auto *elementType = ParseTsTypeAnnotation(&options); CHECK_NOT_NULL(elementType); if (elementType && isRestType) { HandleRestType(elementType->Type(), hasRestType); } element = AllocNode(elementIdent, elementType, isOptional, isRestType); element->SetRange({startPos, elementType->End()}); } else { if (*kind == ir::TSTupleKind::NAMED) { ThrowSyntaxError("Tuple members must all have or haven't names"); } *kind = ir::TSTupleKind::DEFAULT; element = ParseTsTypeAnnotation(&options); ASSERT(element != nullptr); if (element && isRestType) { HandleRestType(element->Type(), hasRestType); lexer::SourcePosition endPos = element->End(); element = AllocNode(std::move(element)); element->SetRange({startPos, endPos}); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { lexer::SourcePosition elementStartPos = element->Start(); element = AllocNode(std::move(element)); element->SetRange({elementStartPos, lexer_->GetToken().End()}); lexer_->NextToken(); // eat '?' *seenOptional = true; } else if (*seenOptional && !isRestType) { ThrowSyntaxError("A required element cannot follow an optional element"); } } return element; } ir::TSTupleType *ParserImpl::ParseTsTupleType() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); lexer::SourcePosition tupleStart = lexer_->GetToken().Start(); ArenaVector elements(Allocator()->Adapter()); ir::TSTupleKind kind = ir::TSTupleKind::NONE; bool seenOptional = false; bool hasRestType = false; lexer_->NextToken(); // eat '[' while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ir::Expression *element = ParseTsTupleElement(&kind, &seenOptional, &hasRestType); elements.push_back(element); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { break; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { ThrowSyntaxError("',' expected."); } lexer_->NextToken(); // eat ',' } lexer::SourcePosition tupleEnd = lexer_->GetToken().End(); lexer_->NextToken(); // eat ']' auto *tupleType = AllocNode(std::move(elements)); tupleType->SetRange({tupleStart, tupleEnd}); return tupleType; } ir::Expression *ParserImpl::ParseTsQualifiedReference(ir::Expression *typeName) { lexer::SourcePosition startLoc = typeName->Start(); do { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat '.' if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { ThrowSyntaxError("Identifier expected"); } auto *propName = AllocNode(lexer_->GetToken().Ident()); propName->SetRange(lexer_->GetToken().Loc()); typeName = AllocNode(typeName, propName); typeName->SetRange({typeName->AsTSQualifiedName()->Left()->Start(), lexer_->GetToken().End()}); lexer_->NextToken(); } while (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD); typeName->SetRange({startLoc, lexer_->GetToken().End()}); return typeName; } ir::Expression *ParserImpl::ParseTsIndexAccessType(ir::Expression *typeName, bool throwError) { TypeAnnotationParsingOptions options = throwError ? TypeAnnotationParsingOptions::THROW_ERROR : TypeAnnotationParsingOptions::NO_OPTS; do { lexer_->NextToken(); // eat '[' ir::Expression *indexType = ParseTsTypeAnnotation(&options); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { if (!throwError) { return nullptr; } ThrowSyntaxError("']' expected"); } lexer_->NextToken(); // eat ']' typeName = AllocNode(typeName, indexType); typeName->SetRange({typeName->AsTSIndexedAccessType()->ObjectType()->Start(), lexer_->GetToken().End()}); } while (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET && lexer_->Lookahead() != LEX_CHAR_RIGHT_SQUARE); return typeName; } ir::Expression *ParserImpl::ParseTsTypeReferenceOrQuery(TypeAnnotationParsingOptions options, bool parseQuery) { lexer::SourcePosition referenceStartLoc = lexer_->GetToken().Start(); if (parseQuery) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_TYPEOF); lexer_->NextToken(); // eat 'typeof' if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_IMPORT) { lexer::SourcePosition &startLoc = referenceStartLoc; return ParseTsImportType(startLoc, true); } if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && lexer_->GetToken().Type() != lexer::TokenType::KEYW_THIS) { ThrowSyntaxError("Identifier expected."); } } ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || lexer_->GetToken().Type() == lexer::TokenType::KEYW_THIS || lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS); ir::Expression *typeName = AllocNode(lexer_->GetToken().Ident()); typeName->SetRange(lexer_->GetToken().Loc()); typeName->AsIdentifier()->SetReference(); if (lexer_->Lookahead() == LEX_CHAR_LESS_THAN) { lexer_->ForwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); } else { lexer_->NextToken(); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { typeName = ParseTsQualifiedReference(typeName); } ir::TSTypeParameterInstantiation *typeParamInst = nullptr; if (!(lexer_->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { typeParamInst = ParseTsTypeParameterInstantiation(options & TypeAnnotationParsingOptions::THROW_ERROR); if (parseQuery) { typeName = AllocNode(typeName, typeParamInst); lexer::SourcePosition endLoc = typeParamInst->End(); typeName->SetRange({referenceStartLoc, endLoc}); } } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET && lexer_->Lookahead() != LEX_CHAR_RIGHT_SQUARE) { if (parseQuery) { typeName = AllocNode(typeName); } else { typeName = AllocNode(typeName, typeParamInst); } typeName->SetRange({referenceStartLoc, lexer_->GetToken().End()}); return ParseTsIndexAccessType(typeName, options & TypeAnnotationParsingOptions::THROW_ERROR); } ir::Expression *returnNode = nullptr; lexer::SourcePosition referenceEndLoc = typeName->End(); if (parseQuery) { returnNode = AllocNode(typeName); } else { returnNode = AllocNode(typeName, typeParamInst); } returnNode->SetRange({referenceStartLoc, referenceEndLoc}); return returnNode; } ir::TSTypeParameter *ParserImpl::ParseTsMappedTypeParameter() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); auto *paramName = AllocNode(lexer_->GetToken().Ident()); paramName->SetRange({lexer_->GetToken().Start(), lexer_->GetToken().End()}); lexer_->NextToken(); lexer_->NextToken(); // eat 'in' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; ir::Expression *constraint = ParseTsTypeAnnotation(&options); lexer::SourcePosition endLoc = constraint->End(); auto *typeParameter = AllocNode(paramName, constraint, nullptr); typeParameter->SetRange({startLoc, endLoc}); return typeParameter; } ir::MappedOption ParserImpl::ParseMappedOption(lexer::TokenType tokenType) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_MINUS && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_PLUS && lexer_->GetToken().KeywordType() != tokenType && lexer_->GetToken().Type() != tokenType) { return ir::MappedOption::NO_OPTS; } auto result = lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS ? ir::MappedOption::MINUS : ir::MappedOption::PLUS; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) { lexer_->NextToken(); } if (lexer_->GetToken().KeywordType() != tokenType && lexer_->GetToken().Type() != tokenType) { ThrowSyntaxError({"'", TokenToString(tokenType), "' expected."}); } lexer_->NextToken(); return result; } ir::TSMappedType *ParserImpl::ParseTsMappedType() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat '{' ir::MappedOption readonly = ParseMappedOption(lexer::TokenType::KEYW_READONLY); lexer_->NextToken(); // eat '[' ir::TSTypeParameter *typeParameter = ParseTsMappedTypeParameter(); ir::Expression *nameKeyType = nullptr; if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_AS) { lexer_->NextToken(); // eat 'as' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; nameKeyType = ParseTsTypeAnnotation(&options); ASSERT(nameKeyType != nullptr); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("']' expected"); } lexer_->NextToken(); // eat ']' ir::MappedOption optional = ParseMappedOption(lexer::TokenType::PUNCTUATOR_QUESTION_MARK); ir::Expression *typeAnnotation = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; typeAnnotation = ParseTsTypeAnnotation(&options); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { ThrowSyntaxError("';' expected"); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); // eat ';' } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { ThrowSyntaxError("'}' expected"); } auto *mappedType = AllocNode(typeParameter, nameKeyType, typeAnnotation, readonly, optional); mappedType->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); // eat '}' return mappedType; } ir::TSTypePredicate *ParserImpl::ParseTsTypePredicate() { auto pos = lexer_->Save(); lexer::SourcePosition startPos = lexer_->GetToken().Start(); bool isAsserts = lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ASSERTS; if (isAsserts) { lexer_->NextToken(); // eat 'asserts' if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IS) { isAsserts = false; lexer_->Rewind(pos); } } ir::Expression *parameterName = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { parameterName = AllocNode(lexer_->GetToken().Ident()); } else { parameterName = AllocNode(); } parameterName->SetRange({lexer_->GetToken().Start(), lexer_->GetToken().End()}); lexer_->NextToken(); ir::Expression *typeAnnotation = nullptr; lexer::SourcePosition endPos; ir::TSTypePredicate *result = nullptr; if (isAsserts && lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_IS) { endPos = parameterName->End(); result = AllocNode(parameterName, typeAnnotation, isAsserts); result->SetRange({startPos, endPos}); return result; } lexer_->NextToken(); // eat 'is' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; typeAnnotation = ParseTsTypeAnnotation(&options); endPos = typeAnnotation->End(); result = AllocNode(parameterName, typeAnnotation, isAsserts); result->SetRange({startPos, endPos}); return result; } ir::Expression *ParserImpl::ParseTsTypeLiteralOrInterfaceKey(bool *computed, bool *signature, bool *isIndexSignature) { ir::Expression *key = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_NEW || (lexer_->Lookahead() != LEX_CHAR_LEFT_PAREN && lexer_->Lookahead() != LEX_CHAR_LESS_THAN))) { key = AllocNode(lexer_->GetToken().Ident()); key->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_NUMBER) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) { key = AllocNode(lexer_->GetToken().BigInt()); } else { key = AllocNode(lexer_->GetToken().Number(), lexer_->GetToken().String()); } key->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { key = AllocNode(lexer_->GetToken().String()); key->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { *computed = true; lexer_->NextToken(); // eat '[' if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && lexer_->Lookahead() == LEX_CHAR_COLON) { *isIndexSignature = true; key = AllocNode(lexer_->GetToken().Ident()); key->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); // eat param if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { ThrowSyntaxError("':' expected"); } lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; ir::Expression *typeAnnotation = ParseTsTypeAnnotation(&options); ValidateIndexSignatureParameterType(typeAnnotation); key->SetTsTypeAnnotation(typeAnnotation); } else { key = ParseExpression(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("']' expected"); } lexer_->NextToken(); // eat ']' } else if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LESS_THAN && lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_NEW) { ThrowSyntaxError("Unexpected token"); } else { *signature = true; } return key; } void ParserImpl::ValidateIndexSignatureParameterType(ir::Expression *typeAnnotation) { // Validation of IndexSignatureParameterType is coarse-grained. if (!typeAnnotation->IsTSStringKeyword() && !typeAnnotation->IsTSNumberKeyword() && !typeAnnotation->IsTSSymbolKeyword() && !typeAnnotation->IsTSTemplateLiteralType() && !typeAnnotation->IsTSUnionType() && !typeAnnotation->IsTSTypeReference() && !typeAnnotation->IsTSParenthesizedType() && !typeAnnotation->IsTSConditionalType() && !typeAnnotation->IsTSIndexedAccessType() && !typeAnnotation->IsTSIntersectionType()) { ThrowSyntaxError( "An index signature parameter type must be 'string', 'number', 'symbol', " "or a template literal type."); } } void ParserImpl::CreateTSVariableForProperty(ir::AstNode *node, const ir::Expression *key, binder::VariableFlags flags) { binder::Variable *propVar = nullptr; bool isMethod = flags & binder::VariableFlags::METHOD; util::StringView propName = "__computed"; switch (key->Type()) { case ir::AstNodeType::IDENTIFIER: { propName = key->AsIdentifier()->Name(); break; } case ir::AstNodeType::NUMBER_LITERAL: { propName = key->AsNumberLiteral()->Str(); flags |= binder::VariableFlags::NUMERIC_NAME; break; } case ir::AstNodeType::STRING_LITERAL: { propName = key->AsStringLiteral()->Str(); break; } default: { flags |= binder::VariableFlags::COMPUTED; break; } } propVar = isMethod ? binder::Scope::CreateVar(Allocator(), propName, flags, node) : binder::Scope::CreateVar(Allocator(), propName, flags, node); node->SetVariable(propVar); } void ParserImpl::ParseTsTypeLiteralOrInterfaceKeyModifiers(bool *isGetAccessor, bool *isSetAccessor) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { return; } char32_t nextCp = lexer_->Lookahead(); if (Extension() == ScriptExtension::TS && nextCp != LEX_CHAR_EQUALS && nextCp != LEX_CHAR_SEMICOLON && nextCp != LEX_CHAR_LEFT_PAREN && nextCp != LEX_CHAR_LESS_THAN && nextCp != LEX_CHAR_QUESTION && nextCp != LEX_CHAR_COLON && nextCp != LEX_CHAR_RIGHT_BRACE && nextCp != LEX_CHAR_COMMA) { if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_GET) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) { ThrowSyntaxError("Keyword must not contain escaped characters"); } *isGetAccessor = true; lexer_->NextToken(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_SET) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) { ThrowSyntaxError("Keyword must not contain escaped characters"); } *isSetAccessor = true; lexer_->NextToken(); } } } ir::Expression *ParserImpl::ParseTsTypeLiteralOrInterfaceMember() { bool computed = false; bool optional = false; bool signature = false; bool readonly = false; bool isGetAccessor = false; bool isSetAccessor = false; bool isConstructSignature = false; bool isIndexSignature = false; lexer::SourcePosition memberStartLoc = lexer_->GetToken().Start(); char32_t nextToken = lexer_->Lookahead(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_READONLY && nextToken != LEX_CHAR_LEFT_PAREN && nextToken != LEX_CHAR_COLON && nextToken != LEX_CHAR_COMMA && nextToken != LEX_CHAR_LESS_THAN && nextToken != LEX_CHAR_SEMICOLON) { readonly = true; lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); } ParseTsTypeLiteralOrInterfaceKeyModifiers(&isGetAccessor, &isSetAccessor); ir::Expression *key = ParseTsTypeLiteralOrInterfaceKey(&computed, &signature, &isIndexSignature); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { if (isIndexSignature) { ThrowSyntaxError("';' expected"); } optional = true; lexer_->NextToken(); // eat '?' } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_NEW && signature) { lexer_->NextToken(); // eat 'new' if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LESS_THAN) { ThrowSyntaxError("'(' expected"); } isConstructSignature = true; } ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { if (isIndexSignature) { ThrowSyntaxError("';' expected"); } typeParamDecl = ParseTsTypeParameterDeclaration(); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { ThrowSyntaxError("'(' expected"); } } ir::Expression *member = nullptr; ir::Expression *typeAnnotation = nullptr; binder::VariableFlags flags = binder::VariableFlags::NONE; if (optional) { flags |= binder::VariableFlags::OPTIONAL; } if (readonly) { flags |= binder::VariableFlags::READONLY; } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && !isIndexSignature) { FunctionParameterContext funcParamContext(&context_, Binder()); auto *funcParamScope = funcParamContext.LexicalScope().GetScope(); ArenaVector params = ParseFunctionParams(true); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE; typeAnnotation = ParseTsTypeAnnotation(&options); } if (signature) { auto kind = isConstructSignature ? ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CONSTRUCT_SIGNATURE : ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE; member = AllocNode(funcParamScope, kind, typeParamDecl, std::move(params), typeAnnotation); funcParamScope->BindNode(member); } else { member = AllocNode(funcParamScope, key, typeParamDecl, std::move(params), typeAnnotation, computed, optional, isGetAccessor, isSetAccessor); funcParamScope->BindNode(member); CreateTSVariableForProperty(member, key, flags | binder::VariableFlags::METHOD); } } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::BREAK_AT_NEW_LINE; typeAnnotation = ParseTsTypeAnnotation(&options); } else if (isIndexSignature) { ThrowSyntaxError("An index signature must have a type annotation.", memberStartLoc); } if (!member && isIndexSignature) { member = AllocNode(key, typeAnnotation, readonly); } else if (!member) { member = AllocNode(key, typeAnnotation, computed, optional, readonly); CreateTSVariableForProperty(member, key, flags | binder::VariableFlags::PROPERTY); } else if (readonly) { ThrowSyntaxError( "'readonly' modifier can only appear on a property " "declaration or index signature.", memberStartLoc); } member->SetRange({memberStartLoc, lexer_->GetToken().End()}); return member; } util::StringView GetTSPropertyName(ir::Expression *key) { switch (key->Type()) { case ir::AstNodeType::IDENTIFIER: { return key->AsIdentifier()->Name(); } case ir::AstNodeType::NUMBER_LITERAL: { return key->AsNumberLiteral()->Str(); } case ir::AstNodeType::STRING_LITERAL: { return key->AsStringLiteral()->Str(); } default: { UNREACHABLE(); } } } void ParserImpl::CheckObjectTypeForDuplicatedProperties(ir::Expression *member, ArenaVector const &members) { ir::Expression *key = nullptr; if (member->IsTSPropertySignature()) { key = member->AsTSPropertySignature()->Key(); } else if (member->IsTSMethodSignature()) { key = member->AsTSMethodSignature()->Key(); } else { return; } if (!key->IsIdentifier() && !key->IsNumberLiteral() && !key->IsStringLiteral()) { return; } for (auto *it : members) { ir::Expression *compare = nullptr; switch (it->Type()) { case ir::AstNodeType::TS_PROPERTY_SIGNATURE: { compare = it->AsTSPropertySignature()->Key(); break; } case ir::AstNodeType::TS_METHOD_SIGNATURE: { compare = it->AsTSMethodSignature()->Key(); break; } default: { continue; } } if (!compare->IsIdentifier() && !compare->IsNumberLiteral() && !compare->IsStringLiteral()) { continue; } if (member->IsTSMethodSignature() && it->Type() == ir::AstNodeType::TS_METHOD_SIGNATURE) { continue; } if (GetTSPropertyName(key) == GetTSPropertyName(compare)) { ThrowSyntaxError("Duplicated identifier", key->Start()); } } } ArenaVector ParserImpl::ParseTsTypeLiteralOrInterface() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat '{' ArenaVector members(Allocator()->Adapter()); while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { ir::Expression *member = ParseTsTypeLiteralOrInterfaceMember(); CheckObjectTypeForDuplicatedProperties(member, members); members.push_back(member); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { break; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON) { if (!lexer_->GetToken().NewLine()) { ThrowSyntaxError("',' expected"); } if (lexer_->GetToken().IsKeyword()) { lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); } continue; } lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); } return members; } ir::TSArrayType *ParserImpl::ParseTsArrayType(ir::Expression *elementType) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); lexer_->NextToken(); // eat '[' if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("']' expected"); } lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); // eat ']' lexer::SourcePosition startLoc = elementType->Start(); auto *arrayType = AllocNode(elementType); arrayType->SetRange({startLoc, endLoc}); return arrayType; } ir::TSUnionType *ParserImpl::ParseTsUnionType(ir::Expression *type, bool restrictExtends, bool throwError) { ArenaVector types(Allocator()->Adapter()); lexer::SourcePosition startLoc; TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::IN_UNION; if (throwError) { options |= TypeAnnotationParsingOptions::THROW_ERROR; } if (restrictExtends) { options |= TypeAnnotationParsingOptions::RESTRICT_EXTENDS; } if (type) { startLoc = type->Start(); types.push_back(type); } else { startLoc = lexer_->GetToken().Start(); } while (true) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_BITWISE_OR) { break; } lexer_->NextToken(); // eat '|' ir::Expression* unionSuffixType = ParseTsTypeAnnotation(&options); if (unionSuffixType == nullptr) { return nullptr; } types.push_back(unionSuffixType); } lexer::SourcePosition endLoc = types.back()->End(); auto *unionType = AllocNode(std::move(types)); auto *typeVar = binder::Scope::CreateVar(Allocator(), "__type", binder::VariableFlags::TYPE, unionType); unionType->SetVariable(typeVar); unionType->SetRange({startLoc, endLoc}); return unionType; } ir::TSIntersectionType *ParserImpl::ParseTsIntersectionType(ir::Expression *type, bool inUnion, bool restrictExtends, bool throwError) { ArenaVector types(Allocator()->Adapter()); lexer::SourcePosition startLoc; TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::IN_INTERSECTION; if (throwError) { options |= TypeAnnotationParsingOptions::THROW_ERROR; } if (restrictExtends) { options |= TypeAnnotationParsingOptions::RESTRICT_EXTENDS; } if (inUnion) { options |= TypeAnnotationParsingOptions::IN_UNION; } if (type) { startLoc = type->Start(); types.push_back(type); } else { startLoc = lexer_->GetToken().Start(); } while (true) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_BITWISE_AND) { break; } lexer_->NextToken(); // eat '&' ir::Expression* suffixType = ParseTsTypeAnnotation(&options); if (suffixType == nullptr) { return nullptr; } types.push_back(suffixType); } lexer::SourcePosition endLoc = types.back()->End(); auto *intersectionType = AllocNode(std::move(types)); auto *typeVar = binder::Scope::CreateVar(Allocator(), "__type", binder::VariableFlags::TYPE, intersectionType); intersectionType->SetVariable(typeVar); intersectionType->SetRange({startLoc, endLoc}); return intersectionType; } bool ParserImpl::IsTsFunctionType() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); const auto startPos = lexer_->Save(); lexer_->NextToken(); // eat '(' if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { lexer_->Rewind(startPos); return true; } try { ParseModifiers(); if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::KEYW_THIS)) { lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN | ExpressionParseFlags::OBJECT_PATTERN); } else { lexer_->Rewind(startPos); return false; } } catch ([[maybe_unused]] const class Error &e) { lexer_->Rewind(startPos); return false; } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EQUAL) { lexer_->Rewind(startPos); return true; } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { lexer_->NextToken(); // eat ')' if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) { lexer_->Rewind(startPos); return true; } } lexer_->Rewind(startPos); return false; } ir::Expression *ParserImpl::ParseTsParenthesizedOrFunctionType(ir::Expression *typeAnnotation, bool throwError) { if (typeAnnotation) { return nullptr; } lexer::SourcePosition typeStart = lexer_->GetToken().Start(); bool abstractConstructor = lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT; if (abstractConstructor) { lexer_->NextToken(); // eat 'abstract' } bool isConstructionType = false; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_NEW) { lexer_->NextToken(); // eat 'new' isConstructionType = true; if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LESS_THAN) { if (!throwError) { return nullptr; } ThrowSyntaxError("'(' expected"); } } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN || isConstructionType) { return ParseTsFunctionType(typeStart, isConstructionType, throwError, abstractConstructor); } if (IsTsFunctionType()) { return ParseTsFunctionType(typeStart, false, throwError); } ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer_->NextToken(); // eat '(' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::NO_OPTS; ir::Expression *type = ParseTsTypeAnnotation(&options); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { if (!throwError) { return nullptr; } ThrowSyntaxError("')' expected"); } lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); // eat ')' auto *result = AllocNode(type); result->SetRange({typeStart, endLoc}); return result; } ir::Expression *ParserImpl::ParseTsFunctionType(lexer::SourcePosition startLoc, bool isConstructionType, bool throwError, bool abstractConstructor) { ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { typeParamDecl = ParseTsTypeParameterDeclaration(throwError); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { if (!throwError) { return nullptr; } ThrowSyntaxError("'(' expected"); } } FunctionParameterContext funcParamContext(&context_, Binder()); auto *funcParamScope = funcParamContext.LexicalScope().GetScope(); ArenaVector params(Allocator()->Adapter()); try { params = ParseFunctionParams(true); } catch (const Error &e) { if (!throwError) { return nullptr; } throw e; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { ThrowSyntaxError("'=>' expected"); } lexer_->NextToken(); // eat '=>' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE; if (throwError) { options |= TypeAnnotationParsingOptions::THROW_ERROR; } ir::Expression *returnTypeAnnotation = ParseTsTypeAnnotation(&options); if (returnTypeAnnotation == nullptr) { return nullptr; } ir::Expression *funcType = nullptr; if (isConstructionType) { funcType = AllocNode(funcParamScope, std::move(params), typeParamDecl, returnTypeAnnotation, abstractConstructor); } else { funcType = AllocNode(funcParamScope, std::move(params), typeParamDecl, returnTypeAnnotation); } funcType->SetRange({startLoc, returnTypeAnnotation->End()}); funcParamScope->BindNode(funcType); return funcType; } ir::Expression *ParserImpl::ParseTsBasicType(TypeAnnotationParsingOptions options) { ir::Expression *typeAnnotation = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { lexer_->NextToken(); if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { if (options & TypeAnnotationParsingOptions::THROW_ERROR) { ThrowSyntaxError("Type expected"); } else { return nullptr; } } } if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_NUMBER) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) { auto *bigintNode = AllocNode(lexer_->GetToken().BigInt()); bigintNode->SetRange(lexer_->GetToken().Loc()); typeAnnotation = AllocNode(bigintNode); } else { auto *numberNode = AllocNode(lexer_->GetToken().Number(), lexer_->GetToken().String()); numberNode->SetRange(lexer_->GetToken().Loc()); typeAnnotation = AllocNode(numberNode); } } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { auto *stringNode = AllocNode(lexer_->GetToken().String()); stringNode->SetRange(lexer_->GetToken().Loc()); typeAnnotation = AllocNode(stringNode); } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_TRUE) { auto *booleanLiteral = AllocNode(true); booleanLiteral->SetRange(lexer_->GetToken().Loc()); typeAnnotation = AllocNode(booleanLiteral); } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_FALSE) { auto *booleanLiteral = AllocNode(false); booleanLiteral->SetRange(lexer_->GetToken().Loc()); typeAnnotation = AllocNode(booleanLiteral); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ANY) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_BOOLEAN) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_NUMBER) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_STRING) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_UNKNOWN) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_VOID) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::LITERAL_NULL) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_UNDEFINED) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_NEVER) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OBJECT) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_BIGINT) { typeAnnotation = AllocNode(); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_SYMBOL) { typeAnnotation = AllocNode(); } else { ThrowSyntaxError("Unexpected type"); } typeAnnotation->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return typeAnnotation; } static ir::ModifierFlags GetAccessability(ir::ModifierFlags modifiers) { if (modifiers & ir::ModifierFlags::PUBLIC) { return ir::ModifierFlags::PUBLIC; } if (modifiers & ir::ModifierFlags::PRIVATE) { return ir::ModifierFlags::PRIVATE; } if (modifiers & ir::ModifierFlags::PROTECTED) { return ir::ModifierFlags::PROTECTED; } return ir::ModifierFlags::NONE; } static bool IsModifierKind(const lexer::Token &token) { if (token.Type() == lexer::TokenType::LITERAL_IDENT) { 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_ABSTRACT: case lexer::TokenType::KEYW_DECLARE: case lexer::TokenType::KEYW_READONLY: case lexer::TokenType::KEYW_ACCESSOR: case lexer::TokenType::KEYW_OVERRIDE: return true; default: return false; } } return false; } ir::ModifierFlags ParserImpl::ParseModifiers() { ir::ModifierFlags resultStatus = ir::ModifierFlags::NONE; ir::ModifierFlags prevStatus = ir::ModifierFlags::ALL; while (IsModifierKind(lexer_->GetToken())) { char32_t nextCp = lexer_->Lookahead(); if (nextCp == LEX_CHAR_LEFT_PAREN || nextCp == LEX_CHAR_EQUALS || nextCp == LEX_CHAR_SEMICOLON) { break; } lexer::TokenFlags tokenFlags = lexer_->GetToken().Flags(); if (tokenFlags & lexer::TokenFlags::HAS_ESCAPE) { ThrowSyntaxError("Keyword must not contain escaped characters"); } ir::ModifierFlags actualStatus = ir::ModifierFlags::NONE; ir::ModifierFlags nextStatus = ir::ModifierFlags::NONE; switch (lexer_->GetToken().KeywordType()) { case lexer::TokenType::KEYW_PUBLIC: { actualStatus = ir::ModifierFlags::PUBLIC; nextStatus = ir::ModifierFlags::ASYNC | ir::ModifierFlags::STATIC | ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::ACCESSOR | ir::ModifierFlags::OVERRIDE; break; } case lexer::TokenType::KEYW_PRIVATE: { actualStatus = ir::ModifierFlags::PRIVATE; nextStatus = ir::ModifierFlags::ASYNC | ir::ModifierFlags::STATIC | ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::ACCESSOR | ir::ModifierFlags::OVERRIDE; break; } case lexer::TokenType::KEYW_PROTECTED: { actualStatus = ir::ModifierFlags::PROTECTED; nextStatus = ir::ModifierFlags::ASYNC | ir::ModifierFlags::STATIC | ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::ACCESSOR | ir::ModifierFlags::OVERRIDE; break; } case lexer::TokenType::KEYW_STATIC: { actualStatus = ir::ModifierFlags::STATIC; nextStatus = ir::ModifierFlags::ASYNC | ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT | ir::ModifierFlags::ACCESSOR | ir::ModifierFlags::OVERRIDE; break; } case lexer::TokenType::KEYW_ASYNC: { actualStatus = ir::ModifierFlags::ASYNC; nextStatus = ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT; break; } case lexer::TokenType::KEYW_ABSTRACT: { actualStatus = ir::ModifierFlags::ABSTRACT; nextStatus = ir::ModifierFlags::ACCESS | ir::ModifierFlags::ASYNC | ir::ModifierFlags::STATIC | ir::ModifierFlags::READONLY | ir::ModifierFlags::DECLARE | ir::ModifierFlags::OVERRIDE | ir::ModifierFlags::ACCESSOR; break; } case lexer::TokenType::KEYW_DECLARE: { actualStatus = ir::ModifierFlags::DECLARE; nextStatus = ir::ModifierFlags::ACCESS | ir::ModifierFlags::ASYNC | ir::ModifierFlags::STATIC | ir::ModifierFlags::READONLY; break; } case lexer::TokenType::KEYW_READONLY: { actualStatus = ir::ModifierFlags::READONLY; nextStatus = ir::ModifierFlags::ASYNC | ir::ModifierFlags::DECLARE | ir::ModifierFlags::ABSTRACT; break; } case lexer::TokenType::KEYW_ACCESSOR: { actualStatus = ir::ModifierFlags::ACCESSOR; nextStatus = ir::ModifierFlags::NONE; break; } case lexer::TokenType::KEYW_OVERRIDE: { actualStatus = ir::ModifierFlags::OVERRIDE; nextStatus = ir::ModifierFlags::ACCESSOR | ir::ModifierFlags::ASYNC | ir::ModifierFlags::READONLY; break; } default: { UNREACHABLE(); } } if (lexer_->Lookahead() == LEX_CHAR_COLON || lexer_->Lookahead() == LEX_CHAR_COMMA || lexer_->Lookahead() == LEX_CHAR_RIGHT_PAREN || lexer_->Lookahead() == LEX_CHAR_QUESTION || lexer_->Lookahead() == LEX_CHAR_RIGHT_BRACE || lexer_->Lookahead() == LEX_CHAR_LESS_THAN) { break; } auto pos = lexer_->Save(); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); if ((prevStatus & actualStatus) == 0) { lexer_->Rewind(pos); ThrowSyntaxError("Unexpected modifier"); } if ((resultStatus & actualStatus) != 0) { lexer_->Rewind(pos); ThrowSyntaxError("Duplicated modifier is not allowed"); } if ((context_.Status() & ParserStatus::CONSTRUCTOR_FUNCTION) && (actualStatus & ~ir::ModifierFlags::ALLOWED_IN_CTOR_PARAMETER)) { lexer_->Rewind(pos); ThrowParameterModifierError(actualStatus); } resultStatus |= actualStatus; prevStatus = nextStatus; } return resultStatus; } void ParserImpl::CheckAccessorPair(const ArenaVector &properties, const ir::Expression *propName, ir::MethodDefinitionKind methodKind, ir::ModifierFlags access, bool hasDecorator, lexer::SourcePosition errorInfo) { for (const auto &it : properties) { if (!it->IsMethodDefinition() || (!hasDecorator && it->AsMethodDefinition()->Kind() != methodKind)) { continue; } const ir::Expression *key = it->AsMethodDefinition()->Key(); if (key->Type() != propName->Type()) { continue; } bool keyIsSame = false; if (key->IsIdentifier()) { const util::StringView &strName = propName->AsIdentifier()->Name(); const util::StringView &compareName = (key->AsIdentifier()->Name()); keyIsSame = strName == compareName; } else if (key->IsNumberLiteral()) { keyIsSame = *key->AsNumberLiteral() == *propName->AsNumberLiteral(); } else if (key->IsStringLiteral()) { keyIsSame = *key->AsStringLiteral() == *propName->AsStringLiteral(); } if (!keyIsSame) { continue; } if (hasDecorator && (it->AsMethodDefinition()->Kind() == ir::MethodDefinitionKind::GET || it->AsMethodDefinition()->Kind() == ir::MethodDefinitionKind::SET) && !it->AsMethodDefinition()->Decorators().empty()) { ThrowSyntaxError("Decorators cannot be applied to multiple get/set accessors of the same name.", errorInfo); } if (it->AsMethodDefinition()->Kind() != methodKind) { continue; } ir::ModifierFlags getAccess = ir::ModifierFlags::NONE; ir::ModifierFlags setAccess = ir::ModifierFlags::NONE; if (methodKind == ir::MethodDefinitionKind::GET) { setAccess = access; getAccess = GetAccessability(it->AsMethodDefinition()->Modifiers()); } else { getAccess = access; setAccess = GetAccessability(it->AsMethodDefinition()->Modifiers()); } if ((setAccess == ir::ModifierFlags::NONE && getAccess > ir::ModifierFlags::PUBLIC) || (setAccess != ir::ModifierFlags::NONE && getAccess > setAccess)) { ThrowSyntaxError("A get accessor must be at least as accessible as the setter", key->Start()); } } } void ParserImpl::ParseClassKeyModifiers(ClassElmentDescriptor *desc) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { return; } char32_t nextCp = lexer_->Lookahead(); if ((Extension() == ScriptExtension::JS && nextCp != LEX_CHAR_LEFT_PAREN) || (Extension() == ScriptExtension::TS && nextCp != LEX_CHAR_EQUALS && nextCp != LEX_CHAR_SEMICOLON && nextCp != LEX_CHAR_LEFT_PAREN && nextCp != LEX_CHAR_LESS_THAN && nextCp != LEX_CHAR_QUESTION && nextCp != LEX_CHAR_COLON && nextCp != LEX_CHAR_RIGHT_BRACE)) { if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_GET) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) { ThrowSyntaxError("Keyword must not contain escaped characters"); } desc->methodKind = ir::MethodDefinitionKind::GET; desc->methodStart = lexer_->GetToken().Start(); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); CheckClassPrivateIdentifier(desc); } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_SET) { if (lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) { ThrowSyntaxError("Keyword must not contain escaped characters"); } desc->methodKind = ir::MethodDefinitionKind::SET; desc->methodStart = lexer_->GetToken().Start(); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); CheckClassPrivateIdentifier(desc); } } } void ParserImpl::ThrowIfPrivateIdent(ClassElmentDescriptor *desc, const char *msg) { if (desc->isPrivateIdent) { ThrowSyntaxError(msg); } } void ParserImpl::ValidateClassKey(ClassElmentDescriptor *desc, bool isDeclare) { if ((desc->modifiers & ir::ModifierFlags::ASYNC) && (desc->methodKind == ir::MethodDefinitionKind::GET || desc->methodKind == ir::MethodDefinitionKind::SET)) { ThrowSyntaxError("Async method can not be getter nor setter"); } if (desc->isPrivateIdent) { if (desc->modifiers & ir::ModifierFlags::ACCESS) { ThrowSyntaxError("An accessibility modifier cannot be used with a private identifier."); } if (desc->modifiers & ir::ModifierFlags::DECLARE) { ThrowSyntaxError("'declare' modifier cannot be used with a private identifier."); } if (desc->modifiers & ir::ModifierFlags::ABSTRACT) { ThrowSyntaxError("'abstract' modifier cannot be used with a private identifier."); } } // Check private properties in another method: ParsePrivateIdentifier() if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) { return; } const util::StringView &propNameStr = lexer_->GetToken().Ident(); if (propNameStr.Is("constructor")) { ThrowIfPrivateIdent(desc, "Private identifier can not be constructor"); if (!(desc->modifiers & ir::ModifierFlags::STATIC)) { if ((desc->modifiers & ir::ModifierFlags::ASYNC) || desc->methodKind == ir::MethodDefinitionKind::GET || desc->methodKind == ir::MethodDefinitionKind::SET || desc->isGenerator) { ThrowSyntaxError("Constructor can not be special method"); } desc->methodKind = ir::MethodDefinitionKind::CONSTRUCTOR; desc->methodStart = lexer_->GetToken().Start(); desc->newStatus |= ParserStatus::CONSTRUCTOR_FUNCTION; if (desc->hasSuperClass) { desc->newStatus |= ParserStatus::ALLOW_SUPER_CALL; } } else if (Extension() == ScriptExtension::TS) { ThrowSyntaxError("Static modifier can not appear on a constructor"); } } else if (!isDeclare && propNameStr.Is("prototype") && (desc->modifiers & ir::ModifierFlags::STATIC)) { ThrowSyntaxError("Classes may not have static property named prototype"); } } ir::Expression *ParserImpl::ParseClassKey(ClassElmentDescriptor *desc, bool isDeclare) { if (desc->isPrivateIdent && program_.TargetApiVersion() > 10) { ValidateClassKey(desc, isDeclare); return ParsePrivateIdentifier(); } ir::Expression *propName = nullptr; if (lexer_->GetToken().IsKeyword()) { lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); } switch (lexer_->GetToken().Type()) { case lexer::TokenType::LITERAL_IDENT: { ValidateClassKey(desc, isDeclare); propName = AllocNode(lexer_->GetToken().Ident()); propName->SetRange(lexer_->GetToken().Loc()); break; } case lexer::TokenType::LITERAL_STRING: { ValidateClassKey(desc, isDeclare); ThrowIfPrivateIdent(desc, "Private identifier name can not be string"); propName = AllocNode(lexer_->GetToken().String()); propName->SetRange(lexer_->GetToken().Loc()); break; } case lexer::TokenType::LITERAL_NUMBER: { ThrowIfPrivateIdent(desc, "Private identifier name can not be number"); if (lexer_->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) { propName = AllocNode(lexer_->GetToken().BigInt()); } else { propName = AllocNode(lexer_->GetToken().Number(), lexer_->GetToken().String()); } propName->SetRange(lexer_->GetToken().Loc()); break; } case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { ThrowIfPrivateIdent(desc, "Unexpected character in private identifier"); lexer_->NextToken(); // eat left square bracket if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && lexer_->Lookahead() == LEX_CHAR_COLON) { desc->isIndexSignature = true; propName = AllocNode(lexer_->GetToken().Ident()); propName->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); // eat param if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { ThrowSyntaxError("':' expected"); } lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; ir::Expression *typeAnnotation = ParseTsTypeAnnotation(&options); ValidateIndexSignatureParameterType(typeAnnotation); propName->SetTsTypeAnnotation(typeAnnotation); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("']' expected"); } lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); return propName; } desc->isComputed = true; propName = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); if (Extension() == ScriptExtension::TS) { // TODO(songqi): Determine whether MemberExpression is a symbol during type check. desc->invalidComputedProperty = !propName->IsNumberLiteral() && util::Helpers::GetSignedNumberLiteral(propName) == util::SignedNumberLiteral::UNRECOGNIZED && !propName->IsStringLiteral() && !propName->IsMemberExpression() && !propName->IsIdentifier(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("Unexpected token, expected ']'"); } break; } default: { ThrowSyntaxError("Unexpected token in class property"); } } lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); return propName; } void ParserImpl::ValidateClassMethodStart(ClassElmentDescriptor *desc, ir::Expression *typeAnnotation) { if (Extension() == ScriptExtension::JS) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { return; } desc->classMethod = true; } if (Extension() == ScriptExtension::TS) { if (!typeAnnotation && (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN)) { if ((desc->modifiers & (ir::ModifierFlags::DECLARE | ir::ModifierFlags::READONLY))) { ThrowSyntaxError("Class method can not be declare nor readonly"); } desc->classMethod = true; } else { if ((desc->modifiers & ir::ModifierFlags::ASYNC) || desc->isGenerator) { ThrowSyntaxError("Expected '('"); } desc->classField = true; if (desc->invalidComputedProperty) { ThrowSyntaxError( "Computed property name must refer to a symbol or " "literal expression whos value is " "number or string"); } } } if (desc->modifiers & ir::ModifierFlags::ASYNC) { desc->newStatus |= ParserStatus::ASYNC_FUNCTION; } if (desc->isGenerator) { desc->newStatus |= ParserStatus::GENERATOR_FUNCTION; } } void ParserImpl::ValidateClassSetter(ClassElmentDescriptor *desc, const ArenaVector &properties, ir::Expression *propName, ir::ScriptFunction *func, bool hasDecorator, lexer::SourcePosition errorInfo) { if (func->Params().size() != 1) { ThrowSyntaxError("Setter must have exactly one formal parameter"); } if (Extension() == ScriptExtension::TS && !(desc->modifiers & ir::ModifierFlags::STATIC)) { ir::ModifierFlags access = GetAccessability(desc->modifiers); CheckAccessorPair(properties, propName, ir::MethodDefinitionKind::GET, access, hasDecorator, errorInfo); } } void ParserImpl::ValidateClassGetter(ClassElmentDescriptor *desc, const ArenaVector &properties, ir::Expression *propName, ir::ScriptFunction *func, bool hasDecorator, lexer::SourcePosition errorInfo) { if (!func->Params().empty()) { ThrowSyntaxError("Getter must not have formal parameters"); } if (Extension() == ScriptExtension::TS && !(desc->modifiers & ir::ModifierFlags::STATIC)) { ir::ModifierFlags access = GetAccessability(desc->modifiers); CheckAccessorPair(properties, propName, ir::MethodDefinitionKind::SET, access, hasDecorator, errorInfo); } } void ParserImpl::ValidatePrivateProperty(ir::Statement *stmt, std::unordered_set &usedPrivateNames, std::unordered_map &unusedGetterSetterPairs) { if (stmt->IsClassProperty()) { auto *prop = stmt->AsClassProperty(); if (!prop->IsPrivate()) { return; } auto name = prop->Key()->AsPrivateIdentifier()->Name(); if (usedPrivateNames.find(name) != usedPrivateNames.end()) { ThrowSyntaxError({"Redeclaration of class private property #", name.Utf8()}, prop->Start()); } usedPrivateNames.insert(name); return; } if (stmt->IsMethodDefinition()) { auto *methodDef = stmt->AsMethodDefinition(); if (!methodDef->IsPrivate()) { return; } auto name = methodDef->Key()->AsPrivateIdentifier()->Name(); if (methodDef->Kind() == ir::MethodDefinitionKind::METHOD) { if (usedPrivateNames.find(name) != usedPrivateNames.end()) { ThrowSyntaxError({"Redeclaration of class private property #", name.Utf8()}, methodDef->Start()); } usedPrivateNames.insert(name); return; } ASSERT(methodDef->Kind() != ir::MethodDefinitionKind::CONSTRUCTOR); PrivateGetterSetterType type = (methodDef->Kind() == ir::MethodDefinitionKind::GET) ? PrivateGetterSetterType::GETTER : PrivateGetterSetterType::SETTER; PrivateGetterSetterType unusedType = (methodDef->Kind() == ir::MethodDefinitionKind::GET) ? PrivateGetterSetterType::SETTER : PrivateGetterSetterType::GETTER; if (methodDef->IsStatic()) { type |= PrivateGetterSetterType::STATIC; unusedType |= PrivateGetterSetterType::STATIC; } auto insertRet = usedPrivateNames.insert(name); if (insertRet.second) { unusedGetterSetterPairs[name] = unusedType; return; } auto result = unusedGetterSetterPairs.find(name); if (result == unusedGetterSetterPairs.end() || unusedGetterSetterPairs[name] != type) { ThrowSyntaxError({"Redeclaration of class private property #", name.Utf8()}, methodDef->Start()); } unusedGetterSetterPairs.erase(result); } } ir::MethodDefinition *ParserImpl::ParseClassMethod(ClassElmentDescriptor *desc, const ArenaVector &properties, ir::Expression *propName, lexer::SourcePosition *propEnd, ArenaVector &&decorators, ArenaVector &&annotations, bool isDeclare) { if (Extension() == ScriptExtension::TS) { if (desc->methodKind == ir::MethodDefinitionKind::SET || desc->methodKind == ir::MethodDefinitionKind::GET) { desc->newStatus |= ParserStatus::ACCESSOR_FUNCTION; } desc->newStatus |= ParserStatus::IN_METHOD_DEFINITION; } if (isDeclare && (desc->newStatus & ParserStatus::ASYNC_FUNCTION)) { ThrowSyntaxError("'async' modifier cannot be used in an ambient context."); } if (isDeclare && desc->isGenerator) { ThrowSyntaxError("Generators are not allowed in an ambient context."); } ArenaVector paramDecorators(Allocator()->Adapter()); ir::ScriptFunction *func = ParseFunction(desc->newStatus, isDeclare, ¶mDecorators); if (func->Body() != nullptr) { lexer_->NextToken(); } if (func->IsOverload() && !decorators.empty()) { ThrowSyntaxError("A decorator can only decorate a method implementation, not an overload.", decorators.front()->Start()); } auto *funcExpr = AllocNode(func); funcExpr->SetRange(func->Range()); lexer::SourcePosition errorInfo = decorators.empty() ? func->Start() : decorators[0]->Start(); if (desc->methodKind == ir::MethodDefinitionKind::SET) { ValidateClassSetter(desc, properties, propName, func, !decorators.empty(), errorInfo); } else if (desc->methodKind == ir::MethodDefinitionKind::GET) { ValidateClassGetter(desc, properties, propName, func, !decorators.empty(), errorInfo); } *propEnd = func->End(); func->AddFlag(ir::ScriptFunctionFlags::METHOD); ir::MethodDefinition *method = nullptr; if (desc->isPrivateIdent && Extension() == ScriptExtension::TS && program_.TargetApiVersion() <= 10) { ir::Expression *privateId = AllocNode(propName, nullptr, nullptr); auto privateIdStart = lexer::SourcePosition(propName->Start().index - 1, propName->Start().line); privateId->SetRange({privateIdStart, propName->End()}); method = AllocNode(desc->methodKind, privateId, funcExpr, desc->modifiers, Allocator(), std::move(decorators), std::move(annotations), std::move(paramDecorators), desc->isComputed); method->SetRange(funcExpr->Range()); return method; } method = AllocNode(desc->methodKind, propName, funcExpr, desc->modifiers, Allocator(), std::move(decorators), std::move(annotations), std::move(paramDecorators), desc->isComputed); method->SetRange(funcExpr->Range()); return method; } ir::ClassStaticBlock *ParserImpl::ParseStaticBlock(ClassElmentDescriptor *desc) { SavedParserContext ctx(this, desc->newStatus | ParserStatus::ALLOW_NEW_TARGET | ParserStatus::STATIC_BLOCK | ParserStatus::DISALLOW_ARGUMENTS); context_.Status() &= ~ParserStatus::FUNCTION; auto lexScope = binder::LexicalScope(Binder()); auto *blockStatement = ParseBlockStatement(); auto *staticBlock = AllocNode(lexScope.GetScope(), blockStatement); staticBlock->SetRange({desc->propStart, blockStatement->End()}); lexScope.GetScope()->BindNode(staticBlock); return staticBlock; } ir::Statement *ParserImpl::ParseClassProperty(ClassElmentDescriptor *desc, const ArenaVector &properties, ir::Expression *propName, ir::Expression *typeAnnotation, ArenaVector &&decorators, ArenaVector &&annotations, bool isDeclare, std::pair implicitScopes) { lexer::SourcePosition propEnd = propName->End(); ir::Statement *property = nullptr; if (desc->classMethod) { property = ParseClassMethod(desc, properties, propName, &propEnd, std::move(decorators), std::move(annotations), isDeclare); property->SetRange({desc->propStart, propEnd}); return property; } if (!annotations.empty()) { ThrowSyntaxError("Annotations can not be used with class properties", annotations.front()->Start()); } if (!desc->isComputed) { CheckFieldKey(propName); } ir::Expression *value = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { if (Extension() == ScriptExtension::TS && (desc->modifiers & ir::ModifierFlags::ABSTRACT)) { ThrowSyntaxError("Property cannot have an initializer because it is marked abstract."); } context_.Status() |= (ParserStatus::ALLOW_SUPER | ParserStatus::DISALLOW_ARGUMENTS); lexer_->NextToken(); // eat equals if (isDeclare) { ThrowSyntaxError("Initializers are not allowed in ambient contexts."); } auto *scope = ((desc->modifiers & ir::ModifierFlags::STATIC) != 0) ? implicitScopes.first : implicitScopes.second; auto scopeCtx = binder::LexicalScope::Enter(Binder(), scope); value = ParseExpression(); context_.Status() &= ~(ParserStatus::ALLOW_SUPER | ParserStatus::DISALLOW_ARGUMENTS); propEnd = value->End(); } if (Extension() == ScriptExtension::TS && desc->isPrivateIdent && program_.TargetApiVersion() <= 10) { auto *privateId = AllocNode(propName, value, typeAnnotation); auto privateIdStart = lexer::SourcePosition(propName->Start().index - 1, propName->Start().line); privateId->SetRange({privateIdStart, propName->End()}); propName = privateId; } property = AllocNode(propName, value, typeAnnotation, desc->modifiers, std::move(decorators), desc->isComputed, desc->modifiers & ir::ModifierFlags::DEFINITE); property->SetRange({desc->propStart, propEnd}); return property; } void ParserImpl::CheckClassGeneratorMethod(ClassElmentDescriptor *desc) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_MULTIPLY) { return; } desc->isGenerator = true; lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); } void ParserImpl::CheckClassPrivateIdentifier(ClassElmentDescriptor *desc) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_HASH_MARK) { return; } if (Extension() == ScriptExtension::AS) { return; } desc->isPrivateIdent = true; if (Extension() == ScriptExtension::TS && program_.TargetApiVersion() <= 10) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); } } void ParserImpl::CheckFieldKey(ir::Expression *propName) { if (propName->IsNumberLiteral() || propName->IsBigIntLiteral()) { return; } ASSERT(propName->IsIdentifier() || propName->IsStringLiteral() || propName->IsPrivateIdentifier()); const util::StringView &stringView = propName->IsIdentifier() ? propName->AsIdentifier()->Name() : (propName->IsStringLiteral() ? propName->AsStringLiteral()->Str() : propName->AsPrivateIdentifier()->Name()); if (stringView.Is("constructor")) { ThrowSyntaxError("Classes may not have field named 'constructor'"); } } ir::Expression *ParserImpl::ParseClassKeyAnnotation() { if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::BREAK_AT_NEW_LINE; return ParseTsTypeAnnotation(&options); } return nullptr; } ir::Statement *ParserImpl::ParseDecoratorAndAnnotation() { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT); auto lexPos = lexer_->Save(); lexer::SourcePosition start = lexer_->GetToken().Start(); lexer_->NextToken(); // eat '@' if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) { // Annotation usage case if (!program_.IsEnableAnnotations()) { ThrowSyntaxError("Annotations are not enabled"); } lexer_->NextToken(); // eat '#' ir::Expression *expr = ParseLeftHandSideExpression(); ir::Statement *resultAnnotation = static_cast(AllocNode(expr)); resultAnnotation->SetRange({start, expr->End()}); return resultAnnotation; } ir::Expression *expr = ParseLeftHandSideExpression(); if (expr->IsIdentifier() && expr->AsIdentifier()->Name().Utf8() == ir::Annotation::interfaceString) { // Annotation declaration case if (!program_.IsEnableAnnotations()) { ThrowSyntaxError("Annotations are not enabled"); } lexer_->Rewind(lexPos); return nullptr; } // Decorator case ir::Statement *resultDecorator = static_cast(AllocNode(expr)); resultDecorator->SetRange({start, expr->End()}); return resultDecorator; } std::pair, ArenaVector> ParserImpl::ParseDecoratorsAndAnnotations() { ArenaVector decorators(Allocator()->Adapter()); ArenaVector annotations(Allocator()->Adapter()); auto savedStatus = context_.Status(); context_.Status() |= ParserStatus::IN_DECORATOR; while (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) { ir::Statement *stmt = ParseDecoratorAndAnnotation(); if (stmt == nullptr) { // Annotation declaration was encountered and will be processed further in ParseClassDeclaration context_.Status() = savedStatus; return {decorators, annotations}; } if (stmt->IsDecorator()) { decorators.push_back(stmt->AsDecorator()); } else { annotations.push_back(stmt->AsAnnotation()); } } if (!decorators.empty() && lexer_->GetToken().Type() != lexer::TokenType::KEYW_CLASS && (context_.Status() & ParserStatus::IN_CLASS_BODY) == 0 && lexer_->GetToken().Type() != lexer::TokenType::KEYW_EXPORT && !(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE || lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT))) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } context_.Status() = savedStatus; return {decorators, annotations}; } ir::Statement *ParserImpl::ParseClassElement(const ArenaVector &properties, ArenaVector *indexSignatures, bool hasSuperClass, bool isDeclare, bool isAbstractClass, bool isExtendsFromNull, std::pair implicitScopes) { ClassElmentDescriptor desc; desc.methodKind = ir::MethodDefinitionKind::METHOD; desc.newStatus = ParserStatus::ALLOW_SUPER; desc.hasSuperClass = hasSuperClass; desc.propStart = lexer_->GetToken().Start(); auto decoratorsAndAnnotations = ParseDecoratorsAndAnnotations(); auto decorators = decoratorsAndAnnotations.first; auto annotations = decoratorsAndAnnotations.second; desc.modifiers = ParseModifiers(); if ((desc.modifiers & ir::ModifierFlags::ABSTRACT) && !isAbstractClass) { ThrowSyntaxError("Abstract methods can only appear within an abstract class."); } if (!decorators.empty() && (desc.modifiers & ir::ModifierFlags::ACCESSOR)) { ThrowSyntaxError("Decorators are not available for auto accessor property now."); } if ((desc.modifiers & ir::ModifierFlags::OVERRIDE) && (!desc.hasSuperClass || isExtendsFromNull)) { ThrowSyntaxError({"This member cannot have an 'override' modifier because its containing class " "does not extend another class."}); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { if (!(desc.modifiers == ir::ModifierFlags::STATIC)) { ThrowSyntaxError("Unexpected token '{'"); } if (!decorators.empty()) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } auto scopeCtx = binder::LexicalScope::Enter(Binder(), implicitScopes.first); return ParseStaticBlock(&desc); } CheckClassGeneratorMethod(&desc); ParseClassKeyModifiers(&desc); CheckClassPrivateIdentifier(&desc); if (desc.isPrivateIdent && !decorators.empty()) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } if (!(desc.modifiers & ir::ModifierFlags::STATIC)) { context_.Status() |= ParserStatus::ALLOW_THIS_TYPE; } ir::Expression *propName = ParseClassKey(&desc, isDeclare); if (desc.methodKind == ir::MethodDefinitionKind::CONSTRUCTOR && !decorators.empty()) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { if (desc.isIndexSignature) { ThrowSyntaxError("';' expected"); } if (desc.methodKind == ir::MethodDefinitionKind::CONSTRUCTOR) { ThrowSyntaxError("'(' expected"); } if (desc.modifiers & ir::ModifierFlags::ACCESSOR) { ThrowSyntaxError("An auto accessor property can't be declared optional."); } desc.modifiers |= ir::ModifierFlags::OPTIONAL; lexer_->NextToken(); } else if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { if (desc.isIndexSignature || lexer_->Lookahead() != LEX_CHAR_COLON) { ThrowSyntaxError("';' expected"); } desc.modifiers |= ir::ModifierFlags::DEFINITE; lexer_->NextToken(); } ir::Expression *typeAnnotation = ParseClassKeyAnnotation(); ir::Statement *property = nullptr; if (desc.isIndexSignature) { if (!decorators.empty()) { ThrowSyntaxError("Decorators are not valid here.", decorators.front()->Start()); } if (!typeAnnotation) { ThrowSyntaxError("An index signature must have a type annotation"); } auto *indexSignature = AllocNode(propName, typeAnnotation, desc.modifiers & ir::ModifierFlags::READONLY, desc.modifiers & ir::ModifierFlags::STATIC); indexSignature->SetRange({desc.propStart, indexSignature->TypeAnnotation()->End()}); indexSignatures->push_back(indexSignature); property = AllocNode(); } else { ValidateClassMethodStart(&desc, typeAnnotation); property = ParseClassProperty(&desc, properties, propName, typeAnnotation, std::move(decorators), std::move(annotations), isDeclare || (desc.modifiers & ir::ModifierFlags::DECLARE), implicitScopes); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && !(lexer_->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) && !(property->IsMethodDefinition() && property->AsMethodDefinition()->Value()->Function()->Body())) { ThrowSyntaxError("';' expected."); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); } context_.Status() &= ~ParserStatus::ALLOW_THIS_TYPE; return property; } static bool IsConstructor(ir::Statement *stmt) { if (!stmt->IsMethodDefinition()) { return false; } ir::MethodDefinition *def = stmt->AsMethodDefinition(); return def->Kind() == ir::MethodDefinitionKind::CONSTRUCTOR; } ir::Identifier *ParserImpl::GetKeyByFuncFlag(ir::ScriptFunctionFlags funcFlag) { ir::Identifier *key = nullptr; switch (funcFlag) { case ir::ScriptFunctionFlags::CONSTRUCTOR: { key = AllocNode("constructor"); break; } case ir::ScriptFunctionFlags::STATIC_INITIALIZER: { key = AllocNode("static_initializer"); break; } case ir::ScriptFunctionFlags::INSTANCE_INITIALIZER: { key = AllocNode("instance_initializer"); break; } default: { UNREACHABLE(); } } return key; } ir::MethodDefinition *ParserImpl::CreateImplicitMethod(ir::Expression *superClass, bool hasSuperClass, ir::ScriptFunctionFlags funcFlag, bool isDeclare) { ArenaVector params(Allocator()->Adapter()); ArenaVector statements(Allocator()->Adapter()); auto *paramScope = Binder()->Allocator()->New(Allocator(), Binder()->GetScope()); auto *scope = Binder()->Allocator()->New(Allocator(), paramScope); CHECK_NOT_NULL(scope); CHECK_NOT_NULL(paramScope); bool isConstructor = (funcFlag == ir::ScriptFunctionFlags::CONSTRUCTOR); if (isConstructor && hasSuperClass) { if (Extension() != ScriptExtension::TS || !superClass->IsNullLiteral()) { util::StringView argsStr = "args"; params.push_back(AllocNode(ir::AstNodeType::REST_ELEMENT, AllocNode(argsStr))); paramScope->AddParamDecl(Allocator(), params.back()); ArenaVector callArgs(Allocator()->Adapter()); auto *superExpr = AllocNode(); callArgs.push_back(AllocNode(ir::AstNodeType::SPREAD_ELEMENT, AllocNode(argsStr))); auto *callExpr = AllocNode(superExpr, std::move(callArgs), nullptr, false); statements.push_back(AllocNode(callExpr)); } } auto *body = AllocNode(scope, std::move(statements)); auto *func = AllocNode(scope, std::move(params), nullptr, isDeclare ? nullptr : body, nullptr, funcFlag, isDeclare, Extension() == ScriptExtension::TS); if (isConstructor) { func->AddFlag(ir::ScriptFunctionFlags::GENERATED_CONSTRUCTOR); } scope->BindNode(func); paramScope->BindNode(func); scope->BindParamScope(paramScope); paramScope->BindFunctionScope(scope); auto *funcExpr = AllocNode(func); ir::Identifier *key = GetKeyByFuncFlag(funcFlag); auto methodKind = isConstructor ? ir::MethodDefinitionKind::CONSTRUCTOR : ir::MethodDefinitionKind::METHOD; ArenaVector decorators(Allocator()->Adapter()); ArenaVector annotations(Allocator()->Adapter()); ArenaVector paramDecorators(Allocator()->Adapter()); auto *method = AllocNode(methodKind, key, funcExpr, ir::ModifierFlags::NONE, Allocator(), std::move(decorators), std::move(annotations), std::move(paramDecorators), false); return method; } bool ParserImpl::IsPropertyKeysAreSame(const ir::Expression *exp1, const ir::Expression *exp2) { if (exp1->IsIdentifier() && exp2->IsIdentifier()) { return exp1->AsIdentifier()->Name() == exp2->AsIdentifier()->Name(); } if (exp1->IsIdentifier() && exp2->IsStringLiteral()) { return exp1->AsIdentifier()->Name() == exp2->AsStringLiteral()->Str(); } if (exp1->IsStringLiteral() && exp2->IsStringLiteral()) { return *exp1->AsStringLiteral() == *exp2->AsStringLiteral(); } if (exp1->IsStringLiteral() && exp2->IsIdentifier()) { return exp1->AsStringLiteral()->Str() == exp2->AsIdentifier()->Name(); } if (exp1->IsStringLiteral() && exp2->IsNumberLiteral()) { std::string exp2String = std::to_string(exp2->AsNumberLiteral()->Number()); exp2String.erase(exp2String.find_last_not_of('0'), std::string::npos); return exp1->AsStringLiteral()->Str().Utf8() == exp2String; } if (exp1->IsNumberLiteral() && exp2->IsNumberLiteral()) { return exp1->AsNumberLiteral()->Number() == exp2->AsNumberLiteral()->Number(); } if (exp1->IsNumberLiteral() && exp2->IsStringLiteral()) { std::string exp1String = std::to_string(exp1->AsNumberLiteral()->Number()); exp1String.erase(exp1String.find_last_not_of('0'), std::string::npos); return exp1String == exp2->AsStringLiteral()->Str().Utf8(); } return false; } bool ParserImpl::IsMemberExpressionsAreSame(const ir::MemberExpression *mExp1, const ir::MemberExpression *mExp2) { if (!IsPropertyKeysAreSame(mExp1->Property(), mExp2->Property())) { return false; } if (mExp1->Object()->IsMemberExpression() && mExp2->Object()->IsMemberExpression()) { return IsMemberExpressionsAreSame(mExp1->Object()->AsMemberExpression(), mExp2->Object()->AsMemberExpression()); } return IsPropertyKeysAreSame(mExp1->Object(), mExp2->Object()); } bool ParserImpl::IsMethodDefinitionsAreSame(const ir::MethodDefinition *property, ir::MethodDefinition *overload) { if (property->Kind() != overload->Kind() || property->IsStatic() != overload->IsStatic()) { return false; } if (property->Key()->IsMemberExpression() && overload->Key()->IsMemberExpression()) { return IsMemberExpressionsAreSame(property->Key()->AsMemberExpression(), overload->Key()->AsMemberExpression()); } return IsPropertyKeysAreSame(property->Key(), overload->Key()); } ir::Identifier *ParserImpl::SetIdentNodeInClassDefinition(bool isDeclare, binder::ConstDecl **decl) { if (!isDeclare) { CheckStrictReservedWord(); } const util::StringView &identStr = lexer_->GetToken().Ident(); *decl = Binder()->AddDecl(lexer_->GetToken().Start(), isDeclare, identStr); auto *identNode = AllocNode(identStr); identNode->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return identNode; } ir::ClassDefinition *ParserImpl::ParseClassDefinition(bool isDeclaration, bool idRequired, bool isDeclare, bool isAbstract) { isDeclare = isDeclare | (context_.Status() & ParserStatus::IN_AMBIENT_CONTEXT); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); binder::ConstDecl *decl = nullptr; ir::Identifier *identNode = nullptr; auto classCtx = binder::LexicalScope(Binder()); if ((lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT) && (Extension() != ScriptExtension::TS || lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_IMPLEMENTS)) { identNode = SetIdentNodeInClassDefinition(isDeclare, &decl); } else if (isDeclaration && idRequired) { ThrowSyntaxError("Unexpected token, expected an identifier."); } ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { typeParamDecl = ParseTsTypeParameterDeclaration(true, true); } // Parse SuperClass bool hasSuperClass = false; bool isExtendsFromNull = false; ir::Expression *superClass = ParseSuperClass(isDeclare, &hasSuperClass, &isExtendsFromNull); ir::TSTypeParameterInstantiation *superTypeParams = nullptr; if (Extension() == ScriptExtension::TS && (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT)) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) { lexer_->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); } superTypeParams = ParseTsTypeParameterInstantiation(); } ArenaVector implements = ParseTSClassImplements(isDeclare); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ThrowSyntaxError("Unexpected token, expected '{'"); } // Parse ClassBody auto savedStatus = context_.Status(); context_.Status() |= ParserStatus::IN_CLASS_BODY; context_.Status() &= ~(ParserStatus::CONSTRUCTOR_FUNCTION); lexer::SourcePosition classBodyStartLoc = lexer_->GetToken().Start(); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); ir::MethodDefinition *ctor = nullptr; ir::MethodDefinition *staticInitializer = CreateImplicitMethod(superClass, hasSuperClass, ir::ScriptFunctionFlags::STATIC_INITIALIZER, isDeclare); ir::MethodDefinition *instanceInitializer = CreateImplicitMethod(superClass, hasSuperClass, ir::ScriptFunctionFlags::INSTANCE_INITIALIZER, isDeclare); ArenaVector properties(Allocator()->Adapter()); ArenaVector indexSignatures(Allocator()->Adapter()); bool hasConstructorFuncBody = false; bool isCtorContinuousDefined = true; auto *static_scope = staticInitializer->Function()->Scope(); auto *instance_scope = instanceInitializer->Function()->Scope(); std::unordered_set usedPrivateNames; std::unordered_map unusedGetterSetterPairs; while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); continue; } ir::Statement *property = ParseClassElement(properties, &indexSignatures, hasSuperClass, isDeclare, isAbstract, isExtendsFromNull, std::make_pair(static_scope, instance_scope)); if (property->IsEmptyStatement()) { continue; } if (IsConstructor(property)) { if (!isDeclare && !isCtorContinuousDefined) { ThrowSyntaxError("Constructor implementation is missing.", property->Start()); } if (hasConstructorFuncBody) { ThrowSyntaxError("Multiple constructor implementations are not allowed.", property->Start()); } ctor = property->AsMethodDefinition(); hasConstructorFuncBody = ctor->Value()->Function()->Body() != nullptr; continue; } isCtorContinuousDefined = ctor == nullptr; ValidatePrivateProperty(property, usedPrivateNames, unusedGetterSetterPairs); properties.push_back(property); } context_.Status() = savedStatus; lexer::SourcePosition classBodyEndLoc = lexer_->GetToken().End(); if (ctor == nullptr) { ctor = CreateImplicitMethod(superClass, hasSuperClass, ir::ScriptFunctionFlags::CONSTRUCTOR, isDeclare); ctor->SetRange({startLoc, classBodyEndLoc}); hasConstructorFuncBody = !isDeclare; } lexer_->NextToken(); ValidateClassConstructor(ctor, properties, isDeclare, hasConstructorFuncBody, hasSuperClass, isExtendsFromNull); auto *classDefinition = AllocNode( classCtx.GetScope(), identNode, typeParamDecl, superTypeParams, std::move(implements), ctor, staticInitializer, instanceInitializer, superClass, std::move(properties), std::move(indexSignatures), isDeclare, isAbstract); classDefinition->SetRange({classBodyStartLoc, classBodyEndLoc}); if (decl != nullptr) { decl->BindNode(classDefinition); } classCtx.GetScope()->BindNode(classDefinition); return classDefinition; } ir::Expression *ParserImpl::ParseSuperClass(bool isDeclare, bool *hasSuperClass, bool *isExtendsFromNull) { ir::Expression *superClass = nullptr; if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_EXTENDS) { return nullptr; } lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT && isDeclare) { lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); } *hasSuperClass = true; superClass = ParseLeftHandSideExpression(); ASSERT(superClass != nullptr); *isExtendsFromNull = superClass->IsNullLiteral(); return superClass; } ArenaVector ParserImpl::ParseTSClassImplements(bool isDeclare) { ArenaVector implements(Allocator()->Adapter()); if (Extension() != ScriptExtension::TS || lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_IMPLEMENTS) { return implements; } lexer_->NextToken(); while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { lexer::SourcePosition implStart = lexer_->GetToken().Start(); if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && !(lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT && isDeclare)) { ThrowSyntaxError("Identifier expected"); } ir::Expression *expr = AllocNode(lexer_->GetToken().Ident()); expr->SetRange(lexer_->GetToken().Loc()); expr->AsIdentifier()->SetReference(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { expr = ParseTsQualifiedReference(expr); } 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) { implTypeParams = ParseTsTypeParameterInstantiation(); } auto *impl = AllocNode(expr, implTypeParams); impl->SetRange({implStart, lexer_->GetToken().End()}); implements.push_back(impl); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); continue; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ThrowSyntaxError("',' expected"); } } if (implements.empty()) { ThrowSyntaxError("Implements clause can not be empty"); } return implements; } void ParserImpl::ValidateClassConstructor(const ir::MethodDefinition *ctor, const ArenaVector &properties, bool isDeclare, bool hasConstructorFuncBody, bool hasSuperClass, bool isExtendsFromNull) { if (!hasConstructorFuncBody) { if (isDeclare) { return; } ThrowSyntaxError("Constructor implementation is missing.", ctor->Start()); } if (Extension() != ScriptExtension::TS || !hasSuperClass) { return; } bool hasSuperCall = false; FindSuperCall(ctor->Function()->Body()->AsBlockStatement(), &hasSuperCall); if (hasSuperCall) { if (isExtendsFromNull) { ThrowSyntaxError("A constructor cannot contain a super call when its class extends null.", ctor->Start()); } ValidateSuperCallLocation(ctor, SuperCallShouldBeRootLevel(ctor, properties)); } else { if (!isExtendsFromNull) { ThrowSyntaxError("Constructors for derived classes must contain a super call.", ctor->Start()); } } } void ParserImpl::FindSuperCall(const ir::AstNode *parent, bool *hasSuperCall) { parent->Iterate([this, hasSuperCall](auto *childNode) { FindSuperCallInCtorChildNode(childNode, hasSuperCall); }); } void ParserImpl::FindSuperCallInCtorChildNode(const ir::AstNode *childNode, bool *hasSuperCall) { if (*hasSuperCall) { return; } switch (childNode->Type()) { case ir::AstNodeType::CALL_EXPRESSION: { if (childNode->AsCallExpression()->Callee()->IsSuperExpression()) { *hasSuperCall = true; return; } break; } case ir::AstNodeType::CLASS_DEFINITION: case ir::AstNodeType::FUNCTION_DECLARATION: case ir::AstNodeType::FUNCTION_EXPRESSION: case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION: { break; } default: { FindSuperCall(childNode, hasSuperCall); break; } } } bool ParserImpl::SuperCallShouldBeRootLevel(const ir::MethodDefinition *ctor, const ArenaVector &properties) { for (const auto *property : properties) { if (property->IsClassProperty()) { auto *classProperty = property->AsClassProperty(); bool isPrivateProperty = program_.TargetApiVersion() > 10 ? classProperty->Key()->IsPrivateIdentifier() : classProperty->Key()->IsTSPrivateIdentifier(); if (classProperty->Value() != nullptr || isPrivateProperty) { return true; } } } for (const auto ¶m : ctor->Function()->Params()) { if (param->IsTSParameterProperty() && (param->AsTSParameterProperty()->Accessibility() != ir::AccessibilityOption::NO_OPTS || param->AsTSParameterProperty()->Readonly())) { return true; } } return false; } void ParserImpl::ValidateSuperCallLocation(const ir::MethodDefinition *ctor, bool superCallShouldBeRootLevel) { bool hasThisOrSuperReferenceBeforeSuperCall = false; const ir::BlockStatement *blockStat = ctor->Function()->Body()->AsBlockStatement(); if (superCallShouldBeRootLevel) { bool superCallInRootLevel = false; for (auto iter = blockStat->Statements().begin(); iter != blockStat->Statements().end(); iter++) { if ((*iter)->IsExpressionStatement() && (*iter)->AsExpressionStatement()->GetExpression()->IsCallExpression() && (*iter)->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsSuperExpression()) { superCallInRootLevel = true; break; } if (!hasThisOrSuperReferenceBeforeSuperCall) { FindThisOrSuperReferenceInChildNode(*iter, &hasThisOrSuperReferenceBeforeSuperCall); } } if (!superCallInRootLevel) { ThrowSyntaxError("A super call must be a root-level statement within a constructor of a derived class " "that contains initialized properties, parameter properties, or private identifiers.", ctor->Start()); } } else { for (auto iter = blockStat->Statements().begin(); iter != blockStat->Statements().end(); iter++) { bool superCallInStatement = false; FindSuperCallInCtorChildNode(*iter, &superCallInStatement); if (superCallInStatement) { break; } if (!hasThisOrSuperReferenceBeforeSuperCall) { FindThisOrSuperReferenceInChildNode(*iter, &hasThisOrSuperReferenceBeforeSuperCall); } } } if (hasThisOrSuperReferenceBeforeSuperCall) { ThrowSyntaxError("super() must be called before this/super access.", ctor->Start()); } } void ParserImpl::FindThisOrSuperReference(const ir::AstNode *parent, bool *hasThisOrSuperReference) { parent->Iterate([this, hasThisOrSuperReference](auto *childNode) { FindThisOrSuperReferenceInChildNode(childNode, hasThisOrSuperReference); }); } void ParserImpl::FindThisOrSuperReferenceInChildNode(const ir::AstNode *childNode, bool *hasThisOrSuperReference) { if (*hasThisOrSuperReference) { return; } // The logic for finding ThisOrSuperReference is coarse-grained and may miss some cases. switch (childNode->Type()) { case ir::AstNodeType::THIS_EXPRESSION: case ir::AstNodeType::SUPER_EXPRESSION: { *hasThisOrSuperReference = true; break; } case ir::AstNodeType::CLASS_DEFINITION: case ir::AstNodeType::FUNCTION_DECLARATION: case ir::AstNodeType::FUNCTION_EXPRESSION: case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION: { break; } default: { FindThisOrSuperReference(childNode, hasThisOrSuperReference); break; } } } ir::Expression *ParserImpl::ParseEnumComputedPropertyKey(binder::EnumDecl *&decl, const lexer::SourcePosition &keyStartLoc, bool isDeclare) { ir::Expression *memberKey = nullptr; lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { memberKey = AllocNode(lexer_->GetToken().String()); decl = Binder()->AddDecl(keyStartLoc, isDeclare, lexer_->GetToken().String()); memberKey->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BACK_TICK) { lexer_->ResetTokenEnd(); const auto startPos = lexer_->Save(); lexer_->ScanString(); util::StringView cooked = lexer_->GetToken().String(); lexer_->Rewind(startPos); memberKey = ParsePrimaryExpression(); ArenaVector expressions = memberKey->AsTemplateLiteral()->Expressions(); if (!expressions.empty()) { ThrowSyntaxError("Computed property names are not allowed in enums"); } decl = Binder()->AddDecl(keyStartLoc, isDeclare, cooked); memberKey->SetRange(lexer_->GetToken().Loc()); } else { ThrowSyntaxError("Unexpected token in enum member"); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { ThrowSyntaxError("Unexpected token, expected ']'"); } lexer_->NextToken(); return memberKey; } ir::TSEnumDeclaration *ParserImpl::ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isExport, bool isDeclare, bool isConst) { if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ThrowSyntaxError("'{' expected"); } ArenaVector members(Allocator()->Adapter()); lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat '{' while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { ir::Expression *memberKey = nullptr; const auto &keyStartLoc = lexer_->GetToken().Start(); binder::EnumDecl *decl {}; if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { memberKey = AllocNode(lexer_->GetToken().Ident()); decl = Binder()->AddDecl(keyStartLoc, isDeclare, lexer_->GetToken().Ident()); memberKey->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { memberKey = AllocNode(lexer_->GetToken().String()); decl = Binder()->AddDecl(keyStartLoc, isDeclare, lexer_->GetToken().String()); memberKey->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { memberKey = ParseEnumComputedPropertyKey(decl, keyStartLoc, isDeclare); } else { ThrowSyntaxError("Unexpected token in enum member"); } ir::Expression *memberInit = nullptr; lexer::SourcePosition initStart = lexer_->GetToken().Start(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { lexer_->NextToken(); // eat '=' initStart = lexer_->GetToken().Start(); memberInit = ParseExpression(); } auto *member = AllocNode(memberKey, memberInit); decl->BindNode(member); member->SetRange({initStart, lexer_->GetToken().End()}); members.push_back(member); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(lexer::LexerNextTokenFlags::KEYWORD_TO_IDENT); // eat ',' } } auto *enumDeclaration = AllocNode( Binder()->GetScope()->AsTSEnumScope(), key, std::move(members), isExport, isDeclare, isConst); enumDeclaration->SetRange({enumStart, lexer_->GetToken().End()}); Binder()->GetScope()->BindNode(enumDeclaration); lexer_->NextToken(); // eat '}' return enumDeclaration; } ir::TSEnumDeclaration *ParserImpl::ParseEnumDeclaration(bool isExport, bool isDeclare, bool isConst) { ASSERT(lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ENUM); lexer::SourcePosition enumStart = lexer_->GetToken().Start(); lexer_->NextToken(); // eat enum keyword if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT && lexer_->GetToken().Type() != lexer::TokenType::KEYW_AWAIT) { ThrowSyntaxError("Identifier expected"); } const util::StringView &ident = lexer_->GetToken().Ident(); auto *currentScope = Binder()->GetScope(); binder::Variable *res = currentScope->FindLocalTSVariable(ident); if (res == nullptr && isExport && currentScope->IsTSModuleScope()) { res = currentScope->AsTSModuleScope()->FindExportTSVariable(ident); if (res != nullptr) { currentScope->AddLocalTSVariable(ident, res); } } if (res == nullptr) { Binder()->AddTsDecl(lexer_->GetToken().Start(), isDeclare, Allocator(), ident, isExport, isConst); res = currentScope->FindLocalTSVariable(ident); if (isExport && currentScope->IsTSModuleScope()) { currentScope->AsTSModuleScope()->AddExportTSVariable(ident, res); } res->AsEnumLiteralVariable()->SetEnumMembers(Allocator()->New(Allocator()->Adapter())); } binder::VariableMap *enumMemberBindings = res->AsEnumLiteralVariable()->GetEnumMembers(); auto *key = AllocNode(ident); key->SetRange(lexer_->GetToken().Loc()); key->SetReference(); lexer_->NextToken(); if (!res->Declaration()->IsEnumLiteralDecl() || (isConst ^ res->Declaration()->AsEnumLiteralDecl()->IsConst())) { Binder()->ThrowRedeclaration(lexer_->GetToken().Start(), ident); } auto enumCtx = binder::LexicalScope(Binder(), enumMemberBindings); auto *enumDeclaration = ParseEnumMembers(key, enumStart, isExport, isDeclare, isConst); res->Declaration()->AsEnumLiteralDecl()->Add(enumDeclaration); res->Declaration()->BindNode(enumDeclaration); return enumDeclaration; } void ParserImpl::ValidateFunctionParam(const ArenaVector ¶ms, const ir::Expression *parameter, bool *seenOptional) { if (!parameter->IsIdentifier()) { context_.Status() |= ParserStatus::HAS_COMPLEX_PARAM; if (!parameter->IsRestElement()) { return; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { const char *msg = (Extension() == ScriptExtension::JS ? "Rest parameter must be last formal parameter" : "A rest parameter must be last in parameter list"); ThrowSyntaxError(msg); } return; } if (Extension() != ScriptExtension::TS) { return; } bool currentIsOptinal = parameter->AsIdentifier()->IsOptional(); if (*seenOptional && !currentIsOptinal) { ThrowSyntaxError("A required parameter cannot follow an optional parameter"); } *seenOptional |= currentIsOptinal; const util::StringView ¶mName = parameter->AsIdentifier()->Name(); if (paramName.Is("this")) { if (!params.empty()) { ThrowSyntaxError("A 'this' parameter must be the first parameter"); } if (context_.Status() & ParserStatus::CONSTRUCTOR_FUNCTION) { ThrowSyntaxError("A constructor cannot have a 'this' parameter"); } if (context_.Status() & ParserStatus::ARROW_FUNCTION) { ThrowSyntaxError("An arrow function cannot have a 'this' parameter"); } if (context_.Status() & ParserStatus::ACCESSOR_FUNCTION) { ThrowSyntaxError("'get' and 'set' accessors cannot declare 'this' parameters"); } } if (paramName.Is("constructor") && (context_.Status() & ParserStatus::CONSTRUCTOR_FUNCTION)) { ThrowSyntaxError("'constructor' cannot be used as a parameter property name"); } } ArenaVector ParserImpl::ParseFunctionParams(bool isDeclare, ArenaVector *paramDecorators) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer_->NextToken(); ArenaVector params(Allocator()->Adapter()); bool seenOptional = false; size_t index = 0; while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { if (context_.Status() & ParserStatus::IN_METHOD_DEFINITION) { auto decoratorsAndAnnotations = ParseDecoratorsAndAnnotations(); auto decorators = decoratorsAndAnnotations.first; auto annotations = decoratorsAndAnnotations.second; if (!annotations.empty()) { ThrowSyntaxError("Annotations can not be used with function parameters", annotations.front()->Start()); } if (!decorators.empty()) { ASSERT(paramDecorators != nullptr); paramDecorators->push_back({index, std::move(decorators)}); } } ir::Expression *parameter = ParseFunctionParameter(isDeclare); ValidateFunctionParam(params, parameter, &seenOptional); params.push_back(parameter); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { ThrowSyntaxError(", expected"); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); } index++; } ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); lexer_->NextToken(); return params; } bool ParserImpl::CheckTypeNameIsReserved(const util::StringView ¶mName) { return paramName.Is("number") || paramName.Is("any") || paramName.Is("unknown") || paramName.Is("never") || paramName.Is("bigint") || paramName.Is("boolean") || paramName.Is("string") || paramName.Is("string") || paramName.Is("void") || paramName.Is("object"); } bool ParserImpl::CheckOutIsIdentInTypeParameter() { auto pos = lexer_->Save(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_GREATER_THAN || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->Rewind(pos); return true; } lexer_->Rewind(pos); return false; } void ParserImpl::ParseTypeModifier(bool &isTypeIn, bool &isTypeOut, bool &isAllowInOut) { if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IN) { if (!isAllowInOut) { ThrowSyntaxError("'in' modifier can only appear on a type parameter of a class, interface or type alias"); } isTypeIn = true; lexer_->NextToken(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IN) { ThrowSyntaxError("'in' modifier already seen."); } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OUT && !CheckOutIsIdentInTypeParameter()) { isTypeOut = true; lexer_->NextToken(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OUT && !CheckOutIsIdentInTypeParameter()) { ThrowSyntaxError("'out' modifier already seen."); } } } else if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OUT && !CheckOutIsIdentInTypeParameter()) { if (!isAllowInOut) { ThrowSyntaxError("'out' modifier can only appear on a type parameter of a class, interface or type alias"); } isTypeOut = true; lexer_->NextToken(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IN) { ThrowSyntaxError("'in' modifier must precede 'out' modifier."); } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OUT && !CheckOutIsIdentInTypeParameter()) { ThrowSyntaxError("'out' modifier already seen."); } } } ir::TSTypeParameter *ParserImpl::ParseTsTypeParameter(bool throwError, bool addBinding, bool isAllowInOut) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); bool isTypeIn = false; bool isTypeOut = false; ParseTypeModifier(isTypeIn, isTypeOut, isAllowInOut); if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { if (!throwError) { return nullptr; } ThrowSyntaxError("Type parameter declaration expected"); } const auto &ident = lexer_->GetToken().Ident(); if (CheckTypeNameIsReserved(ident)) { if (!throwError) { return nullptr; } ThrowSyntaxError("Invalid type parameter name"); } auto *paramIdent = AllocNode(ident); if (addBinding) { Binder()->AddDecl(lexer_->GetToken().Start(), false, ident); } paramIdent->SetRange({lexer_->GetToken().Start(), lexer_->GetToken().End()}); lexer_->NextToken(); TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::NO_OPTS; if (throwError) { options |= TypeAnnotationParsingOptions::THROW_ERROR; } ir::Expression *constraint = TryParseConstraintOfInferType(&options); ir::Expression *defaultType = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { lexer_->NextToken(); defaultType = ParseTsTypeAnnotation(&options); } auto *typeParam = AllocNode(paramIdent, constraint, defaultType, isTypeIn, isTypeOut); typeParam->SetRange({startLoc, lexer_->GetToken().End()}); return typeParam; } ir::Expression *ParserImpl::TryParseConstraintOfInferType(TypeAnnotationParsingOptions *options) { ir::Expression *constraint = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { auto savedPos = lexer_->Save(); lexer_->NextToken(); // eat 'extends' constraint = DoInsideOfDisallowConditinalTypesContext(&ParserImpl::ParseTsTypeAnnotation, options); if (!InDisallowConditionalTypesContext() && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { constraint = nullptr; lexer_->Rewind(savedPos); // go back to 'extends' } } return constraint; } ir::TSTypeParameterDeclaration *ParserImpl::ParseTsTypeParameterDeclaration(bool throwError, bool isAllowInOut) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN); auto localCtx = binder::LexicalScope(Binder()); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ArenaVector params(Allocator()->Adapter()); bool seenDefault = false; size_t requiredParams = 0; lexer_->NextToken(); // eat '<' while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_GREATER_THAN) { ir::TSTypeParameter *currentParam = ParseTsTypeParameter(throwError, true, isAllowInOut); if (!currentParam) { ASSERT(!throwError); return nullptr; } if (currentParam->DefaultType()) { seenDefault = true; } else if (seenDefault) { ThrowSyntaxError("Required type parameters may not follow optional type parameters."); } else { requiredParams++; } params.push_back(currentParam); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); continue; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_GREATER_THAN) { if (!throwError) { return nullptr; } ThrowSyntaxError("'>' expected"); } } if (params.empty()) { ThrowSyntaxError("Type parameter list cannot be empty."); } lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); // eat '>' auto *typeParamDecl = AllocNode(localCtx.GetScope(), std::move(params), requiredParams); typeParamDecl->SetRange({startLoc, endLoc}); localCtx.GetScope()->BindNode(typeParamDecl); return typeParamDecl; } ir::TSTypeParameterInstantiation *ParserImpl::ParseTsTypeParameterInstantiation(bool throwError) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ArenaVector params(Allocator()->Adapter()); lexer_->NextToken(); // eat '<' while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_GREATER_THAN) { TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::NO_OPTS; if (throwError) { options |= TypeAnnotationParsingOptions::THROW_ERROR; } ir::Expression *currentParam = ParseTsTypeAnnotation(&options); if (!currentParam) { return nullptr; } params.push_back(currentParam); switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_COMMA: { lexer_->NextToken(); continue; } case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: { lexer_->BackwardToken(lexer::TokenType::PUNCTUATOR_GREATER_THAN, 1); break; } case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: { lexer_->BackwardToken(lexer::TokenType::PUNCTUATOR_GREATER_THAN, 2); break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { break; } default: { if (throwError) { ThrowSyntaxError("'>' expected"); } return nullptr; } } } lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); auto *typeParamInst = AllocNode(std::move(params)); typeParamInst->SetRange({startLoc, endLoc}); return typeParamInst; } ir::ScriptFunction *ParserImpl::ParseFunction(ParserStatus newStatus, bool isDeclare, ArenaVector *paramDecorators) { FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION | ParserStatus::ALLOW_NEW_TARGET); FunctionParameterContext funcParamContext(&context_, Binder()); auto *funcParamScope = funcParamContext.LexicalScope().GetScope(); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { typeParamDecl = ParseTsTypeParameterDeclaration(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { ThrowSyntaxError("Unexpected token, expected '('"); } if ((newStatus & (ParserStatus::ASYNC_FUNCTION | ParserStatus::FUNCTION_DECLARATION)) | context_.IsModule()) { context_.Status() |= ParserStatus::DISALLOW_AWAIT; } ArenaVector params = ParseFunctionParams(isDeclare, paramDecorators); ir::Expression *returnTypeAnnotation = nullptr; if (Extension() == ScriptExtension::TS && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE; returnTypeAnnotation = ParseTsTypeAnnotation(&options); } auto functionCtx = binder::LexicalScope(Binder()); auto *functionScope = functionCtx.GetScope(); functionScope->BindParamScope(funcParamScope); funcParamScope->BindFunctionScope(functionScope); ir::BlockStatement *body = nullptr; lexer::SourcePosition endLoc = lexer_->GetToken().End(); bool letDeclare = true; if (newStatus & ParserStatus::ASYNC_FUNCTION) { context_.Status() &= ~ParserStatus::DISALLOW_AWAIT; } else { context_.Status() |= ParserStatus::DISALLOW_AWAIT; } if (newStatus & ParserStatus::GENERATOR_FUNCTION) { context_.Status() |= ParserStatus::ALLOW_YIELD; } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { if (Extension() == ScriptExtension::TS && (newStatus & ParserStatus::FUNCTION_DECLARATION)) { ValidateTsFunctionOverloadParams(params); functionContext.AddFlag(ir::ScriptFunctionFlags::OVERLOAD); } else if (!isDeclare && !(context_.Status() & ParserStatus::IN_METHOD_DEFINITION)) { ThrowSyntaxError("Unexpected token, expected '{'"); } else { letDeclare = false; functionContext.AddFlag(ir::ScriptFunctionFlags::OVERLOAD); } } else if (isDeclare) { ThrowSyntaxError("An implementation cannot be declared in ambient contexts."); } else { body = ParseBlockStatement(functionScope); endLoc = body->End(); } auto *funcNode = AllocNode(functionScope, std::move(params), typeParamDecl, body, returnTypeAnnotation, functionContext.Flags(), isDeclare && letDeclare, Extension() == ScriptExtension::TS); functionScope->BindNode(funcNode); funcParamScope->BindNode(funcNode); funcNode->SetRange({startLoc, endLoc}); return funcNode; } void ParserImpl::ValidateTsFunctionOverloadParams(const ArenaVector ¶ms) { for (auto *it : params) { if (it->IsAssignmentPattern()) { ThrowSyntaxError( "A parameter initializer is only allowed in a function " "or constructor implementation.", it->Start()); } } } ir::SpreadElement *ParserImpl::ParseSpreadElement(ExpressionParseFlags flags) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD); lexer::SourcePosition startLocation = lexer_->GetToken().Start(); bool inPattern = (flags & ExpressionParseFlags::MUST_BE_PATTERN); lexer_->NextToken(); ir::Expression *argument {}; if (inPattern) { argument = ParsePatternElement(ExpressionParseFlags::IN_REST); if ((flags & ExpressionParseFlags::OBJECT_PATTERN) && !argument->IsIdentifier()) { ThrowSyntaxError("RestParameter must be followed by an identifier in declaration contexts"); } } else { argument = ParseExpression(flags); } ir::Expression *typeAnnotation = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { lexer_->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; typeAnnotation = ParseTsTypeAnnotation(&options); } if (inPattern && argument->IsAssignmentExpression()) { ThrowSyntaxError("RestParameter does not support an initializer"); } lexer::SourcePosition endLoc = typeAnnotation ? typeAnnotation->End() : argument->End(); auto nodeType = inPattern ? ir::AstNodeType::REST_ELEMENT : ir::AstNodeType::SPREAD_ELEMENT; auto *spreadElementNode = AllocNode(nodeType, argument); spreadElementNode->SetRange({startLocation, endLoc}); if (typeAnnotation) { spreadElementNode->SetTsTypeAnnotation(typeAnnotation); } return spreadElementNode; } ir::TSParameterProperty *ParserImpl::CreateTsParameterProperty(ir::Expression *parameter, ir::ModifierFlags modifiers) { auto accessibility = ir::AccessibilityOption::NO_OPTS; bool readonly = false; bool isOverride = false; bool isStatic = false; bool isExport = false; if (modifiers & ir::ModifierFlags::PRIVATE) { accessibility = ir::AccessibilityOption::PRIVATE; } else if ((modifiers & ir::ModifierFlags::PUBLIC)) { accessibility = ir::AccessibilityOption::PUBLIC; } else if (modifiers & ir::ModifierFlags::PROTECTED) { accessibility = ir::AccessibilityOption::PROTECTED; } if (modifiers & ir::ModifierFlags::READONLY) { readonly = true; } if (modifiers & ir::ModifierFlags::OVERRIDE) { isOverride = true; } if (modifiers & ir::ModifierFlags::STATIC) { isStatic = true; } return AllocNode(accessibility, parameter, readonly, isOverride, isStatic, isExport); } ir::Expression *ParserImpl::ParseFunctionParameter(bool isDeclare) { if (Extension() == ScriptExtension::TS && lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_THIS) { lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); } lexer::SourcePosition parameterStart = lexer_->GetToken().Start(); ir::ModifierFlags modifiers = ParseModifiers(); if (!(context_.Status() & ParserStatus::CONSTRUCTOR_FUNCTION) && modifiers != ir::ModifierFlags::NONE) { ThrowSyntaxError("A parameter property is only allowed in a constructor implementation.", parameterStart); } lexer::TokenType tokenType = lexer_->GetToken().Type(); if (tokenType == lexer::TokenType::LITERAL_IDENT && (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_ARGUMENTS || lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_EVAL)) { ThrowSyntaxError( "'eval' or 'arguments' can't be defined or assigned to " "in strict mode code", lexer_->GetToken().Start()); } ir::Expression *functionParameter = ParsePatternElement(ExpressionParseFlags::NO_OPTS, true, isDeclare); if (modifiers != ir::ModifierFlags::NONE && functionParameter->IsRestElement()) { ThrowSyntaxError("A parameter property cannot be declared using a rest parameter.", parameterStart); } if (modifiers != ir::ModifierFlags::NONE && (functionParameter->IsArrayPattern() || functionParameter->IsObjectPattern() || (functionParameter->IsAssignmentPattern() && (functionParameter->AsAssignmentPattern()->Left()->IsArrayPattern() || functionParameter->AsAssignmentPattern()->Left()->IsObjectPattern())))) { ThrowSyntaxError("A parameter property may not be declared using a binding pattern.", parameterStart); } if (modifiers != ir::ModifierFlags::NONE) { functionParameter = CreateTsParameterProperty(functionParameter, modifiers); functionParameter->SetRange({parameterStart, functionParameter->AsTSParameterProperty()->Parameter()->End()}); } Binder()->AddParamDecl(functionParameter); return functionParameter; } void ParserImpl::ValidateLvalueAssignmentTarget(ir::Expression *node) const { switch (node->Type()) { case ir::AstNodeType::IDENTIFIER: { // Check the prevoius ident name if (node->AsIdentifier()->Name().Is("arguments")) { ThrowSyntaxError("Assigning to 'arguments' in strict mode is invalid"); } else if (node->AsIdentifier()->Name().Is("eval")) { ThrowSyntaxError("Assigning to 'eval' in strict mode is invalid"); } break; } case ir::AstNodeType::MEMBER_EXPRESSION: { break; } case ir::AstNodeType::TS_AS_EXPRESSION: { ValidateLvalueAssignmentTarget(node->AsTSAsExpression()->Expr()); break; } case ir::AstNodeType::TS_SATISFIES_EXPRESSION: { ValidateLvalueAssignmentTarget(node->AsTSSatisfiesExpression()->Expr()); break; } case ir::AstNodeType::TS_TYPE_ASSERTION: { ValidateLvalueAssignmentTarget(node->AsTSTypeAssertion()->GetExpression()); break; } case ir::AstNodeType::TS_NON_NULL_EXPRESSION: { ValidateLvalueAssignmentTarget(node->AsTSNonNullExpression()->Expr()); break; } default: { ThrowSyntaxError("Invalid left-hand side in assignment expression"); } } } void ParserImpl::ValidateAssignmentTarget(ExpressionParseFlags flags, ir::Expression *node) { switch (node->Type()) { case ir::AstNodeType::ARRAY_PATTERN: case ir::AstNodeType::OBJECT_PATTERN: { break; } case ir::AstNodeType::ARRAY_EXPRESSION: case ir::AstNodeType::OBJECT_EXPRESSION: { if (flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) { return; } [[fallthrough]]; } default: { return ValidateLvalueAssignmentTarget(node); } } } void ParserImpl::ValidateArrowParameterBindings(const ir::Expression *node) { switch (node->Type()) { case ir::AstNodeType::IDENTIFIER: { const util::StringView &identifier = node->AsIdentifier()->Name(); if (context_.IsAsync() && identifier.Is("await")) { ThrowSyntaxError("'await' in formal parameter is invalid.", node->Start()); } break; } case ir::AstNodeType::OMITTED_EXPRESSION: { break; } case ir::AstNodeType::REST_ELEMENT: { ValidateArrowParameterBindings(node->AsRestElement()->Argument()); break; } case ir::AstNodeType::PROPERTY: { break; } case ir::AstNodeType::OBJECT_PATTERN: { const auto &props = node->AsObjectPattern()->Properties(); for (auto *it : props) { ValidateArrowParameterBindings(it); } break; } case ir::AstNodeType::ARRAY_PATTERN: { const auto &elements = node->AsArrayPattern()->Elements(); for (auto *it : elements) { ValidateArrowParameterBindings(it); } break; } case ir::AstNodeType::ASSIGNMENT_PATTERN: { ValidateArrowParameterBindings(node->AsAssignmentPattern()->Left()); break; } default: { ThrowSyntaxError("Unexpected ArrowParameter element"); } } } bool ParserImpl::CurrentTokenIsModifier(char32_t nextCp) const { return (Extension() == ScriptExtension::TS && (nextCp != LEX_CHAR_EQUALS || nextCp != LEX_CHAR_SEMICOLON || nextCp != LEX_CHAR_LEFT_PAREN)); } void ParserImpl::ThrowParameterModifierError(ir::ModifierFlags status) const { ThrowSyntaxError( {"'", (status & ir::ModifierFlags::STATIC) ? "static" : ((status & ir::ModifierFlags::ASYNC) ? "async" : "declare"), "' modifier cannot appear on a parameter."}, lexer_->GetToken().Start()); } void ParserImpl::ThrowSyntaxError(std::string_view errorMessage) const { ThrowSyntaxError(errorMessage, lexer_->GetToken().Start()); } void ParserImpl::ThrowSyntaxError(std::initializer_list list) const { ThrowSyntaxError(list, lexer_->GetToken().Start()); } void ParserImpl::ThrowSyntaxError(std::initializer_list list, const lexer::SourcePosition &pos) const { std::stringstream ss; for (const auto &it : list) { ss << it; } std::string err = ss.str(); ThrowSyntaxError(std::string_view {err}, pos); } void ParserImpl::ThrowSyntaxError(std::string_view errorMessage, const lexer::SourcePosition &pos) const { lexer::LineIndex index(program_.SourceCode()); lexer::SourceLocation loc = index.GetLocation(pos); throw Error {ErrorType::SYNTAX, errorMessage, loc.line, loc.col}; } ScriptExtension ParserImpl::Extension() const { return program_.Extension(); } parser::SourceTextModuleRecord *ParserImpl::GetSourceTextModuleRecord() { return Binder()->Program()->ModuleRecord(); } parser::SourceTextModuleRecord *ParserImpl::GetSourceTextTypeModuleRecord() { return Binder()->Program()->TypeModuleRecord(); } void ParserImpl::AddPatchFixHelper(util::PatchFix *patchFixHelper) { program_.AddPatchFixHelper(patchFixHelper); } bool ParserImpl::IsDtsFile() const { return program_.IsDtsFile(); } void ParserImpl::CheckStrictReservedWord() const { if (Extension() == ScriptExtension::JS) { if (lexer_->GetToken().IsJsStrictReservedWord()) { ThrowSyntaxError("Unexpected reserved word in strict mode."); } } else { if (lexer_->GetToken().KeywordType() >= lexer::TokenType::KEYW_ARGUMENTS) { ThrowSyntaxError("Unexpected reserved word in strict mode."); } } if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_AWAIT && context_.IsModule() && !context_.IsTsModule()) { ThrowSyntaxError("Unexpected reserved word"); } } template ir::Expression* ParserImpl::DoOutsideOfDisallowConditinalTypesContext(Function func, Args &&... args) { ParserStatus status = ParserStatus::DISALLOW_CONDITIONAL_TYPES; auto inDisallowConditionalTypesContext = InDisallowConditionalTypesContext(); ir::Expression *result = nullptr; if (inDisallowConditionalTypesContext) { RemoveFlagToStatus(status); result = (this->*func)(std::forward(args)...); AddFlagToStatus(status); return result; } result = (this->*func)(std::forward(args)...); return result; } template ir::Expression* ParserImpl::DoInsideOfDisallowConditinalTypesContext(Function func, Args &&... args) { ParserStatus status = ParserStatus::DISALLOW_CONDITIONAL_TYPES; auto inAllowConditionalTypesContext = status & ~context_.Status(); ir::Expression *result = nullptr; if (inAllowConditionalTypesContext) { AddFlagToStatus(status); result = (this->*func)(std::forward(args)...); RemoveFlagToStatus(status); return result; } result = (this->*func)(std::forward(args)...); return result; } bool ParserImpl::InDisallowConditionalTypesContext() { return InContext(ParserStatus::DISALLOW_CONDITIONAL_TYPES); } bool ParserImpl::InContext(ParserStatus status) { return context_.Status() & status; } void ParserImpl::AddFlagToStatus(ParserStatus status) { context_.Status() |= status; } void ParserImpl::RemoveFlagToStatus(ParserStatus status) { context_.Status() &= ~status; } void ParserImpl::RecursiveDepthException() { auto pos = lexer_->GetToken().Start(); lexer::LineIndex index(program_.SourceCode()); lexer::SourceLocation loc = index.GetLocation(pos); throw Error(ErrorType::GENERIC, "Too many nested expressions/statemnets/declarations", loc.line, loc.col); } } // namespace panda::es2panda::parser