diff --git a/ets2panda/ir/expressions/assignmentExpression.cpp b/ets2panda/ir/expressions/assignmentExpression.cpp index 0f02e9ab6011aed32a9cd2fa43b148d6634ba45c..2a17ccd0a9695e0c9ed6be5521fa4f4903e8338b 100644 --- a/ets2panda/ir/expressions/assignmentExpression.cpp +++ b/ets2panda/ir/expressions/assignmentExpression.cpp @@ -30,69 +30,65 @@ #include "checker/ets/typeRelationContext.h" namespace ark::es2panda::ir { -bool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern) -{ - bool convResult = true; +bool AssignmentExpression::ConvertibleToAssignmentPatternLeft(bool mustBePattern) +{ switch (left_->Type()) { case AstNodeType::ARRAY_EXPRESSION: { - convResult = left_->AsArrayExpression()->ConvertibleToArrayPattern(); - break; + return left_->AsArrayExpression()->ConvertibleToArrayPattern(); } case AstNodeType::SPREAD_ELEMENT: { - convResult = mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false); - break; + return mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false); } case AstNodeType::OBJECT_EXPRESSION: { - convResult = left_->AsObjectExpression()->ConvertibleToObjectPattern(); - break; + return left_->AsObjectExpression()->ConvertibleToObjectPattern(); } case AstNodeType::ASSIGNMENT_EXPRESSION: { - convResult = left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern); - break; + return left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern); } case AstNodeType::META_PROPERTY_EXPRESSION: case AstNodeType::CHAIN_EXPRESSION: { - convResult = false; - break; + return false; } default: { - break; + return true; } } +} - if (mustBePattern) { - SetType(AstNodeType::ASSIGNMENT_PATTERN); - } - - if (!right_->IsAssignmentExpression()) { - return convResult; - } - +bool AssignmentExpression::ConvertibleToAssignmentPatternRight() +{ switch (right_->Type()) { case AstNodeType::ARRAY_EXPRESSION: { - convResult = right_->AsArrayExpression()->ConvertibleToArrayPattern(); - break; + return right_->AsArrayExpression()->ConvertibleToArrayPattern(); } case AstNodeType::CHAIN_EXPRESSION: case AstNodeType::SPREAD_ELEMENT: { - convResult = false; - break; + return false; } case AstNodeType::OBJECT_EXPRESSION: { - convResult = right_->AsObjectExpression()->ConvertibleToObjectPattern(); - break; + return right_->AsObjectExpression()->ConvertibleToObjectPattern(); } case AstNodeType::ASSIGNMENT_EXPRESSION: { - convResult = right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false); - break; + return right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false); } default: { - break; + return true; } } +} - return convResult; +bool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern) +{ + bool convResult = ConvertibleToAssignmentPatternLeft(mustBePattern); + if (mustBePattern) { + SetType(AstNodeType::ASSIGNMENT_PATTERN); + } + + if (!right_->IsAssignmentExpression()) { + return convResult; + } + return ConvertibleToAssignmentPatternRight(); } void AssignmentExpression::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) diff --git a/ets2panda/ir/expressions/assignmentExpression.h b/ets2panda/ir/expressions/assignmentExpression.h index c455e4627622e0f62e3152107d8f832d9f5cdb53..83c56cf4b5e081ba6361dd1f39d90d1b93d20f05 100644 --- a/ets2panda/ir/expressions/assignmentExpression.h +++ b/ets2panda/ir/expressions/assignmentExpression.h @@ -133,6 +133,8 @@ public: [[nodiscard]] AssignmentExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override; + [[nodiscard]] bool ConvertibleToAssignmentPatternLeft(bool mustBePattern); + [[nodiscard]] bool ConvertibleToAssignmentPatternRight(); [[nodiscard]] bool ConvertibleToAssignmentPattern(bool mustBePattern = true); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; diff --git a/ets2panda/parser/ASparser.cpp b/ets2panda/parser/ASparser.cpp index 92b5dd2b26385a18e30fbfbf4a648bac089be65d..5a083c11d7b68d0afc1b5f765d989d07c0b3e87f 100644 --- a/ets2panda/parser/ASparser.cpp +++ b/ets2panda/parser/ASparser.cpp @@ -196,6 +196,53 @@ void ASParser::ParseOptionalFunctionParameter(ir::AnnotatedExpression *returnNod } } +ParserStatus ASParser::ValidateArrowExprIdentifier(ir::Expression *expr, bool *seenOptional) +{ + const util::StringView &identifier = expr->AsIdentifier()->Name(); + bool isOptional = expr->AsIdentifier()->IsOptional(); + if ((*seenOptional) != isOptional) { + ThrowSyntaxError("A required parameter cannot follow an optional parameter.", expr->Start()); + } + + (*seenOptional) |= isOptional; + + if (expr->AsIdentifier()->TypeAnnotation() == nullptr) { + ThrowSyntaxError("':' expected", expr->End()); + } + + if (identifier.Is("arguments")) { + ThrowSyntaxError("Binding 'arguments' in strict mode is invalid"); + } else if (identifier.Is("eval")) { + ThrowSyntaxError("Binding 'eval' in strict mode is invalid"); + } + + ValidateArrowParameterBindings(expr); + return ParserStatus::NO_OPTS; +} + +ParserStatus ASParser::ValidateArrowAssignmentExpr(ir::Expression *expr) +{ + auto *assignmentExpr = expr->AsAssignmentExpression(); + if (assignmentExpr->Right()->IsYieldExpression()) { + ThrowSyntaxError("yield is not allowed in arrow function parameters"); + } + + if (assignmentExpr->Right()->IsAwaitExpression()) { + ThrowSyntaxError("await is not allowed in arrow function parameters"); + } + + if (!assignmentExpr->ConvertibleToAssignmentPattern()) { + ThrowSyntaxError("Invalid destructuring assignment target"); + } + + if (assignmentExpr->Left()->IsIdentifier() && assignmentExpr->Left()->AsIdentifier()->IsOptional()) { + ThrowSyntaxError("Parameter cannot have question mark and initializer.", expr->Start()); + } + + ValidateArrowParameterBindings(expr); + return ParserStatus::HAS_COMPLEX_PARAM; +} + ParserStatus ASParser::ValidateArrowParameter(ir::Expression *expr, bool *seenOptional) { switch (expr->Type()) { @@ -215,47 +262,10 @@ ParserStatus ASParser::ValidateArrowParameter(ir::Expression *expr, bool *seenOp return ParserStatus::HAS_COMPLEX_PARAM; } case ir::AstNodeType::IDENTIFIER: { - const util::StringView &identifier = expr->AsIdentifier()->Name(); - bool isOptional = expr->AsIdentifier()->IsOptional(); - if ((*seenOptional) != isOptional) { - ThrowSyntaxError("A required parameter cannot follow an optional parameter.", expr->Start()); - } - - (*seenOptional) |= isOptional; - - if (expr->AsIdentifier()->TypeAnnotation() == nullptr) { - ThrowSyntaxError("':' expected", expr->End()); - } - - if (identifier.Is("arguments")) { - ThrowSyntaxError("Binding 'arguments' in strict mode is invalid"); - } else if (identifier.Is("eval")) { - ThrowSyntaxError("Binding 'eval' in strict mode is invalid"); - } - - ValidateArrowParameterBindings(expr); - return ParserStatus::NO_OPTS; + return ValidateArrowExprIdentifier(expr, seenOptional); } case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { - auto *assignmentExpr = expr->AsAssignmentExpression(); - if (assignmentExpr->Right()->IsYieldExpression()) { - ThrowSyntaxError("yield is not allowed in arrow function parameters"); - } - - if (assignmentExpr->Right()->IsAwaitExpression()) { - ThrowSyntaxError("await is not allowed in arrow function parameters"); - } - - if (!assignmentExpr->ConvertibleToAssignmentPattern()) { - ThrowSyntaxError("Invalid destructuring assignment target"); - } - - if (assignmentExpr->Left()->IsIdentifier() && assignmentExpr->Left()->AsIdentifier()->IsOptional()) { - ThrowSyntaxError("Parameter cannot have question mark and initializer.", expr->Start()); - } - - ValidateArrowParameterBindings(expr); - return ParserStatus::HAS_COMPLEX_PARAM; + return ValidateArrowAssignmentExpr(expr); } default: { break; @@ -318,7 +328,7 @@ ArrowFunctionDescriptor ASParser::ConvertToArrowParameter(ir::Expression *expr, } // NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ASParser::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault) +std::tuple ASParser::ParsePatternElementToken(ExpressionParseFlags flags) { ir::AnnotatedExpression *returnNode = nullptr; bool isOptional = false; @@ -338,12 +348,13 @@ ir::Expression *ASParser::ParsePatternElement(ExpressionParseFlags flags, bool a returnNode->SetRange(Lexer()->GetToken().Loc()); Lexer()->NextToken(); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - isOptional = true; + bool questionMark = Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK; + if (questionMark && ((flags & ExpressionParseFlags::IN_REST) != 0)) { + ThrowSyntaxError("A rest parameter cannot be optional"); + } - if ((flags & ExpressionParseFlags::IN_REST) != 0) { - ThrowSyntaxError("A rest parameter cannot be optional"); - } + if (questionMark) { + isOptional = true; returnNode->AsIdentifier()->SetOptional(true); Lexer()->NextToken(); @@ -363,6 +374,14 @@ ir::Expression *ASParser::ParsePatternElement(ExpressionParseFlags flags, bool a ThrowSyntaxError("Identifier expected"); } } + return {returnNode, isOptional}; +} + +ir::Expression *ASParser::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault) +{ + ir::AnnotatedExpression *returnNode = nullptr; + bool isOptional = false; + std::tie(returnNode, isOptional) = ParsePatternElementToken(flags); if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { return returnNode; @@ -550,101 +569,74 @@ ir::TypeNode *ASParser::ParseParenthesizedOrFunctionType(bool throwError) return type; } -ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options) +ir::TypeNode *ASParser::ParseTypeAnnotationLiteralIdentHelper(ir::TypeNode *type, TypeAnnotationParsingOptions *options) { - ir::TypeNode *type = nullptr; + auto *typeName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + typeName->SetRange(Lexer()->GetToken().Loc()); + type = AllocNode(typeName); + type->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); - bool throwError = (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); + ir::NamedType *current = type->AsNamedType(); + while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + ThrowSyntaxError("Identifier expected"); + } + + typeName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + typeName->SetRange(Lexer()->GetToken().Loc()); + auto *next = AllocNode(typeName); + current->SetRange(Lexer()->GetToken().Loc()); + current->SetNext(next); + current = next; + Lexer()->NextToken(); + } + + ir::TSTypeParameterInstantiation *typeParams = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { + typeParams = ParseTypeParameterInstantiation(options); + if (typeParams == nullptr) { + return nullptr; + } + + type->AsNamedType()->SetTypeParams(typeParams); + } + return type; +} + +ir::TypeNode *ASParser::ParseTypeAnnotationTokens(ir::TypeNode *type, bool throwError, + TypeAnnotationParsingOptions *options) +{ + util::StringView name = ""; switch (Lexer()->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - type = ParseParenthesizedOrFunctionType(throwError); - if (type == nullptr) { - return nullptr; - } - - break; + return ParseParenthesizedOrFunctionType(throwError); } case lexer::TokenType::KEYW_VOID: { - util::StringView name = "void"; - auto *typeName = AllocNode(name, Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); + name = "void"; break; } case lexer::TokenType::KEYW_THIS: { - util::StringView name = "this"; - auto *typeName = AllocNode(name, Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); + name = "this"; break; } case lexer::TokenType::LITERAL_FALSE: case lexer::TokenType::LITERAL_TRUE: { - util::StringView name = "bool"; - auto *typeName = AllocNode(name, Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); + name = "bool"; break; } case lexer::TokenType::LITERAL_NULL: { - util::StringView name = "null"; - auto *typeName = AllocNode(name, Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); + name = "null"; break; } case lexer::TokenType::LITERAL_STRING: { - util::StringView name = "string"; - auto *typeName = AllocNode(name, Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); + name = "string"; break; } case lexer::TokenType::LITERAL_IDENT: { - auto *typeName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - type = AllocNode(typeName); - type->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - - ir::NamedType *current = type->AsNamedType(); - while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { - ThrowSyntaxError("Identifier expected"); - } - - typeName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - typeName->SetRange(Lexer()->GetToken().Loc()); - auto *next = AllocNode(typeName); - current->SetRange(Lexer()->GetToken().Loc()); - current->SetNext(next); - current = next; - Lexer()->NextToken(); - } - - ir::TSTypeParameterInstantiation *typeParams = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { - typeParams = ParseTypeParameterInstantiation(options); - if (typeParams == nullptr) { - return nullptr; - } - - type->AsNamedType()->SetTypeParams(typeParams); - } - - break; + return ParseTypeAnnotationLiteralIdentHelper(type, options); } default: { if (throwError) { @@ -655,8 +647,16 @@ ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *option } } - bool isNullable = false; + auto *typeName = AllocNode(name, Allocator()); + typeName->SetRange(Lexer()->GetToken().Loc()); + type = AllocNode(typeName); + type->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + return type; +} +ir::TypeNode *ASParser::ParseTypeAnnotationTokensBitwiseOr(ir::TypeNode *type, bool throwError, bool isNullable) +{ while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { Lexer()->NextToken(); @@ -681,7 +681,11 @@ ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *option type->SetEnd(Lexer()->GetToken().End()); Lexer()->NextToken(); } + return type; +} +ir::TypeNode *ASParser::ParseTypeAnnotationTokenLeftSquareBracket(ir::TypeNode *type, bool throwError, bool isNullable) +{ while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { Lexer()->NextToken(); @@ -700,11 +704,11 @@ ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *option if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { Lexer()->NextToken(); - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NULL) { - if (throwError) { - ThrowSyntaxError("'null' expected"); - } - + bool isLiteralNull = Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NULL; + if (isLiteralNull && throwError) { + ThrowSyntaxError("'null' expected"); + } + if (isLiteralNull) { return nullptr; } @@ -731,7 +735,24 @@ ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *option break; } } + return type; +} + +ir::TypeNode *ASParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options) +{ + bool throwError = (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); + ir::TypeNode *type = ParseTypeAnnotationTokens(nullptr, throwError, options); + if (type == nullptr) { + return nullptr; + } + + bool isNullable = false; + type = ParseTypeAnnotationTokensBitwiseOr(type, throwError, isNullable); + if (type == nullptr) { + return nullptr; + } + type = ParseTypeAnnotationTokenLeftSquareBracket(type, throwError, isNullable); return type; } diff --git a/ets2panda/parser/ASparser.h b/ets2panda/parser/ASparser.h index 09bf72448479d39fb33eced1d5fdc5fb07809487..029c5fc98ccb63013193406a69f299db2c981d17 100644 --- a/ets2panda/parser/ASparser.h +++ b/ets2panda/parser/ASparser.h @@ -36,12 +36,18 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseStatement(StatementParsingFlags flags = StatementParsingFlags::NONE) override; // NOLINTNEXTLINE(google-default-arguments) + std::tuple ParsePatternElementToken(ExpressionParseFlags flags); + // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ParsePatternElement(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS, bool allowDefault = true) override; // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ParsePropertyDefinition( [[maybe_unused]] ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS) override; bool CurrentIsBasicType() override; + ir::TypeNode *ParseTypeAnnotationLiteralIdentHelper(ir::TypeNode *type, TypeAnnotationParsingOptions *options); + ir::TypeNode *ParseTypeAnnotationTokens(ir::TypeNode *type, bool throwError, TypeAnnotationParsingOptions *options); + ir::TypeNode *ParseTypeAnnotationTokensBitwiseOr(ir::TypeNode *type, bool throwError, bool isNullable); + ir::TypeNode *ParseTypeAnnotationTokenLeftSquareBracket(ir::TypeNode *type, bool throwError, bool isNullable); ir::TypeNode *ParseTypeAnnotation(TypeAnnotationParsingOptions *options) override; ir::ArrowFunctionExpression *ParsePotentialArrowExpression(ir::Expression **returnExpression, const lexer::SourcePosition &startLoc) override; @@ -94,6 +100,8 @@ private: void ParseOptionalClassElement(ClassElementDescriptor *desc) override; void ValidateIndexSignatureTypeAnnotation(ir::TypeNode *typeAnnotation) override; ArrowFunctionDescriptor ConvertToArrowParameter(ir::Expression *expr, bool isAsync) override; + ParserStatus ValidateArrowExprIdentifier(ir::Expression *expr, bool *seenOptional); + ParserStatus ValidateArrowAssignmentExpr(ir::Expression *expr); ParserStatus ValidateArrowParameter(ir::Expression *expr, bool *seenOptional) override; void ThrowIllegalBreakError() override; void ThrowIllegalContinueError() override;