diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParser.scala index 4b21b5a33..c0844a7b4 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParser.scala @@ -42,7 +42,7 @@ private object AnnotationParser { SpaceParser.parseOrFail.? ~ IdentifierParser.parse ~ SpaceParser.parseOrFail.? ~ - TupleParser.parseOrFail.? ~ + ParameterParser.parseOrFail.? ~ SpaceParser.parseOrFail.? ~ Index } map { diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParser.scala index fe8d602eb..290266b6a 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParser.scala @@ -10,7 +10,7 @@ private case object AssignmentParser { def parseOrFail[Unknown: P]: P[SoftAST.Assignment] = P { Index ~ - ExpressionParser.parseOrFailSelective(parseInfix = true, parseMethodCall = true, parseAssignment = false) ~ + leftExpression ~ SpaceParser.parseOrFail.? ~ TokenParser.parseOrFail(Token.Equal) ~ SpaceParser.parseOrFail.? ~ @@ -28,4 +28,20 @@ private case object AssignmentParser { ) } + private def leftExpression[Unknown: P]: P[SoftAST.ExpressionAST] = + P { + InfixCallParser.parseOrFail | + MethodCallParser.parseOrFail | + BlockParser.parseOrFail | + VariableDeclarationParser.parseOrFail | + MutableBindingParser.parseOrFail | + ReferenceCallParser.parseOrFail | + AnnotationParser.parseOrFail | + ParameterParser.parseOrFail | + NumberParser.parseOrFail | + BooleanParser.parseOrFail | + BStringParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BlockParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BlockParser.scala index 6e2b3b3db..32a3fde0c 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BlockParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BlockParser.scala @@ -23,7 +23,16 @@ import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} private object BlockParser { - def clause[Unknown: P](required: Boolean): P[SoftAST.BlockClause] = + def parse[Unknown: P]: P[SoftAST.BlockClause] = + parse(required = true) + + def parseOrFail[Unknown: P]: P[SoftAST.BlockClause] = + parse(required = false) + + def body[Unknown: P]: P[SoftAST.BlockBody] = + body() + + private def parse[Unknown: P](required: Boolean): P[SoftAST.BlockClause] = P { Index ~ TokenParser.parse(required, Token.OpenCurly) ~ @@ -44,9 +53,6 @@ private object BlockParser { ) } - def body[Unknown: P]: P[SoftAST.BlockBody] = - body() - private def body[Unknown: P](stop: Token*): P[SoftAST.BlockBody] = P { Index ~ @@ -80,7 +86,8 @@ private object BlockParser { private def part[Unknown: P](stop: Seq[Token]): P[SoftAST.BodyPartAST] = P { TemplateParser.parseOrFail | - DataTemplateParser.parseOrFail | + EventTemplateParser.parseOrFail | + StructTemplateParser.parseOrFail | FunctionParser.parseOrFail | ExpressionParser.parseOrFail | CommentParser.parseOrFail | diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BooleanParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BooleanParser.scala index eaaaada4b..f6d7de7ec 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BooleanParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BooleanParser.scala @@ -3,7 +3,7 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import fastparse._ import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -object BooleanParser { +private object BooleanParser { def parseOrFail[Unknown: P]: P[SoftAST.TokenExpression[Token.PrimitiveBoolean]] = P(boolean) map (SoftAST.TokenExpression(_)) diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CodeParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CodeParser.scala index 553ec4458..2dfb1434c 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CodeParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CodeParser.scala @@ -5,7 +5,7 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -object CodeParser { +private object CodeParser { def parseOrFail[Unknown: P, T <: Token](token: T): P[SoftAST.CodeToken[T]] = P(Index ~ token.lexeme ~ Index) map { diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/Demo.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/Demo.scala index c55a8c377..bbf105fb4 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/Demo.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/Demo.scala @@ -10,6 +10,9 @@ object Demo extends App { val ast = compiler.parseSoft { """ + |event Event(a: Type) + |struct Struct { a: Type } + | |Contract HelloWorld(type: SomeType, tuple: (A, B)) extends Class implements Trait { | | // This multiline comment diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/DataTemplateParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParser.scala similarity index 63% rename from compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/DataTemplateParser.scala rename to compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParser.scala index 98f161e58..9a07f16a0 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/DataTemplateParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParser.scala @@ -5,22 +5,22 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -private object DataTemplateParser { +private object EventTemplateParser { - def parseOrFail[Unknown: P]: P[SoftAST.DataTemplate] = + def parseOrFail[Unknown: P]: P[SoftAST.EventTemplate] = P { Index ~ - (TokenParser.parseOrFail(Token.Struct) | TokenParser.parseOrFail(Token.Enum) | TokenParser.parseOrFail(Token.Event)) ~ + TokenParser.parseOrFail(Token.Event) ~ SpaceParser.parse ~ IdentifierParser.parse ~ SpaceParser.parseOrFail.? ~ ParameterParser.parse ~ Index } map { - case (from, templateType, preIdentifierSpace, identifier, preParamSpace, params, to) => - SoftAST.DataTemplate( + case (from, eventToken, preIdentifierSpace, identifier, preParamSpace, params, to) => + SoftAST.EventTemplate( index = range(from, to), - dataType = templateType, + eventToken = eventToken, preIdentifierSpace = preIdentifierSpace, identifier = identifier, preParamSpace = preParamSpace, diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ExpressionParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ExpressionParser.scala index 5c46c3fa9..743330f0b 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ExpressionParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ExpressionParser.scala @@ -24,30 +24,9 @@ import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST private object ExpressionParser { def parse[Unknown: P]: P[SoftAST.ExpressionAST] = - parseSelective( - parseInfix = true, - parseMethodCall = true, - parseAssignment = true - ) - - def parseOrFail[Unknown: P]: P[SoftAST.ExpressionAST] = - parseOrFailSelective( - parseInfix = true, - parseMethodCall = true, - parseAssignment = true - ) - - def parseSelective[Unknown: P]( - parseInfix: Boolean, - parseMethodCall: Boolean, - parseAssignment: Boolean): P[SoftAST.ExpressionAST] = P { Index ~ - parseOrFailSelective( - parseInfix = parseInfix, - parseMethodCall = parseMethodCall, - parseAssignment = parseAssignment - ).? ~ + parseOrFail.? ~ Index } map { case (_, Some(expression), _) => @@ -57,48 +36,21 @@ private object ExpressionParser { SoftAST.ExpressionExpected(range(from, to)) } - def parseOrFailSelective[Unknown: P]( - parseInfix: Boolean, - parseMethodCall: Boolean, - parseAssignment: Boolean): P[SoftAST.ExpressionAST] = { - def infixOrFail() = - if (parseInfix) - InfixCallParser.parseOrFail - else - Fail(s"${InfixCallParser.productPrefix} ignored") - - def methodCallOrFail() = - if (parseMethodCall) - MethodCallParser.parseOrFail - else - Fail(s"${MethodCallParser.productPrefix} ignored") - - def assignmentOrFail() = - if (parseAssignment) - AssignmentParser.parseOrFail - else - Fail(s"${AssignmentParser.productPrefix} ignored") - - P { - assignmentOrFail() | - infixOrFail() | - methodCallOrFail() | - common - } - } - - private def common[Unknown: P]: P[SoftAST.ExpressionAST] = + def parseOrFail[Unknown: P]: P[SoftAST.ExpressionAST] = P { - ReturnStatementParser.parseOrFail | + TypeAssignmentParser.parseOrFail | + AssignmentParser.parseOrFail | + InfixCallParser.parseOrFail | + MethodCallParser.parseOrFail | + BlockParser.parseOrFail | + ReturnStatementParser.parseOrFail | ForLoopParser.parseOrFail | WhileLoopParser.parseOrFail | VariableDeclarationParser.parseOrFail | MutableBindingParser.parseOrFail | - TypeAssignmentParser.parseOrFail | - BlockParser.clause(required = false) | ReferenceCallParser.parseOrFail | AnnotationParser.parseOrFail | - TupleParser.parseOrFail | + ParameterParser.parseOrFail | NumberParser.parseOrFail | BooleanParser.parseOrFail | BStringParser.parseOrFail | diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ForLoopParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ForLoopParser.scala index 2ca74a1dc..19416e1a8 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ForLoopParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ForLoopParser.scala @@ -26,7 +26,7 @@ private object ForLoopParser { SpaceParser.parseOrFail.? ~ TokenParser.parse(Token.CloseParen) ~ SpaceParser.parseOrFail.? ~ - BlockParser.clause(required = true) ~ + BlockParser.parse ~ Index } map { case (from, diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionParser.scala index 848c13f92..240e4b4ce 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionParser.scala @@ -18,7 +18,7 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import fastparse._ import fastparse.NoWhitespace.noWhitespaceImplicit -import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range +import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.{point, range} import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} private object FunctionParser { @@ -39,7 +39,7 @@ private object FunctionParser { SpaceParser.parse ~ signature ~ SpaceParser.parseOrFail.? ~ - BlockParser.clause(required = false).? ~ + BlockParser.parseOrFail.? ~ Index } map { case (from, annotation, postAnnotationSpace, pub, fnDeceleration, headSpace, signature, tailSpace, block, to) => @@ -92,7 +92,9 @@ private object FunctionParser { private def returnSignature[Unknown: P]: P[SoftAST.FunctionReturnAST] = P { Index ~ - (TokenParser.parse(Token.ForwardArrow) ~ SpaceParser.parseOrFail.? ~ TypeParser.parse).? ~ + (TokenParser.parse(Token.ForwardArrow) ~ + SpaceParser.parseOrFail.? ~ + returnExpression).? ~ Index } map { case (from, Some((forwardArrow, space, tpe)), to) => @@ -107,4 +109,20 @@ private object FunctionParser { SoftAST.FunctionReturnExpected(range(from, to)) } + private def returnExpression[Unknown: P]: P[SoftAST.ExpressionAST] = + P(Index ~ returnExpressionParserOrFail.?) map { + case (_, Some(expression)) => + expression + + case (from, None) => + SoftAST.ExpressionExpected(point(from)) + } + + private def returnExpressionParserOrFail[Unknown: P]: P[SoftAST.ExpressionAST] = + P { + ParameterParser.parseOrFail | + NumberParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParser.scala similarity index 59% rename from compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleParser.scala rename to compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParser.scala index 23c108c98..99358dc1e 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParser.scala @@ -21,16 +21,41 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.{point, range} import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -private object TupleParser { +private object GroupParser { - def parseOrFail[Unknown: P]: P[SoftAST.Tuple] = - P(tuple(required = false)) + def parse[Unknown: P, O <: Token, C <: Token]( + open: O, + close: C): P[SoftAST.Group[O, C]] = + P { + group( + required = true, + open = open, + close = close + ) + } - def parse[Unknown: P]: P[SoftAST.Tuple] = - P(tuple(required = true)) + def parse[Unknown: P, O <: Token, C <: Token]( + required: Boolean, + open: O, + close: C): P[SoftAST.Group[O, C]] = + P { + group( + required, + open = open, + close = close + ) + } - def parse[Unknown: P](required: Boolean): P[SoftAST.Tuple] = - P(tuple(required)) + def parseOrFail[Unknown: P, O <: Token, C <: Token]( + open: O, + close: C): P[SoftAST.Group[O, C]] = + P { + group( + required = false, + open = open, + close = close + ) + } /** * Parses a sequence of arguments enclosed within parentheses. @@ -38,18 +63,21 @@ private object TupleParser { * Syntax: (arg1, arg2, (arg3, arg4), arg5) * * @param required Determines if the parser should fail when the opening parenthesis is missing. - * @return An instance of [[SoftAST.Tuple]]. + * @return An instance of [[SoftAST.Group]]. */ - private def tuple[Unknown: P](required: Boolean): P[SoftAST.Tuple] = + private def group[Unknown: P, O <: Token, C <: Token]( + required: Boolean, + open: O, + close: C): P[SoftAST.Group[O, C]] = P { Index ~ - TokenParser.parse(required, Token.OpenParen) ~ + TokenParser.parse(required, open) ~ SpaceParser.parseOrFail.? ~ Index ~ - ExpressionParser.parseOrFail.? ~ + expression(open, close).? ~ SpaceParser.parseOrFail.? ~ - tailParams.rep ~ - TokenParser.parse(Token.CloseParen) ~ + tail(open, close).rep ~ + TokenParser.parse(close) ~ Index } map { case (from, openParen, preHeadSpace, headParamIndex, headExpression, postHeadSpace, tailParams, closeParen, to) => @@ -61,14 +89,14 @@ private object TupleParser { else headExpression - SoftAST.Tuple( + SoftAST.Group( index = range(from, to), - openParen = openParen, + openToken = openParen, preHeadExpressionSpace = preHeadSpace, headExpression = headExpressionAdjusted, postHeadExpressionSpace = postHeadSpace, tailExpressions = tailParams, - closeParen = closeParen + closeToken = closeParen ) } @@ -78,19 +106,21 @@ private object TupleParser { * * Syntax: (arg1>>, arg2, (arg3, arg4), arg5<<) * - * @return An instance of [[SoftAST.TupleTail]]. + * @return An instance of [[SoftAST.GroupTail]]. */ - private def tailParams[Unknown: P]: P[SoftAST.TupleTail] = + private def tail[Unknown: P, O <: Token, C <: Token]( + open: O, + close: C): P[SoftAST.GroupTail] = P { Index ~ TokenParser.parseOrFail(Token.Comma) ~ SpaceParser.parseOrFail.? ~ - ExpressionParser.parse ~ + expression(open, close) ~ SpaceParser.parseOrFail.? ~ Index } map { case (from, comma, preParamNameSpace, argumentName, postParamNameSpace, to) => - SoftAST.TupleTail( + SoftAST.GroupTail( index = range(from, to), comma = comma, preExpressionSpace = preParamNameSpace, @@ -99,4 +129,21 @@ private object TupleParser { ) } + private def expression[Unknown: P, O <: Token, C <: Token]( + open: O, + close: C): P[SoftAST.ExpressionAST] = + P { + GroupParser.parseOrFail(open, close) | + TypeAssignmentParser.parseOrFail | + AssignmentParser.parseOrFail | + InfixCallParser.parseOrFail | + MethodCallParser.parseOrFail | + MutableBindingParser.parseOrFail | + ReferenceCallParser.parseOrFail | + NumberParser.parseOrFail | + BooleanParser.parseOrFail | + BStringParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParser.scala index 99def2be8..a4840b65d 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParser.scala @@ -5,7 +5,7 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra._ import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -object IdentifierParser { +private object IdentifierParser { def parse[Unknown: P](required: Boolean): P[SoftAST.IdentifierAST] = if (required) @@ -58,7 +58,7 @@ object IdentifierParser { private def isDevDefinedName[Unknown: P]: P[Unit] = CharsWhile { char => - char.isLetterOrDigit || Token.Underscore.lexeme.contains(char) + char.isLetterOrDigit || Token.Underscore.lexeme.contains(char) || Token.Exclamation.lexeme.contains(char) } } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/InfixCallParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/InfixCallParser.scala index 57fdfaaab..96e052c04 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/InfixCallParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/InfixCallParser.scala @@ -5,12 +5,12 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST -case object InfixCallParser { +private case object InfixCallParser { def parseOrFail[Unknown: P]: P[SoftAST.InfixExpression] = P { Index ~ - ExpressionParser.parseOrFailSelective(parseInfix = false, parseMethodCall = true, parseAssignment = false) ~ + leftExpression ~ SpaceParser.parseOrFail.? ~ TokenParser.InfixOperatorOrFail ~ SpaceParser.parseOrFail.? ~ @@ -28,4 +28,18 @@ case object InfixCallParser { ) } + private def leftExpression[Unknown: P]: P[SoftAST.ExpressionAST] = + P { + MethodCallParser.parseOrFail | + BlockParser.parseOrFail | + VariableDeclarationParser.parseOrFail | + MutableBindingParser.parseOrFail | + ReferenceCallParser.parseOrFail | + ParameterParser.parseOrFail | + NumberParser.parseOrFail | + BooleanParser.parseOrFail | + BStringParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MethodCallParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MethodCallParser.scala index fd72082ea..27ec46138 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MethodCallParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MethodCallParser.scala @@ -5,12 +5,12 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -case object MethodCallParser { +private case object MethodCallParser { def parseOrFail[Unknown: P]: P[SoftAST.MethodCall] = P { Index ~ - ExpressionParser.parseOrFailSelective(parseInfix = false, parseMethodCall = false, parseAssignment = false) ~ + leftExpression ~ SpaceParser.parseOrFail.? ~ dotCall.rep(1) ~ Index @@ -41,4 +41,16 @@ case object MethodCallParser { ) } + private def leftExpression[Unknown: P]: P[SoftAST.ExpressionAST] = + P { + VariableDeclarationParser.parseOrFail | + MutableBindingParser.parseOrFail | + ReferenceCallParser.parseOrFail | + ParameterParser.parseOrFail | + NumberParser.parseOrFail | + BooleanParser.parseOrFail | + BStringParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/NumberParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/NumberParser.scala index 2b9e7fb93..84bf5e99e 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/NumberParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/NumberParser.scala @@ -5,7 +5,7 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra._ import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -object NumberParser { +private object NumberParser { def parseOrFail[Unknown: P]: P[SoftAST.Number] = P { diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ParameterParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ParameterParser.scala index 36756c9b3..ad6355e30 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ParameterParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ParameterParser.scala @@ -17,14 +17,27 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import fastparse._ -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -private object ParameterParser { +private case object ParameterParser { - def parse[Unknown: P]: P[SoftAST.Tuple] = - TupleParser.parse + def parse[Unknown: P]: P[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] = + GroupParser.parse( + open = Token.OpenParen, + close = Token.CloseParen + ) - def parseOrFail[Unknown: P]: P[SoftAST.Tuple] = - TupleParser.parseOrFail + def parse[Unknown: P](required: Boolean): P[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] = + GroupParser.parse( + required = required, + open = Token.OpenParen, + close = Token.CloseParen + ) + + def parseOrFail[Unknown: P]: P[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] = + GroupParser.parseOrFail( + open = Token.OpenParen, + close = Token.CloseParen + ) } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ReferenceCallParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ReferenceCallParser.scala index 6bc9f1d90..9d36b3728 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ReferenceCallParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ReferenceCallParser.scala @@ -14,7 +14,7 @@ private object ReferenceCallParser { parse(required = false) /** - * Parses a function or object call along with its arguments [[TupleParser]]. + * Parses a function or object call along with its arguments [[GroupParser]]. * * Syntax: reference(arg1, arg2, (arg3, arg4)) * @@ -27,7 +27,7 @@ private object ReferenceCallParser { Index ~ IdentifierParser.parse(required) ~ SpaceParser.parseOrFail.? ~ - TupleParser.parse(required) ~ + ParameterParser.parse(required) ~ Index } map { case (from, identifier, space, arguments, to) => diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/SpaceParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/SpaceParser.scala index 54f2a8057..5108531e8 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/SpaceParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/SpaceParser.scala @@ -21,7 +21,7 @@ import fastparse.NoWhitespace.noWhitespaceImplicit import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} -object SpaceParser { +private object SpaceParser { def parse[Unknown: P]: P[SoftAST.SpaceAST] = P(Index ~ parseOrFail.?) map { diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParser.scala new file mode 100644 index 000000000..aeedc450b --- /dev/null +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParser.scala @@ -0,0 +1,31 @@ +package org.alephium.ralph.lsp.access.compiler.parser.soft + +import fastparse._ +import fastparse.NoWhitespace.noWhitespaceImplicit +import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} + +private object StructTemplateParser { + + def parseOrFail[Unknown: P]: P[SoftAST.StructTemplate] = + P { + Index ~ + TokenParser.parseOrFail(Token.Struct) ~ + SpaceParser.parse ~ + IdentifierParser.parse ~ + SpaceParser.parseOrFail.? ~ + GroupParser.parse(Token.OpenCurly, Token.CloseCurly) ~ + Index + } map { + case (from, structToken, preIdentifierSpace, identifier, preParamSpace, params, to) => + SoftAST.StructTemplate( + index = range(from, to), + structToken = structToken, + preIdentifierSpace = preIdentifierSpace, + identifier = identifier, + preParamSpace = preParamSpace, + params = params + ) + } + +} diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateParser.scala index 34584e6fc..de0fd5deb 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateParser.scala @@ -17,7 +17,7 @@ private object TemplateParser { ParameterParser.parseOrFail.? ~ SpaceParser.parseOrFail.? ~ inheritance.rep ~ - BlockParser.clause(required = true) ~ + BlockParser.parse ~ Index } map { case (from, templateType, preIdentifierSpace, identifier, preParamSpace, params, postParamSpace, inheritance, block, to) => diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParser.scala index c1bd02039..82d688ed7 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParser.scala @@ -2,7 +2,7 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import fastparse._ import fastparse.NoWhitespace.noWhitespaceImplicit -import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.range +import org.alephium.ralph.lsp.access.compiler.message.SourceIndexExtra.{point, range} import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} private object TypeAssignmentParser { @@ -10,24 +10,37 @@ private object TypeAssignmentParser { def parseOrFail[Unknown: P]: P[SoftAST.TypeAssignment] = P { Index ~ - AssignmentAccessModifierParser.parseOrFail.rep ~ - IdentifierParser.parseOrFail ~ + leftExpression ~ SpaceParser.parseOrFail.? ~ TokenParser.parseOrFail(Token.Colon) ~ SpaceParser.parseOrFail.? ~ - TypeParser.parse ~ + ExpressionParser.parse ~ Index } map { - case (from, access, identifier, postIdentifierSpace, equalToken, postEqualSpace, expression, to) => + case (from, left, postIdentifierSpace, equalToken, postEqualSpace, right, to) => SoftAST.TypeAssignment( index = range(from, to), - modifiers = access, - name = identifier, + name = left, preColonSpace = postIdentifierSpace, colon = equalToken, postColonSpace = postEqualSpace, - tpe = expression + tpe = right ) } + private def leftExpression[Unknown: P]: P[SoftAST.ExpressionAST] = + P(Index ~ leftExpressionOrFail.?) map { + case (_, Some(expression)) => + expression + + case (from, None) => + SoftAST.ExpressionExpected(point(from)) + } + + private def leftExpressionOrFail[Unknown: P] = + P { + MutableBindingParser.parseOrFail | + IdentifierParser.parseOrFail + } + } diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParser.scala deleted file mode 100644 index 0a5f4328b..000000000 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParser.scala +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2024 The Alephium Authors -// This file is part of the alephium project. -// -// The library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the library. If not, see http://www.gnu.org/licenses/. - -package org.alephium.ralph.lsp.access.compiler.parser.soft - -import fastparse._ -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST - -private object TypeParser { - - def parse[Unknown: P]: P[SoftAST.TypeAST] = - P(TupleParser.parseOrFail | IdentifierParser.parse) - -} diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/WhileLoopParser.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/WhileLoopParser.scala index e000326e5..b7d75c8c4 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/WhileLoopParser.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/WhileLoopParser.scala @@ -18,7 +18,7 @@ private object WhileLoopParser { SpaceParser.parseOrFail.? ~ TokenParser.parse(Token.CloseParen) ~ SpaceParser.parseOrFail.? ~ - BlockParser.clause(required = true) ~ + BlockParser.parse ~ Index } map { case (from, whileToken, postWhileSpace, openParen, postOpenParenSpace, expression, postExpressionSpace, closeParen, postCloseParenSpace, block, to) => diff --git a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/SoftAST.scala b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/SoftAST.scala index 3d53aa0cc..abd22ea39 100644 --- a/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/SoftAST.scala +++ b/compiler-access/src/main/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/SoftAST.scala @@ -98,7 +98,14 @@ object SoftAST { } - abstract class ErrorAST(val message: String) extends SoftAST + abstract class ErrorAST(val message: String) extends SoftAST { + + // Also display the error message in the Tree representation + final override def toStringPretty(): String = + s"""${this.getClass.getSimpleName}("$message"): ${this.index}""" + + } + abstract class ExpectedErrorAST(element: String) extends ErrorAST(s"$element expected") abstract class TokenExpectedErrorAST(token: Token) extends ExpectedErrorAST(s"'${token.lexeme}'") @@ -151,19 +158,28 @@ object SoftAST { preIdentifierSpace: SpaceAST, identifier: IdentifierAST, preParamSpace: Option[Space], - params: Option[Tuple], + params: Option[Group[Token.OpenParen.type, Token.CloseParen.type]], postParamSpace: Option[Space], inheritance: Seq[TemplateInheritance], block: BlockClause) extends BodyPartAST - case class DataTemplate( + case class EventTemplate( index: SourceIndex, - dataType: TokenDocumented[Token.DataTemplate], + eventToken: TokenDocumented[Token.Event.type], preIdentifierSpace: SpaceAST, identifier: IdentifierAST, preParamSpace: Option[Space], - params: Tuple) + params: Group[Token.OpenParen.type, Token.CloseParen.type]) + extends BodyPartAST + + case class StructTemplate( + index: SourceIndex, + structToken: TokenDocumented[Token.Struct.type], + preIdentifierSpace: SpaceAST, + identifier: IdentifierAST, + preParamSpace: Option[Space], + params: Group[Token.OpenCurly.type, Token.CloseCurly.type]) extends BodyPartAST /** Syntax: `implements or extends contract(arg1, arg2 ...)` */ @@ -212,27 +228,33 @@ object SoftAST { index: SourceIndex, fnName: IdentifierAST, preParamSpace: Option[Space], - params: Tuple, + params: Group[Token.OpenParen.type, Token.CloseParen.type], postParamSpace: Option[Space], returned: FunctionReturnAST) extends SoftAST - sealed trait TypeAST extends SoftAST - - /** Multiple arguments. Syntax: (arg1, (arg2, arg3)) */ - case class Tuple( + /** + * Represents a comma separated list of expressions. + * + * This list of expressions is parsed by the following syntax: + * - Struct `{ a, b: Type, mut c: C }` + * - Annotation `@using(a = b)` + * - Contract | TxScript`(a, b, c)` + * - fn `(a: Type, b: Type, c)` + * - `enum` etc + */ + case class Group[O <: Token, C <: Token]( index: SourceIndex, - openParen: TokenDocExpectedAST[Token.OpenParen.type], + openToken: TokenDocExpectedAST[O], preHeadExpressionSpace: Option[Space], headExpression: Option[ExpressionAST], postHeadExpressionSpace: Option[Space], - tailExpressions: Seq[TupleTail], - closeParen: TokenDocExpectedAST[Token.CloseParen.type]) + tailExpressions: Seq[GroupTail], + closeToken: TokenDocExpectedAST[C]) extends ExpressionAST - with TypeAST - /** Syntax: (arg1, >>arg2, (arg3, arg4)<<) */ - case class TupleTail( + /** Comma separated tail expressions of a [[Group]] */ + case class GroupTail( index: SourceIndex, comma: TokenDocumented[Token.Comma.type], preExpressionSpace: Option[Space], @@ -246,7 +268,7 @@ object SoftAST { index: SourceIndex, forwardArrow: TokenDocExpectedAST[Token.ForwardArrow.type], space: Option[Space], - tpe: TypeAST) + tpe: ExpressionAST) extends FunctionReturnAST case class FunctionReturnExpected( @@ -254,7 +276,7 @@ object SoftAST { extends TokenExpectedErrorAST(Token.ForwardArrow) with FunctionReturnAST - sealed trait IdentifierAST extends TypeAST with ReferenceCallOrIdentifier + sealed trait IdentifierAST extends ReferenceCallOrIdentifier case class Identifier( index: SourceIndex, @@ -288,7 +310,7 @@ object SoftAST { index: SourceIndex, documentation: Option[Comments], code: CodeString) - extends ErrorAST(s"Cannot resolve '$code'") + extends ErrorAST(s"Cannot resolve '${code.text}'") with CodeDocumentedAST with BodyPartAST @@ -298,7 +320,7 @@ object SoftAST { index: SourceIndex, reference: IdentifierAST, preArgumentsSpace: Option[Space], - arguments: Tuple) + arguments: Group[Token.OpenParen.type, Token.CloseParen.type]) extends ExpressionAST with ReferenceCallOrIdentifier @@ -377,12 +399,11 @@ object SoftAST { case class TypeAssignment( index: SourceIndex, - modifiers: Seq[SoftAST.AssignmentAccessModifier], - name: IdentifierAST, + name: ExpressionAST, preColonSpace: Option[Space], colon: TokenDocumented[Token.Colon.type], postColonSpace: Option[Space], - tpe: TypeAST) + tpe: ExpressionAST) extends ExpressionAST case class AssignmentAccessModifier( @@ -417,7 +438,7 @@ object SoftAST { preIdentifierSpace: Option[Space], identifier: IdentifierAST, postIdentifierSpace: Option[Space], - tuple: Option[Tuple], + tuple: Option[Group[Token.OpenParen.type, Token.CloseParen.type]], postTupleSpace: Option[Space]) extends ExpressionAST diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParserSpec.scala similarity index 96% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParserSpec.scala index 09ccf1ef5..a40a6b206 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AnnotationParserSpec.scala @@ -25,7 +25,7 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues._ -class AnnotationSpec extends AnyWordSpec with Matchers { +class AnnotationParserSpec extends AnyWordSpec with Matchers { "error cases" should { "report missing identifier" in { @@ -49,9 +49,9 @@ class AnnotationSpec extends AnyWordSpec with Matchers { parseAnnotation("@anno(") // opening paren is parsed - annotation.tuple.value.openParen shouldBe OpenParen(indexOf("@anno>>(<<")) + annotation.tuple.value.openToken shouldBe OpenParen(indexOf("@anno>>(<<")) // closing paren is reported as expected - annotation.tuple.value.closeParen shouldBe SoftAST.TokenExpected(indexOf("@anno(>><<"), Token.CloseParen) + annotation.tuple.value.closeToken shouldBe SoftAST.TokenExpected(indexOf("@anno(>><<"), Token.CloseParen) } "reject reserved keyword as annotation identifier" in { diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParserSpec.scala similarity index 98% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParserSpec.scala index a8ee41fc9..88a969fa2 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/AssignmentParserSpec.scala @@ -23,7 +23,7 @@ import org.alephium.ralph.lsp.access.util.TestCodeUtil._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class AssignmentSpec extends AnyWordSpec with Matchers { +class AssignmentParserSpec extends AnyWordSpec with Matchers { "assignments to an identifier" should { "report ExpressionExpected" when { diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringParserSpec.scala similarity index 98% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringParserSpec.scala index 71c8cf2ac..2da2a4432 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/BStringParserSpec.scala @@ -9,7 +9,7 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues._ -class BStringSpec extends AnyWordSpec with Matchers { +class BStringParserSpec extends AnyWordSpec with Matchers { "b alone" should { "not parse as String literal" in { diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentParserSpec.scala similarity index 98% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentParserSpec.scala index 1f16fa9c3..a8715eefb 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/CommentParserSpec.scala @@ -23,7 +23,7 @@ import org.alephium.ralph.lsp.access.util.TestCodeUtil._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class CommentSpec extends AnyWordSpec with Matchers { +class CommentParserSpec extends AnyWordSpec with Matchers { "no text comment" should { "store empty comment" in { diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParserSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParserSpec.scala new file mode 100644 index 000000000..48d8e91e0 --- /dev/null +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/EventTemplateParserSpec.scala @@ -0,0 +1,24 @@ +package org.alephium.ralph.lsp.access.compiler.parser.soft + +import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ +import org.alephium.ralph.lsp.access.util.TestCodeUtil._ +import org.scalatest.matchers.should.Matchers._ +import org.scalatest.wordspec.AnyWordSpec + +class EventTemplateParserSpec extends AnyWordSpec { + + "successfully parse an event" in { + val event = parseEventTemplate("event MyEvent(varName: TypeName") + + event.eventToken shouldBe Event(indexOf(">>event<< MyEvent(varName: TypeName")) + event.identifier shouldBe Identifier(indexOf("event >>MyEvent<<(varName: TypeName"), "MyEvent") + + // Tuples are tested in TupleSpec, test for the index and string code here. + event.params.index shouldBe indexOf("event MyEvent>>(varName: TypeName<<") + event.params.toCode() shouldBe "(varName: TypeName" + event.params.closeToken shouldBe SoftAST.TokenExpected(indexOf("event MyEvent(varName: TypeName>><<"), Token.CloseParen) + } + +} diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionNameSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionNameSpec.scala index 49303dbdd..cf49e0d5f 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionNameSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionNameSpec.scala @@ -167,7 +167,7 @@ class FunctionNameSpec extends AnyWordSpec with Matchers { function .signature .params - .closeParen shouldBe SoftAST.TokenExpected(indexOf("fn abcd(>><<"), Token.CloseParen) + .closeToken shouldBe SoftAST.TokenExpected(indexOf("fn abcd(>><<"), Token.CloseParen) } "missing opening parentheses" in { @@ -183,7 +183,7 @@ class FunctionNameSpec extends AnyWordSpec with Matchers { function .signature .params - .openParen shouldBe SoftAST.TokenExpected(indexOf("fn abcd>><<)"), Token.OpenParen) + .openToken shouldBe SoftAST.TokenExpected(indexOf("fn abcd>><<)"), Token.OpenParen) } } diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionReturnClauseSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionReturnClauseSpec.scala index 358d0639a..716533218 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionReturnClauseSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/FunctionReturnClauseSpec.scala @@ -35,7 +35,7 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { index = indexOf("fn >>-> <<"), forwardArrow = ForwardArrow(indexOf("fn >>-><< ")), space = Some(SpaceOne(indexOf("fn __>> <<"))), - tpe = SoftAST.IdentifierExpected(indexOf("fn -> >><<")) + tpe = SoftAST.ExpressionExpected(indexOf("fn -> >><<")) ) } @@ -79,7 +79,7 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { index = indexOf("fn function >>-> <<"), forwardArrow = ForwardArrow(indexOf("fn function >>-><< ")), space = Some(SpaceOne(indexOf("fn function __>> <<"))), - tpe = SoftAST.IdentifierExpected(indexOf("fn function -> >><<")) + tpe = SoftAST.ExpressionExpected(indexOf("fn function -> >><<")) ) } @@ -117,9 +117,9 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { text = "function" ) - function.signature.params.openParen shouldBe OpenParen(indexOf("fn function>>(<<-> ")) + function.signature.params.openToken shouldBe OpenParen(indexOf("fn function>>(<<-> ")) - function.signature.params.closeParen shouldBe + function.signature.params.closeToken shouldBe SoftAST.TokenExpected(indexOf("fn function(>><<-> "), Token.CloseParen) function.signature.returned shouldBe @@ -127,7 +127,7 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { index = indexOf("fn function(>>-> <<"), forwardArrow = ForwardArrow(indexOf("fn function(>>-><< ")), space = Some(SpaceOne(indexOf("fn function(__>> <<"))), - tpe = SoftAST.IdentifierExpected(indexOf("fn function(-> >><<")) + tpe = SoftAST.ExpressionExpected(indexOf("fn function(-> >><<")) ) } @@ -141,8 +141,8 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { text = "function" ) - function.signature.params.openParen shouldBe OpenParen(indexOf("fn function>>(<<-> Type")) - function.signature.params.closeParen shouldBe SoftAST.TokenExpected(indexOf("fn function(>><<-> Type"), Token.CloseParen) + function.signature.params.openToken shouldBe OpenParen(indexOf("fn function>>(<<-> Type")) + function.signature.params.closeToken shouldBe SoftAST.TokenExpected(indexOf("fn function(>><<-> Type"), Token.CloseParen) function.signature.returned shouldBe SoftAST.FunctionReturn( @@ -169,15 +169,15 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { text = "function" ) - function.signature.params.openParen shouldBe OpenParen(indexOf("fn function>>(<<) -> ")) - function.signature.params.closeParen shouldBe CloseParen(indexOf("fn function(>>)<< -> ")) + function.signature.params.openToken shouldBe OpenParen(indexOf("fn function>>(<<) -> ")) + function.signature.params.closeToken shouldBe CloseParen(indexOf("fn function(>>)<< -> ")) function.signature.returned shouldBe SoftAST.FunctionReturn( index = indexOf("fn function() >>-> <<"), forwardArrow = ForwardArrow(indexOf("fn function() >>-><< ")), space = Some(SpaceOne(indexOf("fn function() __>> <<"))), - tpe = SoftAST.IdentifierExpected(indexOf("fn function() -> >><<")) + tpe = SoftAST.ExpressionExpected(indexOf("fn function() -> >><<")) ) } @@ -191,8 +191,8 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { text = "function" ) - function.signature.params.openParen shouldBe OpenParen(indexOf("fn function>>(<<) -> type")) - function.signature.params.closeParen shouldBe CloseParen(indexOf("fn function(>>)<< -> type")) + function.signature.params.openToken shouldBe OpenParen(indexOf("fn function>>(<<) -> type")) + function.signature.params.closeToken shouldBe CloseParen(indexOf("fn function(>>)<< -> type")) function.signature.returned shouldBe SoftAST.FunctionReturn( @@ -225,8 +225,8 @@ class FunctionReturnClauseSpec extends AnyWordSpec with Matchers { text = "function" ) - function.signature.params.openParen shouldBe OpenParen(indexOf("fn function>>(<<) => ABC")) - function.signature.params.closeParen shouldBe CloseParen(indexOf("fn function(>>)<< => ABC")) + function.signature.params.openToken shouldBe OpenParen(indexOf("fn function>>(<<) => ABC")) + function.signature.params.closeToken shouldBe CloseParen(indexOf("fn function(>>)<< => ABC")) /** * Second part is [[SoftAST.Unresolved]] arrow `=>` diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParserSpec.scala similarity index 69% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParserSpec.scala index 4a76e3ead..a5ff15ef2 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TupleSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/GroupParserSpec.scala @@ -24,22 +24,22 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues._ -class TupleSpec extends AnyWordSpec with Matchers { +class GroupParserSpec extends AnyWordSpec with Matchers { "missing opening paren" in { val tuple = parseTuple(")") - tuple.openParen shouldBe SoftAST.TokenExpected(indexOf(">><<)"), Token.OpenParen) - tuple.closeParen shouldBe CloseParen(indexOf(">>)<<")) + tuple.openToken shouldBe SoftAST.TokenExpected(indexOf(">><<)"), Token.OpenParen) + tuple.closeToken shouldBe CloseParen(indexOf(">>)<<")) } "missing closing paren" in { val tuple = parseTuple("(") - tuple.openParen shouldBe OpenParen(indexOf(">>(<<")) - tuple.closeParen shouldBe SoftAST.TokenExpected(indexOf("(>><<"), Token.CloseParen) + tuple.openToken shouldBe OpenParen(indexOf(">>(<<")) + tuple.closeToken shouldBe SoftAST.TokenExpected(indexOf("(>><<"), Token.CloseParen) } "empty tuple" when { @@ -48,14 +48,14 @@ class TupleSpec extends AnyWordSpec with Matchers { parseTuple("()") val expected = - SoftAST.Tuple( + SoftAST.Group( index = indexOf(">>()<<"), - openParen = OpenParen(indexOf(">>(<<)")), + openToken = OpenParen(indexOf(">>(<<)")), preHeadExpressionSpace = None, headExpression = None, postHeadExpressionSpace = None, tailExpressions = Seq.empty, - closeParen = CloseParen(indexOf("(>>)<<)")) + closeToken = CloseParen(indexOf("(>>)<<)")) ) tuple shouldBe expected @@ -66,14 +66,14 @@ class TupleSpec extends AnyWordSpec with Matchers { parseTuple("( )") val expected = - SoftAST.Tuple( + SoftAST.Group( index = indexOf(">>( )<<"), - openParen = OpenParen(indexOf(">>(<< )")), + openToken = OpenParen(indexOf(">>(<< )")), preHeadExpressionSpace = Some(SpaceOne(indexOf("(>> <<)"))), headExpression = None, postHeadExpressionSpace = None, tailExpressions = Seq.empty, - closeParen = CloseParen(indexOf("( >>)<<)")) + closeToken = CloseParen(indexOf("( >>)<<)")) ) tuple shouldBe expected @@ -88,9 +88,9 @@ class TupleSpec extends AnyWordSpec with Matchers { * First body part is Tuple */ val tuple = - body.parts.head.part.asInstanceOf[SoftAST.Tuple] + body.parts.head.part.asInstanceOf[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] - tuple.openParen shouldBe OpenParen(indexOf(">>(<>(<><><>(<>(<>)<<")) + tuple.closeToken shouldBe CloseParen(indexOf("(aaa: typename>>)<<")) } "valid second type assignment expression exists" in { @@ -187,9 +187,44 @@ class TupleSpec extends AnyWordSpec with Matchers { ) // A quick text to check that the tuple is actually a tuple - bbb.tpe shouldBe a[SoftAST.Tuple] + bbb.tpe shouldBe a[SoftAST.Group[_, _]] // Convert the tpe to code and it should be the tuple bbb.tpe.toCode() shouldBe "(tuple1, tuple2)" } + "nested tuples" in { + val tuple = parseTuple("(a, (b, c))") + + tuple.headExpression.value shouldBe a[SoftAST.Identifier] + + tuple.tailExpressions should have size 1 + val lastTuple = tuple.tailExpressions.head + + lastTuple shouldBe + SoftAST.GroupTail( + index = indexOf("(a>>, (b, c)<<)"), + comma = Comma(indexOf("(a>>,<< (b, c))")), + preExpressionSpace = Some(SpaceOne(indexOf("(a,>> <<(b, c))"))), + expression = SoftAST.Group( + index = indexOf("(a, >>(b, c)<<)"), + openToken = OpenParen(indexOf("(a, >>(<>b<<, c))"), "b")), + postHeadExpressionSpace = None, + tailExpressions = Seq( + SoftAST.GroupTail( + index = indexOf("(a, (b>>, c<<))"), + comma = Comma(indexOf("(a, (b>>,<< c))")), + preExpressionSpace = Some(SpaceOne(indexOf("(a, (b,>> <>c<<))"), "c"), + postExpressionSpace = None + ) + ), + closeToken = CloseParen(indexOf("(a, (b, c>>)<<)")) + ), + postExpressionSpace = None + ) + + } + } diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParserSpec.scala similarity index 93% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParserSpec.scala index 3eebf0fa3..fe0b019f9 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/IdentifierParserSpec.scala @@ -6,7 +6,7 @@ import org.alephium.ralph.lsp.access.util.TestFastParse._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class IdentifierSpec extends AnyWordSpec with Matchers { +class IdentifierParserSpec extends AnyWordSpec with Matchers { "disallow reserved tokens to be used as identifier" when { val reserved = diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingParserSpec.scala similarity index 89% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingParserSpec.scala index fa7e2cd70..098809ce9 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/MutableBindingParserSpec.scala @@ -17,14 +17,14 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ import org.alephium.ralph.lsp.access.util.TestCodeUtil._ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues._ -class MutableBindingSpec extends AnyWordSpec with Matchers { +class MutableBindingParserSpec extends AnyWordSpec with Matchers { "succeed" when { "an identifier is set a mut" in { @@ -45,7 +45,7 @@ class MutableBindingSpec extends AnyWordSpec with Matchers { parseSoft("(a, b, mut variable)") body.parts should have size 1 - val tuple = body.parts.head.part.asInstanceOf[SoftAST.Tuple] + val tuple = body.parts.head.part.asInstanceOf[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] tuple.headExpression shouldBe defined tuple.tailExpressions should have size 2 // there are two tail expressions @@ -75,7 +75,7 @@ class MutableBindingSpec extends AnyWordSpec with Matchers { } body.parts should have size 1 - val tuple = body.parts.head.part.asInstanceOf[SoftAST.Tuple] + val tuple = body.parts.head.part.asInstanceOf[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] tuple.headExpression shouldBe defined tuple.tailExpressions should have size 2 // there are two tail expressions diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParserSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParserSpec.scala new file mode 100644 index 000000000..0c2395b92 --- /dev/null +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/StructTemplateParserSpec.scala @@ -0,0 +1,38 @@ +package org.alephium.ralph.lsp.access.compiler.parser.soft + +import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ +import org.alephium.ralph.lsp.access.util.TestCodeUtil._ +import org.scalatest.matchers.should.Matchers._ +import org.scalatest.wordspec.AnyWordSpec + +class StructTemplateParserSpec extends AnyWordSpec { + + "closing curly is missing" in { + val struct = parseStructTemplate("struct MyStruct{varName: TypeName") + + struct.structToken shouldBe Struct(indexOf(">>struct<< MyStruct{varName: TypeName")) + struct.identifier shouldBe Identifier(indexOf("struct >>MyStruct<<{varName: TypeName"), "MyStruct") + + // Tuples are tested in TupleSpec, test for the index and string code here. + struct.params.index shouldBe indexOf("struct MyStruct>>{varName: TypeName<<") + struct.params.toCode() shouldBe "{varName: TypeName" + struct.params.closeToken shouldBe SoftAST.TokenExpected(indexOf("struct MyStruct{varName: TypeName>><<"), Token.CloseCurly) + } + + "well defined struct" in { + val struct = parseStructTemplate("struct Bar { z: U256, mut foo: Foo }") + + struct.structToken shouldBe Struct(indexOf(">>struct<< Bar { z: U256, mut foo: Foo }")) + struct.identifier shouldBe Identifier(indexOf("struct >>Bar<< { z: U256, mut foo: Foo }"), "Bar") + + // Tuples are tested in TupleSpec, test for the index and string code here. + struct.params.index shouldBe indexOf("struct Bar >>{ z: U256, mut foo: Foo }<<") + struct.params.toCode() shouldBe "{ z: U256, mut foo: Foo }" + struct.params.openToken shouldBe OpenCurly(indexOf("struct Bar >>{<< z: U256, mut foo: Foo }")) + struct.params.closeToken shouldBe CloseCurly(indexOf("struct Bar { z: U256, mut foo: Foo >>}<<")) + + } + +} diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateSpec.scala index 0e95ea0b5..f169ff874 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TemplateSpec.scala @@ -115,8 +115,8 @@ class TemplateSpec extends AnyWordSpec with Matchers { parseTemplate("Contract mycontract(") val params = template.params.value - params.openParen shouldBe OpenParen(indexOf("Contract mycontract>>(<<")) - params.closeParen shouldBe SoftAST.TokenExpected(indexOf("Contract mycontract(>><<"), Token.CloseParen) + params.openToken shouldBe OpenParen(indexOf("Contract mycontract>>(<<")) + params.closeToken shouldBe SoftAST.TokenExpected(indexOf("Contract mycontract(>><<"), Token.CloseParen) } "params are empty" in { diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala index afbd94ffb..066b8ca7a 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TestParser.scala @@ -45,11 +45,8 @@ object TestParser { def parseFunction(code: String): SoftAST.Function = runSoftParser(FunctionParser.parseOrFail(_))(code) - def parseTuple(code: String): SoftAST.Tuple = - runSoftParser(TupleParser.parse(_))(code) - - def parseBlockClause(mandatory: Boolean)(code: String): SoftAST.BlockClause = - runSoftParser(BlockParser.clause(mandatory)(_))(code) + def parseTuple(code: String): SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type] = + runSoftParser(ParameterParser.parse(_))(code) def parseBlockBody(code: String): SoftAST.BlockBody = runSoftParser(BlockParser.body(_))(code) @@ -57,9 +54,6 @@ object TestParser { def parseComment(code: String): SoftAST.Comments = runSoftParser(CommentParser.parseOrFail(_))(code) - def parseType(code: String): SoftAST.TypeAST = - runSoftParser(TypeParser.parse(_))(code) - def parseReservedToken(remove: Token.Reserved*)(code: String): Token.Reserved = runAnyParser(TokenParser.Reserved(remove: _*)(_))(code) @@ -85,6 +79,15 @@ object TestParser { def parseBString(code: String): SoftAST.BString = runSoftParser(BStringParser.parseOrFail(_))(code) + def parseEventTemplate(code: String): SoftAST.EventTemplate = + runSoftParser(EventTemplateParser.parseOrFail(_))(code) + + def parseStructTemplate(code: String): SoftAST.StructTemplate = + runSoftParser(StructTemplateParser.parseOrFail(_))(code) + + def parseTypeAssignment(code: String): SoftAST.TypeAssignment = + runSoftParser(TypeAssignmentParser.parseOrFail(_))(code) + def findAnnotation(identifier: String)(code: String): Option[SoftAST.Annotation] = findAnnotation( identifier = identifier, diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParserSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParserSpec.scala new file mode 100644 index 000000000..0237a4e5e --- /dev/null +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeAssignmentParserSpec.scala @@ -0,0 +1,48 @@ +package org.alephium.ralph.lsp.access.compiler.parser.soft + +import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ +import org.alephium.ralph.lsp.access.util.TestCodeUtil._ +import org.scalatest.matchers.should.Matchers._ +import org.scalatest.wordspec.AnyWordSpec + +class TypeAssignmentParserSpec extends AnyWordSpec { + + "report error" when { + "type name is not supplied" in { + val assignment = + parseTypeAssignment(": Type") + + assignment shouldBe + SoftAST.TypeAssignment( + index = indexOf(">>: Type<<"), + name = SoftAST.ExpressionExpected(indexOf(">><<: Type")), + preColonSpace = None, + colon = Colon(indexOf(">>:<< Type")), + postColonSpace = Some(SpaceOne(indexOf(":>> <>Type<<"), "Type") + ) + } + } + + "success" when { + "type assignment is fully defined" when { + "defined as identifier" in { + val assignment = + parseTypeAssignment("name : Type") + + assignment shouldBe + SoftAST.TypeAssignment( + index = indexOf(">>name : Type<<"), + name = Identifier(indexOf(">>name<< : Type"), "name"), + preColonSpace = Some(SpaceOne(indexOf("name>> <<: Type"))), + colon = Colon(indexOf("name >>:<< Type")), + postColonSpace = Some(SpaceOne(indexOf("name :>> <>Type<<"), "Type") + ) + } + } + } + +} diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParserSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParserSpec.scala deleted file mode 100644 index cfc17e494..000000000 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/TypeParserSpec.scala +++ /dev/null @@ -1,61 +0,0 @@ -package org.alephium.ralph.lsp.access.compiler.parser.soft - -import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ -import org.alephium.ralph.lsp.access.util.TestCodeUtil._ -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec - -class TypeParserSpec extends AnyWordSpec with Matchers { - - "type expected" when { - "empty" in { - parseType("") shouldBe SoftAST.IdentifierExpected(indexOf(">><<")) - } - } - - "type is provided" in { - parseType("one") shouldBe - Identifier( - index = indexOf(">>one<<"), - text = "one" - ) - } - - "tuple 1" when { - "closing parentheses is missing" in { - val tpe = parseType("( one") - - tpe shouldBe a[SoftAST.Tuple] - } - - "closing parentheses is provided" in { - val tpe = parseType("( one)") - - tpe shouldBe a[SoftAST.Tuple] - } - } - - "tuple 2" when { - "second type is missing" in { - val tpe = parseType("(one, )") - - tpe shouldBe a[SoftAST.Tuple] - } - - "second type is a simple type name" in { - val tpe = parseType("(one, two)") - - tpe shouldBe a[SoftAST.Tuple] - } - - "second type is another tuple" in { - val tpe = parseType("(one, (two, three))") - - tpe shouldBe a[SoftAST.Tuple] - } - - } - -} diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationSpec.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationParserSpec.scala similarity index 96% rename from compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationSpec.scala rename to compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationParserSpec.scala index 1d136b8c3..fe275a00f 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationSpec.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/VariableDeclarationParserSpec.scala @@ -18,7 +18,7 @@ package org.alephium.ralph.lsp.access.compiler.parser.soft import org.alephium.ralph.error.CompilerError import org.alephium.ralph.lsp.access.compiler.parser.soft.TestParser._ -import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.SoftAST +import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.{SoftAST, Token} import org.alephium.ralph.lsp.access.compiler.parser.soft.ast.TestSoftAST._ import org.alephium.ralph.lsp.access.util.TestCodeUtil._ import org.scalatest.matchers.should.Matchers @@ -27,7 +27,7 @@ import org.scalatest.TryValues.convertTryToSuccessOrFailure import scala.util.Try -class VariableDeclarationSpec extends AnyWordSpec with Matchers { +class VariableDeclarationParserSpec extends AnyWordSpec with Matchers { "succeed" when { "full valid variable declaration is defined" in { @@ -122,7 +122,7 @@ class VariableDeclarationSpec extends AnyWordSpec with Matchers { ) // left is a tuple - val left = tupleDecl.assignment.expressionLeft.asInstanceOf[SoftAST.Tuple] + val left = tupleDecl.assignment.expressionLeft.asInstanceOf[SoftAST.Group[Token.OpenParen.type, Token.CloseParen.type]] left.index shouldBe indexOf("let >>(a, b, c)<< = blah") left.toCode() shouldBe "(a, b, c)" diff --git a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/TestSoftAST.scala b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/TestSoftAST.scala index 10e42c1eb..51c60fe8c 100644 --- a/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/TestSoftAST.scala +++ b/compiler-access/src/test/scala/org/alephium/ralph/lsp/access/compiler/parser/soft/ast/TestSoftAST.scala @@ -138,6 +138,18 @@ object TestSoftAST { token = Token.Tick ) + def Event(index: SourceIndex): SoftAST.TokenDocumented[Token.Event.type] = + TokenDocumented( + index = index, + token = Token.Event + ) + + def Struct(index: SourceIndex): SoftAST.TokenDocumented[Token.Struct.type] = + TokenDocumented( + index = index, + token = Token.Struct + ) + def Identifier( index: SourceIndex, text: String): SoftAST.Identifier =