diff --git a/build.sbt b/build.sbt index f8ac720a..edce76fa 100644 --- a/build.sbt +++ b/build.sbt @@ -26,6 +26,8 @@ val commons = Seq( scalaVersion := scalaV, libraryDependencies ++= Seq( "com.outr" %%% "scribe" % scribeV, + "dev.optics" %%% "monocle-core" % monocleV, + "dev.optics" %%% "monocle-macro" % monocleV, "org.scalatest" %%% "scalatest" % scalaTestV % Test, "org.scalatestplus" %%% "scalacheck-1-17" % scalaTestScalaCheckV % Test ), @@ -201,12 +203,6 @@ lazy val semantics = crossProject(JVMPlatform, JSPlatform) .withoutSuffixFor(JVMPlatform) .crossType(CrossType.Pure) .settings(commons) - .settings( - libraryDependencies ++= Seq( - "dev.optics" %%% "monocle-core" % monocleV, - "dev.optics" %%% "monocle-macro" % monocleV - ) - ) .dependsOn(raw, parser, errors, mangler) lazy val compiler = crossProject(JVMPlatform, JSPlatform) @@ -287,6 +283,7 @@ lazy val helpers = crossProject(JVMPlatform, JSPlatform) "org.typelevel" %%% "cats-free" % catsV ) ) + .dependsOn(errors) lazy val errors = crossProject(JVMPlatform, JSPlatform) .withoutSuffixFor(JVMPlatform) diff --git a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala index 85295f76..1ae44f63 100644 --- a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala +++ b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala @@ -29,6 +29,7 @@ import cats.syntax.show.* import org.scalatest.Inside import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import scala.annotation.tailrec class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { import ModelBuilder.* @@ -497,10 +498,14 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } } - val moduleNames = List("Test", "Imp", "Sub", "Path").inits - .takeWhile(_.nonEmpty) - .map(_.mkString(".")) - .toList + def paths(parts: List[String]): List[String] = + parts.inits + .takeWhile(_.nonEmpty) + .map(_.mkString(".")) + .toList + + val moduleNames = paths(List("Test", "Imp", "Sub", "Path")) + val renames = paths(List("Renamed", "With", "New", "Name")) it should "import function with `use`" in { def test(name: String, rename: Option[String]) = { @@ -536,13 +541,15 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } moduleNames.foreach { name => - val rename = "Imported" withClue(s"Testing $name") { test(name, None) } - withClue(s"Testing $name as $rename") { - test(name, rename.some) + + renames.foreach { rename => + withClue(s"Testing $name as $rename") { + test(name, rename.some) + } } } } @@ -664,13 +671,15 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } moduleNames.foreach { name => - val rename = "Imported" withClue(s"Testing $name") { test(name, None) } - withClue(s"Testing $name as $rename") { - test(name, rename.some) + + renames.foreach { rename => + withClue(s"Testing $name as $rename") { + test(name, rename.some) + } } } } @@ -733,13 +742,15 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } moduleNames.foreach { name => - val rename = "Imported" withClue(s"Testing $name") { test(name, None) } - withClue(s"Testing $name as $rename") { - test(name, rename.some) + + renames.foreach { rename => + withClue(s"Testing $name as $rename") { + test(name, rename.some) + } } } } @@ -878,6 +889,161 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } } + it should "import redeclared functions" in { + + final case class Imp( + idx: Int, + name: String, + rename: Option[String] = None, + use: Option[Imp] = None + ) { + def withUse(other: Imp): Imp = copy(use = Some(other)) + + lazy val path: String = s"import$idx.aqua" + + lazy val declares: List[String] = use + .map(u => u.declares.map(n => s"${u.access}.$n")) + .getOrElse(Nil) + .prepended("foo") + + lazy val code: String = + s"""|aqua $name declares ${declares.mkString(", ")} + | + |${use.fold("")(_.usage)} + | + |func foo() -> i32: + | <- $idx + |""".stripMargin + + lazy val usage: String = s"use \"$path\"" + rename.fold("")(n => s" as $n") + + lazy val access: String = rename.getOrElse(name) + } + + type NameRename = (String, Option[String]) + + def test(imps: List[NameRename]) = { + (imps.length > 0) should be(true) + + val top = imps.zipWithIndex.map { case ((name, rename), idx) => + Imp(idx + 1, name, rename) + }.reduceRight { case (cur, prev) => + cur.withUse(prev) + } + + val (calls, vars) = top.declares.zipWithIndex.map { case (decl, idx) => + val v = s"v$idx" + val call = s"$v <- ${top.access}.$decl()" + call -> v + }.unzip + + val main = + s"""|aqua Main + | + |export main + | + |${top.usage} + | + |func main() -> i32: + | ${calls.mkString("\n ")} + | <- ${vars.mkString(" + ")} + |""".stripMargin + + val imports = List + .unfold(top.some)( + _.map(i => i -> i.use) + ) + .map(i => i.path -> i.code) + .toMap + + val src = Map( + "main.aqua" -> main + ) + + val transformCfg = TransformConfig(relayVarName = None) + + insideRes(src, imports, transformCfg)( + "main" + ) { case main :: _ => + val l = imps.length + val res = LiteralModel.number(l * (l + 1) / 2) + val expected = XorRes.wrap( + respCall(transformCfg, res, initPeer), + errorCall(transformCfg, 0, initPeer) + ) + + main.body.equalsOrShowDiff(expected) should be(true) + } + } + + // Simple + (1 to 10).foreach { i => + val names = (1 to i).map(n => s"Imp$n").toList + withClue(s"Testing ${names.mkString(" -> ")}") { + test(names.map(_ -> none)) + } + } + + extension [A](l: List[List[A]]) { + def rotate: List[List[A]] = + l.foldLeft(List.empty[List[A]]) { case (acc, next) => + if (acc.isEmpty) next.map(List(_)) + else + for { + elem <- next + prev <- acc + } yield elem +: prev + } + } + + // With subpaths + (1 to 4).foreach { i => + (1 to i) + .map(idx => + paths( + List("Imp", "Sub", "Path") + .map(p => s"$p$idx") + ) + ) + .toList + .rotate + .foreach(names => + withClue(s"Testing ${names.mkString(" -> ")}") { + test(names.map(_ -> none)) + } + ) + } + + // With renames + (1 to 3).foreach { i => + (1 to i) + .map(idx => + for { + name <- paths( + List("Imp", "Sub", "Path") + .map(p => s"$p$idx") + ) + rename <- None :: paths( + List("Rename", "To", "Other") + .map(p => s"$p$idx") + ).map(_.some) + } yield name -> rename + ) + .toList + .rotate + .foreach(names => + val message = names.map { case (n, r) => + s"$n${r.fold("")(n => s" as $n")}" + }.mkString(" -> ") + + withClue(s"Testing $message") { + test(names) + } + ) + } + + } + it should "not generate error propagation in `if` with `noXor = true`" in { val src = Map( "index.aqua" -> diff --git a/language-server/language-server-api/src/main/scala/aqua/lsp/LspContext.scala b/language-server/language-server-api/src/main/scala/aqua/lsp/LspContext.scala index 19679aec..fde657ed 100644 --- a/language-server/language-server-api/src/main/scala/aqua/lsp/LspContext.scala +++ b/language-server/language-server-api/src/main/scala/aqua/lsp/LspContext.scala @@ -1,5 +1,6 @@ package aqua.lsp +import aqua.helpers.data.PName import aqua.parser.lexer.{LiteralToken, NamedTypeToken, Token} import aqua.raw.{RawContext, RawPart} import aqua.semantics.header.Picker @@ -94,15 +95,12 @@ object LspContext { ): LspContext[S] = ctx.copy(importPaths = importPaths) - override def setModule( - ctx: LspContext[S], - name: String - ): LspContext[S] = + override def setModule(ctx: LspContext[S], name: Option[String]): LspContext[S] = ctx.copy(raw = ctx.raw.setModule(name)) override def setDeclares( ctx: LspContext[S], - declares: Set[String] + declares: Set[PName] ): LspContext[S] = ctx.copy(raw = ctx.raw.setDeclares(declares)) @@ -145,6 +143,9 @@ object LspContext { ) ) + override def pick(ctx: LspContext[S], name: PName, declared: Boolean): Option[LspContext[S]] = + ctx.raw.pick(name, declared).map(rc => ctx.copy(raw = rc)) + override def pickHeader(ctx: LspContext[S]): LspContext[S] = ctx.copy(raw = ctx.raw.pickHeader) override def pickDeclared(ctx: LspContext[S]): LspContext[S] = diff --git a/model/raw/src/main/scala/aqua/raw/RawContext.scala b/model/raw/src/main/scala/aqua/raw/RawContext.scala index 741d5547..ff021c96 100644 --- a/model/raw/src/main/scala/aqua/raw/RawContext.scala +++ b/model/raw/src/main/scala/aqua/raw/RawContext.scala @@ -1,5 +1,6 @@ package aqua.raw +import aqua.helpers.data.PName import aqua.raw.arrow.FuncRaw import aqua.raw.value.ValueRaw import aqua.types.{AbilityType, StructType, Type} @@ -8,8 +9,11 @@ import cats.Monoid import cats.Semigroup import cats.data.Chain import cats.data.NonEmptyMap +import cats.syntax.align.* import cats.syntax.monoid.* import cats.syntax.option.* +import monocle.Lens +import monocle.macros.GenLens import scala.collection.immutable.SortedMap /** @@ -28,7 +32,7 @@ import scala.collection.immutable.SortedMap */ case class RawContext( module: Option[String] = None, - declares: Set[String] = Set.empty, + declares: Set[PName] = Set.empty, exports: Map[String, Option[String]] = Map.empty, parts: Chain[(RawContext, RawPart)] = Chain.empty, abilities: Map[String, RawContext] = Map.empty @@ -51,6 +55,9 @@ case class RawContext( } .map(prefixFirst(prefix, _)) + lazy val allAbilities: Map[String, RawContext] = + all(_.abilities) + lazy val services: Map[String, ServiceRaw] = collectPartsMap { case srv: ServiceRaw => srv } lazy val allServices: Map[String, ServiceRaw] = @@ -87,10 +94,11 @@ case class RawContext( all(_.definedAbilities) lazy val allNames: Set[String] = + // TODO: How about names in abilities? parts.map { case (_, p) => p.name }.toList.toSet lazy val declaredNames: Set[String] = - allNames.intersect(declares) + declares.map(_.value).toSet override def toString: String = s"""|module: ${module.getOrElse("unnamed")} @@ -105,6 +113,18 @@ case class RawContext( object RawContext { val blank: RawContext = RawContext() + val partsLens: Lens[RawContext, Chain[(RawContext, RawPart)]] = + GenLens[RawContext](_.parts) + + val abilitiesLens: Lens[RawContext, Map[String, RawContext]] = + GenLens[RawContext](_.abilities) + + def fromParts(parts: Chain[(RawContext, RawPart)]): RawContext = + partsLens.set(parts)(blank) + + def fromAbilities(abilities: Map[String, RawContext]): RawContext = + abilitiesLens.set(abilities)(blank) + given Monoid[RawContext] with { override def empty: RawContext = blank @@ -115,7 +135,8 @@ object RawContext { x.declares ++ y.declares, x.exports ++ y.exports, x.parts ++ y.parts, - x.abilities ++ y.abilities + // This combines abilities (which are RawContexts too) recursively + x.abilities.alignCombine(y.abilities) ) } } diff --git a/parser/src/main/scala/aqua/parser/Expr.scala b/parser/src/main/scala/aqua/parser/Expr.scala index b3290c79..54bfd5a8 100644 --- a/parser/src/main/scala/aqua/parser/Expr.scala +++ b/parser/src/main/scala/aqua/parser/Expr.scala @@ -3,21 +3,18 @@ package aqua.parser import aqua.parser.Ast.Tree import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* -import aqua.parser.expr.func.ReturnExpr import aqua.parser.lift.LiftParser.* -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import aqua.parser.lift.{LiftParser, Span} -import aqua.parser.Ast.Tree -import aqua.parser.ListToTreeConverter +import cats.Show import cats.data.Chain.:== +import cats.data.Validated.{invalid, invalidNec, invalidNel, valid, validNec, validNel} import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec} import cats.free.Cofree -import cats.Show -import cats.data.Validated.{invalid, invalidNec, invalidNel, valid, validNec, validNel} import cats.parse.{Parser as P, Parser0 as P0} import cats.syntax.comonad.* -import cats.{~>, Comonad, Eval} +import cats.{Comonad, Eval, ~>} import scribe.Logging abstract class Expr[F[_]](val companion: Expr.Companion, val token: Token[F]) { diff --git a/parser/src/main/scala/aqua/parser/Parser.scala b/parser/src/main/scala/aqua/parser/Parser.scala index 1b4e49ee..feb94a0a 100644 --- a/parser/src/main/scala/aqua/parser/Parser.scala +++ b/parser/src/main/scala/aqua/parser/Parser.scala @@ -2,9 +2,10 @@ package aqua.parser import aqua.parser.expr.RootExpr import aqua.parser.head.Header -import aqua.parser.lift.LiftParser.LiftErrorOps -import aqua.parser.lift.Span.S -import aqua.parser.lift.{LiftParser, Span} +import aqua.parser.lift.LiftParser +import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} import cats.data.{Validated, ValidatedNec} import cats.free.Cofree diff --git a/parser/src/main/scala/aqua/parser/expr/AliasExpr.scala b/parser/src/main/scala/aqua/parser/expr/AliasExpr.scala index fa54b40e..1fe257a3 100644 --- a/parser/src/main/scala/aqua/parser/expr/AliasExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/AliasExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.lexer.Token._ import aqua.parser.lexer.{NamedTypeToken, TypeToken} import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.Parser import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan} case class AliasExpr[F[_]](name: NamedTypeToken[F], target: TypeToken[F]) extends Expr[F](AliasExpr, name) { diff --git a/parser/src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala b/parser/src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala index fb523f00..44f23f29 100644 --- a/parser/src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/ArrowTypeExpr.scala @@ -5,7 +5,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, Name} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.parse.Parser diff --git a/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala b/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala index 319089ef..5396c37b 100644 --- a/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/ConstantExpr.scala @@ -1,16 +1,17 @@ package aqua.parser.expr import aqua.parser.Expr -import aqua.parser.lexer.Token.* import aqua.parser.lexer.* +import aqua.parser.lexer.PrefixToken +import aqua.parser.lexer.Token.* +import aqua.parser.lexer.VarToken import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.Parser as P import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} -import aqua.parser.lexer.PrefixToken -import aqua.parser.lexer.VarToken case class ConstantExpr[F[_]]( name: Name[F], diff --git a/parser/src/main/scala/aqua/parser/expr/DataStructExpr.scala b/parser/src/main/scala/aqua/parser/expr/DataStructExpr.scala index dff79f1d..81904b61 100644 --- a/parser/src/main/scala/aqua/parser/expr/DataStructExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/DataStructExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.lexer.NamedTypeToken import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.Parser import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class DataStructExpr[F[_]](name: NamedTypeToken[F]) extends Expr[F](DataStructExpr, name) { override def mapK[K[_]: Comonad](fk: F ~> K): DataStructExpr[K] = copy(name.mapK(fk)) diff --git a/parser/src/main/scala/aqua/parser/expr/FieldTypeExpr.scala b/parser/src/main/scala/aqua/parser/expr/FieldTypeExpr.scala index 0f587925..25477c8d 100644 --- a/parser/src/main/scala/aqua/parser/expr/FieldTypeExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/FieldTypeExpr.scala @@ -5,7 +5,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{BasicTypeToken, Name, StreamTypeToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.parse.Parser diff --git a/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala b/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala index cca390e0..7d2ceb24 100644 --- a/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala @@ -1,17 +1,18 @@ package aqua.parser.expr import aqua.parser.expr.func.ArrowExpr -import aqua.parser.lexer.Token.* import aqua.parser.lexer.Name +import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} import aqua.parser.{Ast, Expr} + import cats.Comonad import cats.data.{Validated, ValidatedNec} import cats.free.Cofree import cats.parse.Parser import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class FuncExpr[F[_]]( name: Name[F] diff --git a/parser/src/main/scala/aqua/parser/expr/RootExpr.scala b/parser/src/main/scala/aqua/parser/expr/RootExpr.scala index 11d0fcc1..4b92b5fe 100644 --- a/parser/src/main/scala/aqua/parser/expr/RootExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/RootExpr.scala @@ -3,8 +3,10 @@ package aqua.parser.expr import aqua.parser.Ast.Tree import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* +import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* -import aqua.parser.lift.{LiftParser, Span} +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} import aqua.parser.{Expr, ParserError} import cats.data.{Chain, NonEmptyChain, NonEmptyList, Validated, ValidatedNec} @@ -21,7 +23,6 @@ case class RootExpr[F[_]](point: Token[F]) extends Expr[F](RootExpr, point) { } object RootExpr extends Expr.Companion { - import Span.* def validChildren: List[Expr.Lexem] = ServiceExpr :: AliasExpr :: DataStructExpr :: AbilityExpr :: ConstantExpr :: FuncExpr :: Nil diff --git a/parser/src/main/scala/aqua/parser/expr/ServiceExpr.scala b/parser/src/main/scala/aqua/parser/expr/ServiceExpr.scala index 21e5144c..bce960bf 100644 --- a/parser/src/main/scala/aqua/parser/expr/ServiceExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/ServiceExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{NamedTypeToken, ValueToken} import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.Parser import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class ServiceExpr[F[_]](name: NamedTypeToken[F], id: Option[ValueToken[F]]) extends Expr[F](ServiceExpr, name) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala index c38f3d35..7f1ea934 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala @@ -3,8 +3,9 @@ package aqua.parser.expr.func import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, NamedTypeToken, TypeToken, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import aqua.parser.{ArrowReturnError, Ast, Expr, ParserError} + import cats.Comonad import cats.parse.Parser import cats.~> diff --git a/parser/src/main/scala/aqua/parser/expr/func/AssignmentExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/AssignmentExpr.scala index 050fca33..3f1e2a92 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/AssignmentExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/AssignmentExpr.scala @@ -5,10 +5,11 @@ import aqua.parser.expr.func.AssignmentExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{CollectionToken, Name, ValueToken} import aqua.parser.lift.LiftParser -import cats.parse.Parser as P -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser as P +import cats.{Comonad, ~>} case class AssignmentExpr[F[_]]( variable: Name[F], diff --git a/parser/src/main/scala/aqua/parser/expr/func/CallArrowExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/CallArrowExpr.scala index 3190b292..735beb79 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/CallArrowExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/CallArrowExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.expr.func.CallArrowExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{CallArrowToken, Name, ValueToken, VarToken} +import aqua.parser.lift.Span.{given, *} import aqua.parser.lift.{LiftParser, Span} -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} + import cats.data.NonEmptyList import cats.parse.{Parser as P, Parser0 as P0} -import cats.{~>, Comonad} +import cats.{Comonad, ~>} case class CallArrowExpr[F[_]]( variables: List[Name[F]], @@ -27,7 +28,8 @@ case class CallArrowExpr[F[_]]( object CallArrowExpr extends Expr.Leaf { override val p: P[CallArrowExpr[Span.S]] = { - val variables: P0[Option[NonEmptyList[Name[Span.S]]]] = (comma(Name.variable) <* ` <- `).backtrack.? + val variables: P0[Option[NonEmptyList[Name[Span.S]]]] = + (comma(Name.variable) <* ` <- `).backtrack.? // TODO: Restrict to function call only // or allow any expression? diff --git a/parser/src/main/scala/aqua/parser/expr/func/CatchExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/CatchExpr.scala index 9be147d4..16164790 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/CatchExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/CatchExpr.scala @@ -5,10 +5,11 @@ import aqua.parser.expr.func.{CatchExpr, TryExpr} import aqua.parser.lexer.Name import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser -import cats.parse.Parser -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser +import cats.{Comonad, ~>} case class CatchExpr[F[_]](name: Name[F]) extends Expr[F](CatchExpr, name) { def mapK[K[_]: Comonad](fk: F ~> K): CatchExpr[K] = copy(name.mapK(fk)) diff --git a/parser/src/main/scala/aqua/parser/expr/func/ClosureExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ClosureExpr.scala index 9c5b5359..0360bd72 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ClosureExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ClosureExpr.scala @@ -4,13 +4,15 @@ import aqua.parser.expr.func.ArrowExpr import aqua.parser.lexer.Name import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser +import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} import aqua.parser.{Ast, Expr, ParserError} + import cats.data.{Validated, ValidatedNec} import cats.free.Cofree import cats.parse.Parser -import cats.{~>, Comonad} -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import cats.{Comonad, ~>} case class ClosureExpr[F[_]]( name: Name[F], diff --git a/parser/src/main/scala/aqua/parser/expr/func/CoExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/CoExpr.scala index a519fc65..eaec6d4a 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/CoExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/CoExpr.scala @@ -6,10 +6,11 @@ import aqua.parser.lexer.Token import aqua.parser.lexer.Token.`co` import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* -import cats.parse.Parser -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser +import cats.{Comonad, ~>} case class CoExpr[F[_]](point: Token[F]) extends Expr[F](CoExpr, point) { def mapK[K[_]: Comonad](fk: F ~> K): CoExpr[K] = copy(point.mapK(fk)) diff --git a/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala index ed2fedea..ee5bf7f0 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/DeclareStreamExpr.scala @@ -6,7 +6,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{BasicTypeToken, Name, Token, TypeToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.parse.Parser as P import cats.{Comonad, ~>} diff --git a/parser/src/main/scala/aqua/parser/expr/func/ElseOtherwiseExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ElseOtherwiseExpr.scala index e6337e0c..37bfbbfd 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ElseOtherwiseExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ElseOtherwiseExpr.scala @@ -6,12 +6,13 @@ import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.parse.Parser -import cats.{~>, Comonad} import cats.syntax.comonad.* import cats.syntax.functor.* -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import cats.{Comonad, ~>} case class ElseOtherwiseExpr[F[_]](kind: ElseOtherwiseExpr.Kind, point: Token[F]) extends Expr[F](ElseOtherwiseExpr, point) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ForExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ForExpr.scala index 0122deb8..25aadc85 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ForExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ForExpr.scala @@ -7,7 +7,7 @@ import aqua.parser.lexer.{Name, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.parse.Parser as P import cats.syntax.comonad.* diff --git a/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala index 7352b20c..1390719c 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/IfExpr.scala @@ -5,11 +5,12 @@ import aqua.parser.expr.func.{ForExpr, IfExpr} import aqua.parser.lexer.Token.* import aqua.parser.lexer.{LiteralToken, ValueToken} import aqua.parser.lift.LiftParser -import aqua.types.LiteralType -import cats.parse.Parser as P -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} +import aqua.types.LiteralType + +import cats.parse.Parser as P +import cats.{Comonad, ~>} case class IfExpr[F[_]](value: ValueToken[F]) extends Expr[F](IfExpr, value) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/JoinExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/JoinExpr.scala index 131f5cc3..bc8163be 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/JoinExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/JoinExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.expr.* import aqua.parser.lexer.Token.* import aqua.parser.lexer.{PropertyToken, ValueToken} +import aqua.parser.lift.Span.{given, *} import aqua.parser.lift.{LiftParser, Span} -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} -import cats.parse.Parser -import cats.{~>, Comonad} + import cats.data.NonEmptyList +import cats.parse.Parser +import cats.{Comonad, ~>} case class JoinExpr[F[_]](values: NonEmptyList[ValueToken[F]]) extends Expr[F](JoinExpr, values.head) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/OnExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/OnExpr.scala index 1569a886..0a56b909 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/OnExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/OnExpr.scala @@ -5,10 +5,11 @@ import aqua.parser.expr.* import aqua.parser.lexer.Token.* import aqua.parser.lexer.ValueToken import aqua.parser.lift.LiftParser -import cats.parse.Parser as P -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser as P +import cats.{Comonad, ~>} case class OnExpr[F[_]](peerId: ValueToken[F], via: List[ValueToken[F]]) extends Expr[F](OnExpr, peerId) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ParExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ParExpr.scala index a3cc342a..1c48a363 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ParExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ParExpr.scala @@ -6,10 +6,11 @@ import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* -import cats.parse.Parser -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser +import cats.{Comonad, ~>} case class ParExpr[F[_]](point: Token[F]) extends Expr[F](ParExpr, point) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ParSeqExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ParSeqExpr.scala index 7016263f..f5c7454c 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ParSeqExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ParSeqExpr.scala @@ -6,11 +6,12 @@ import aqua.parser.lexer.Token.{`parseq`, *} import aqua.parser.lexer.{Name, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.parse.Parser as P import cats.syntax.comonad.* -import cats.{~>, Comonad} -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import cats.{Comonad, ~>} case class ParSeqExpr[F[_]]( item: Name[F], diff --git a/parser/src/main/scala/aqua/parser/expr/func/PushToStreamExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/PushToStreamExpr.scala index b21af57e..84e91ad9 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/PushToStreamExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/PushToStreamExpr.scala @@ -5,10 +5,11 @@ import aqua.parser.expr.func.PushToStreamExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Name, ValueToken} import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.parse.Parser as P import cats.{Comonad, ~>} -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class PushToStreamExpr[F[_]]( stream: Name[F], diff --git a/parser/src/main/scala/aqua/parser/expr/func/ReturnExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ReturnExpr.scala index 242427b4..36e101fc 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ReturnExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ReturnExpr.scala @@ -5,11 +5,12 @@ import aqua.parser.expr.func.ReturnExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.ValueToken import aqua.parser.lift.LiftParser +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.data.NonEmptyList import cats.parse.Parser -import cats.{~>, Comonad} -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import cats.{Comonad, ~>} case class ReturnExpr[F[_]](values: NonEmptyList[ValueToken[F]]) extends Expr[F](ReturnExpr, values.head) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala index 79f9a85c..c710fbb6 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ServiceIdExpr.scala @@ -5,10 +5,11 @@ import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.Token.* import aqua.parser.lexer.{NamedTypeToken, ValueToken} import aqua.parser.lift.LiftParser -import cats.parse.Parser as P -import cats.{~>, Comonad} import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.parse.Parser as P +import cats.{Comonad, ~>} case class ServiceIdExpr[F[_]](service: NamedTypeToken[F], id: ValueToken[F]) extends Expr[F](ServiceIdExpr, service) { diff --git a/parser/src/main/scala/aqua/parser/expr/func/TryExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/TryExpr.scala index 9da55629..a5874c0a 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/TryExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/TryExpr.scala @@ -4,11 +4,12 @@ import aqua.parser.Expr import aqua.parser.expr.func.{IfExpr, TryExpr} import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* -import aqua.parser.lift.{LiftParser, Span} import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span.{given, *} +import aqua.parser.lift.{LiftParser, Span} + import cats.parse.Parser as P import cats.{Comonad, ~>} -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class TryExpr[F[_]](point: Token[F]) extends Expr[F](TryExpr, point) { diff --git a/parser/src/main/scala/aqua/parser/head/ExportExpr.scala b/parser/src/main/scala/aqua/parser/head/ExportExpr.scala index a8c561ed..854dacc4 100644 --- a/parser/src/main/scala/aqua/parser/head/ExportExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ExportExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{LiteralToken, Token, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.data.NonEmptyList diff --git a/parser/src/main/scala/aqua/parser/head/FromExpr.scala b/parser/src/main/scala/aqua/parser/head/FromExpr.scala index eda42bfb..a39ef048 100644 --- a/parser/src/main/scala/aqua/parser/head/FromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/FromExpr.scala @@ -1,16 +1,16 @@ package aqua.parser.head -import cats.Comonad -import cats.data.NonEmptyList -import cats.parse.Parser as P -import cats.~> -import cats.syntax.bifunctor.* - import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Ability, Name} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} + +import cats.Comonad +import cats.data.NonEmptyList +import cats.parse.Parser as P +import cats.syntax.bifunctor.* +import cats.~> trait FromExpr[F[_]] { def imports: NonEmptyList[FromExpr.NameOrAbAs[F]] diff --git a/parser/src/main/scala/aqua/parser/head/Header.scala b/parser/src/main/scala/aqua/parser/head/Header.scala index e1e5b4b0..67bc71a3 100644 --- a/parser/src/main/scala/aqua/parser/head/Header.scala +++ b/parser/src/main/scala/aqua/parser/head/Header.scala @@ -6,7 +6,7 @@ import aqua.parser.lexer.Token.` \n+` import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.data.Chain import cats.free.Cofree diff --git a/parser/src/main/scala/aqua/parser/head/HeaderExpr.scala b/parser/src/main/scala/aqua/parser/head/HeaderExpr.scala index 48a1b3b8..851fb479 100644 --- a/parser/src/main/scala/aqua/parser/head/HeaderExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/HeaderExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.Ast import aqua.parser.lexer.Token import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Show import cats.data.Chain diff --git a/parser/src/main/scala/aqua/parser/head/ImportExpr.scala b/parser/src/main/scala/aqua/parser/head/ImportExpr.scala index 5545a95e..ab4c3210 100644 --- a/parser/src/main/scala/aqua/parser/head/ImportExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ImportExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token._ import aqua.parser.lexer.{LiteralToken, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.parse.Parser diff --git a/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala b/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala index 98abd065..e69872c0 100644 --- a/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ImportFromExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{LiteralToken, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.data.NonEmptyList diff --git a/parser/src/main/scala/aqua/parser/head/ModuleExpr.scala b/parser/src/main/scala/aqua/parser/head/ModuleExpr.scala index f2943f90..3d63f5ad 100644 --- a/parser/src/main/scala/aqua/parser/head/ModuleExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/ModuleExpr.scala @@ -1,14 +1,16 @@ package aqua.parser.head +import aqua.parser.lexer.QName import aqua.parser.lexer.Token import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Ability, LiteralToken, Name, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad +import cats.data.NonEmptyList import cats.parse.Parser import cats.syntax.applicative.* import cats.syntax.comonad.* @@ -18,10 +20,8 @@ import cats.~> case class ModuleExpr[F[_]]( word: ModuleExpr.Word[F], - name: Ability[F], - declareAll: Option[Token[F]], - declareNames: List[Name[F]], - declareCustom: List[Ability[F]] + name: QName[F], + declares: Option[ModuleExpr.Declares[F]] ) extends HeaderExpr[F] { override def token: Token[F] = name @@ -29,14 +29,31 @@ case class ModuleExpr[F[_]]( copy( word = word.mapK(fk), name = name.mapK(fk), - declareAll = declareAll.map(_.mapK(fk)), - declareNames = declareNames.map(_.mapK(fk)), - declareCustom = declareCustom.map(_.mapK(fk)) + declares = declares.map(_.mapK(fk)) ) } object ModuleExpr extends HeaderExpr.Companion { + enum Declares[F[_]] { + case All(point: Token[F]) + case Names(names: NonEmptyList[QName[F]]) + + def mapK[K[_]: Comonad](fk: F ~> K): Declares[K] = this match { + case All(point) => All(point.mapK(fk)) + case Names(names) => Names(names.map(_.mapK(fk))) + } + } + + object Declares { + + val p: Parser[Declares[Span.S]] = + (`declares` ~ ` *`) *> ( + comma(QName.p).map(Names(_)) | + `star`.lift.map(Token.lift).map(All(_)) + ) + } + final case class Word[F[_]: Comonad]( token: F[Word.Kind] ) extends Token[F] { @@ -60,49 +77,21 @@ object ModuleExpr extends HeaderExpr.Companion { case Kind.Aqua => aqua } } - } - type NameOrAb[F[_]] = Either[Name[F], Ability[F]] - - private val nameOrAb: Parser[NameOrAb[Span.S]] = - Name.p.map(Left(_)) | Ability.ab.map(Right(_)) - - private val nameOrAbList: Parser[List[NameOrAb[Span.S]]] = - comma[NameOrAb[Span.S]](nameOrAb).map(_.toList) - - private val nameOrAbListOrAll: Parser[Either[List[NameOrAb[Span.S]], Token[Span.S]]] = - nameOrAbList.map(Left(_)) | (`star` <* ` *`).lift.map(Token.lift(_)).map(Right(_)) - - private val moduleWord: Parser[Word[Span.S]] = - (`module`.as(Word.Kind.Module).lift.backtrack | + val p = (`module`.as(Word.Kind.Module).lift.backtrack | `aqua-word`.as(Word.Kind.Aqua).lift).map(Word(_)) + } override val p: Parser[ModuleExpr[Span.S]] = ( - (` *`.with1 *> moduleWord) ~ - (` ` *> Ability.dotted) ~ - (` declares ` *> nameOrAbListOrAll).backtrack + (` *`.with1 *> Word.p) ~ + (` *` *> QName.p) ~ + (` *` *> Declares.p <* ` *`).backtrack .map(_.some) - .orElse(` *`.as(none)) // Allow trailing spaces - ).map { - case ((word, name), None) => - ModuleExpr(word, name, None, Nil, Nil) - case ((word, name), Some(Left(exportMembers))) => - ModuleExpr( - word, - name, - None, - exportMembers.collect { case Left(x) => x }, - exportMembers.collect { case Right(x) => x } - ) - case ((word, name), Some(Right(point))) => - ModuleExpr( - word, - name, - Some(point), - Nil, - Nil - ) + // Allow trailing spaces without `declares` + .orElse(` *`.as(none)) + ).map { case ((word, name), declares) => + ModuleExpr(word, name, declares) } } diff --git a/parser/src/main/scala/aqua/parser/head/UseExpr.scala b/parser/src/main/scala/aqua/parser/head/UseExpr.scala index 56ced035..b2f79fc2 100644 --- a/parser/src/main/scala/aqua/parser/head/UseExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/UseExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Ability, LiteralToken, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.parse.Parser @@ -25,7 +25,7 @@ case class UseExpr[F[_]]( object UseExpr extends HeaderExpr.Companion { override val p: Parser[HeaderExpr[Span.S]] = - (`use` *> ` ` *> ValueToken.string ~ (` as ` *> Ability.ab).?).map { + (`use` *> ` ` *> ValueToken.string ~ (` as ` *> Ability.dotted).?).map { case (filename, asModule) => UseExpr(filename, asModule) } diff --git a/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala b/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala index ca38a8b5..a530a7d6 100644 --- a/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala +++ b/parser/src/main/scala/aqua/parser/head/UseFromExpr.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lexer.{Ability, LiteralToken, Name, ValueToken} import aqua.parser.lift.LiftParser import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import cats.Comonad import cats.data.NonEmptyList @@ -27,9 +27,8 @@ case class UseFromExpr[F[_]]( object UseFromExpr extends HeaderExpr.Companion { override val p: Parser[UseFromExpr[Span.S]] = - (`use` *> FromExpr.importFrom.surroundedBy( - ` ` - ) ~ ValueToken.string ~ (` as ` *> Ability.ab)).map { case ((imports, filename), asModule) => + (`use` *> FromExpr.importFrom.surroundedBy(` `) ~ + ValueToken.string ~ (` as ` *> Ability.dotted)).map { case ((imports, filename), asModule) => UseFromExpr(imports, filename, asModule) } } diff --git a/parser/src/main/scala/aqua/parser/lexer/Ability.scala b/parser/src/main/scala/aqua/parser/lexer/Ability.scala index 7541e448..c7e239eb 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Ability.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Ability.scala @@ -3,13 +3,14 @@ package aqua.parser.lexer import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.Parser as P -import cats.syntax.functor.* import cats.syntax.comonad.* +import cats.syntax.functor.* import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class Ability[F[_]: Comonad](name: F[String]) extends Token[F] { override def as[T](v: T): F[T] = name.as(v) diff --git a/parser/src/main/scala/aqua/parser/lexer/Arg.scala b/parser/src/main/scala/aqua/parser/lexer/Arg.scala index 59aac4dc..2abfd374 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Arg.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Arg.scala @@ -1,11 +1,12 @@ package aqua.parser.lexer import aqua.parser.lift.LiftParser -import cats.parse.{Parser => P} +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import Token._ import cats.Comonad -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import cats.parse.{Parser => P} case class Arg[F[_]](name: Name[F], `type`: TypeToken[F]) diff --git a/parser/src/main/scala/aqua/parser/lexer/Name.scala b/parser/src/main/scala/aqua/parser/lexer/Name.scala index f2714e11..c2749cfd 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Name.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Name.scala @@ -1,15 +1,16 @@ package aqua.parser.lexer -import aqua.parser.lexer.Token._ +import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser -import aqua.parser.lift.LiftParser._ +import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + import cats.Comonad import cats.parse.{Parser => P} -import cats.syntax.functor._ -import cats.syntax.comonad._ +import cats.syntax.comonad.* +import cats.syntax.functor.* import cats.~> -import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} case class Name[F[_]: Comonad](name: F[String]) extends Token[F] { override def as[T](v: T): F[T] = name.as(v) diff --git a/parser/src/main/scala/aqua/parser/lexer/PropertyOp.scala b/parser/src/main/scala/aqua/parser/lexer/PropertyOp.scala index 049b87bb..014b0984 100644 --- a/parser/src/main/scala/aqua/parser/lexer/PropertyOp.scala +++ b/parser/src/main/scala/aqua/parser/lexer/PropertyOp.scala @@ -6,7 +6,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import aqua.types.LiteralType import cats.data.{NonEmptyList, NonEmptyMap} diff --git a/parser/src/main/scala/aqua/parser/lexer/QName.scala b/parser/src/main/scala/aqua/parser/lexer/QName.scala new file mode 100644 index 00000000..9a01fcf3 --- /dev/null +++ b/parser/src/main/scala/aqua/parser/lexer/QName.scala @@ -0,0 +1,55 @@ +package aqua.parser.lexer + +import aqua.helpers.data.PName +import aqua.parser.lexer.Token.* +import aqua.parser.lift.LiftParser +import aqua.parser.lift.LiftParser.* +import aqua.parser.lift.Span +import aqua.parser.lift.Span.{given, *} + +import cats.Comonad +import cats.arrow.FunctionK +import cats.data.NonEmptyList +import cats.parse.{Parser => P} +import cats.syntax.comonad.* +import cats.syntax.functor.* + +/** + * Qualified name. Name with parts separated by `.` + * e.g. `Some.Imported.Module.foo` + * + * @param name Name as a whole + * @param parts Parts of the name + */ +final case class QName[F[_]: Comonad]( + name: F[String], + parts: NonEmptyList[F[String]] +) extends Token[F] { + + def value: String = name.extract + override def as[T](v: T): F[T] = name.as(v) + + override def mapK[K[_]: Comonad](fk: FunctionK[F, K]): QName[K] = + copy(fk(name), parts.map(p => fk(p))) + + def toPName: PName = PName(parts.map(_.extract)) +} + +object QName { + + final case class As[F[_]: Comonad]( + name: QName[F], + rename: Option[QName[F]] + ) + + val p: P[QName[Span.S]] = + anyName.lift + .repSep(`.`) + .withString + .lift + .map(span => { + val name = span.fmap { case (_, name) => name } + val parts = span.fmap { case (parts, _) => parts }.extract + QName(name, parts) + }) +} diff --git a/parser/src/main/scala/aqua/parser/lexer/Token.scala b/parser/src/main/scala/aqua/parser/lexer/Token.scala index 7f65dc9b..3490afd0 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Token.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Token.scala @@ -39,7 +39,6 @@ object Token { val `module`: P[Unit] = P.string("module") val `aqua-word`: P[Unit] = P.string("aqua") val `declares`: P[Unit] = P.string("declares") - val ` declares ` : P[Unit] = `declares`.surroundedBy(` `) val `declare`: P[Unit] = P.string("declare") val `_export`: P[Unit] = P.string("export") val `star`: P[Unit] = P.char('*') diff --git a/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala b/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala index f9e7f2f6..894ff06a 100644 --- a/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala +++ b/parser/src/main/scala/aqua/parser/lexer/TypeToken.scala @@ -4,7 +4,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan, S} +import aqua.parser.lift.Span.{given, *} import aqua.types.ScalarType import cats.Comonad diff --git a/parser/src/main/scala/aqua/parser/lexer/ValueToken.scala b/parser/src/main/scala/aqua/parser/lexer/ValueToken.scala index 6fdbfcb1..e062e4fa 100644 --- a/parser/src/main/scala/aqua/parser/lexer/ValueToken.scala +++ b/parser/src/main/scala/aqua/parser/lexer/ValueToken.scala @@ -6,7 +6,7 @@ import aqua.parser.lexer.Token.* import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser.* import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan, S} +import aqua.parser.lift.Span.{given, *} import aqua.types.LiteralType import cats.arrow.FunctionK diff --git a/parser/src/main/scala/aqua/parser/lift/LiftParser.scala b/parser/src/main/scala/aqua/parser/lift/LiftParser.scala index e17f9ca9..46701042 100644 --- a/parser/src/main/scala/aqua/parser/lift/LiftParser.scala +++ b/parser/src/main/scala/aqua/parser/lift/LiftParser.scala @@ -13,25 +13,23 @@ trait LiftParser[S[_]] { object LiftParser { - implicit class LiftErrorOps[S[_]: LiftParser, T](e: Parser.Error) { - def wrapErr: S[Parser.Error] = implicitly[LiftParser[S]].wrapErr(e) + def apply[S[_]](using lp: LiftParser[S]): LiftParser[S] = lp + + extension [S[_]: LiftParser, T](e: Parser.Error) { + def wrapErr: S[Parser.Error] = LiftParser[S].wrapErr(e) } - implicit class LiftParserOps[S[_]: LiftParser, T](parser: Parser[T]) { - def lift: Parser[S[T]] = implicitly[LiftParser[S]].lift(parser) + extension [S[_]: LiftParser, T](parser: Parser[T]) { + def lift: Parser[S[T]] = LiftParser[S].lift(parser) } - implicit class LiftParser0Ops[S[_]: LiftParser, T](parser0: Parser0[T]) { - def lift0: Parser0[S[T]] = implicitly[LiftParser[S]].lift0(parser0) + extension [S[_]: LiftParser, T](parser0: Parser0[T]) { + def lift0: Parser0[S[T]] = LiftParser[S].lift0(parser0) } - object Implicits { - - implicit object idLiftParser extends LiftParser[Id] { - override def lift[T](p: Parser[T]): Parser[Id[T]] = p - override def lift0[T](p0: Parser0[T]): Parser0[Id[T]] = p0 - override def wrapErr(e: Parser.Error): Id[Parser.Error] = e - } - + given LiftParser[Id] with { + override def lift[T](p: Parser[T]): Parser[Id[T]] = p + override def lift0[T](p0: Parser0[T]): Parser0[Id[T]] = p0 + override def wrapErr(e: Parser.Error): Id[Parser.Error] = e } } diff --git a/parser/src/main/scala/aqua/parser/lift/Span.scala b/parser/src/main/scala/aqua/parser/lift/Span.scala index 090603e2..1189552a 100644 --- a/parser/src/main/scala/aqua/parser/lift/Span.scala +++ b/parser/src/main/scala/aqua/parser/lift/Span.scala @@ -1,8 +1,7 @@ package aqua.parser.lift import cats.Comonad -import cats.parse.{LocationMap, Parser0, Parser as P} - +import cats.parse.{LocationMap, Parser as P, Parser0} import scala.language.implicitConversions case class Span(startIndex: Int, endIndex: Int) { @@ -131,7 +130,7 @@ object Span { type S[T] = (Span, T) - implicit object spanComonad extends Comonad[S] { + given Comonad[S] with { override def extract[A](x: S[A]): A = x._2 override def coflatMap[A, B](fa: S[A])(f: S[A] ⇒ B): S[B] = fa.copy(_2 = f(fa)) @@ -139,15 +138,7 @@ object Span { override def map[A, B](fa: S[A])(f: A ⇒ B): S[B] = fa.copy(_2 = f(fa._2)) } - implicit class PToSpan[T](p: P[T]) { - def lift: P[Span.S[T]] = Span.spanLiftParser.lift(p) - } - - implicit class P0ToSpan[T](p: Parser0[T]) { - def lift0: Parser0[Span.S[T]] = Span.spanLiftParser.lift0(p) - } - - implicit object spanLiftParser extends LiftParser[S] { + given LiftParser[S] with { override def lift[T](p: P[T]): P[S[T]] = (P.index.with1 ~ p ~ P.index).map { case ((s, v), e) ⇒ diff --git a/parser/src/test/scala/aqua/AquaSpec.scala b/parser/src/test/scala/aqua/AquaSpec.scala index 1b85fd56..9f22808b 100644 --- a/parser/src/test/scala/aqua/AquaSpec.scala +++ b/parser/src/test/scala/aqua/AquaSpec.scala @@ -11,9 +11,9 @@ import aqua.parser.lexer.InfixToken.Op as InfixOp import aqua.parser.lexer.PrefixToken.Op.* import aqua.parser.lexer.PrefixToken.Op as PrefixOp import aqua.parser.lexer.Token.LiftToken -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given import aqua.parser.lift.Span -import aqua.parser.lift.Span.{P0ToSpan, PToSpan} +import aqua.parser.lift.Span.{given, *} import aqua.types.LiteralType.{bool, number, signed, string, unsigned} import aqua.types.{LiteralType, ScalarType} @@ -40,6 +40,11 @@ object AquaSpec { def toAb(str: String): Ability[Id] = Ability[Id](str) + def toQName(str: String): QName[Id] = QName[Id]( + str, + NonEmptyList.fromListUnsafe(str.split("\\.").toList) + ) + def toVar(name: String): VarToken[Id] = VarToken[Id](toName(name)) def toVarOp(name: Option[String]): Option[VarToken[Id]] = diff --git a/parser/src/test/scala/aqua/parser/CoExprSpec.scala b/parser/src/test/scala/aqua/parser/CoExprSpec.scala index 5f5bead0..a93ee34e 100644 --- a/parser/src/test/scala/aqua/parser/CoExprSpec.scala +++ b/parser/src/test/scala/aqua/parser/CoExprSpec.scala @@ -4,14 +4,14 @@ import aqua.AquaSpec import aqua.AquaSpec.* import aqua.parser.expr.func.{CallArrowExpr, CoExpr, ForExpr, JoinExpr, OnExpr} import aqua.parser.lexer.{CallArrowToken, Token} -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given import cats.data.{Chain, NonEmptyList} import cats.free.Cofree import cats.{Eval, Id} +import org.scalatest.Inside import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -import org.scalatest.Inside class CoExprSpec extends AnyFlatSpec with Matchers with Inside with AquaSpec { diff --git a/parser/src/test/scala/aqua/parser/ParExprSpec.scala b/parser/src/test/scala/aqua/parser/ParExprSpec.scala index 9d962899..65f7342f 100644 --- a/parser/src/test/scala/aqua/parser/ParExprSpec.scala +++ b/parser/src/test/scala/aqua/parser/ParExprSpec.scala @@ -4,14 +4,14 @@ import aqua.AquaSpec import aqua.AquaSpec.* import aqua.parser.expr.func.{CallArrowExpr, ForExpr, JoinExpr, OnExpr, ParExpr} import aqua.parser.lexer.{CallArrowToken, Token} -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import org.scalatest.Inside -import cats.{Eval, Id} import cats.data.{Chain, NonEmptyList} import cats.free.Cofree +import cats.{Eval, Id} +import org.scalatest.Inside +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers class ParExprSpec extends AnyFlatSpec with Matchers with Inside with AquaSpec { diff --git a/parser/src/test/scala/aqua/parser/head/FromSpec.scala b/parser/src/test/scala/aqua/parser/head/FromSpec.scala index 16e65fbb..1f5d0e78 100644 --- a/parser/src/test/scala/aqua/parser/head/FromSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/FromSpec.scala @@ -3,8 +3,9 @@ package aqua.parser.head import aqua.AquaSpec import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} -import aqua.parser.lift.LiftParser.Implicits.* +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType + import cats.Id import cats.data.NonEmptyList import org.scalatest.flatspec.AnyFlatSpec diff --git a/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala b/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala index e5f90393..0eee238a 100644 --- a/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/ImportFromSpec.scala @@ -3,7 +3,7 @@ package aqua.parser.head import aqua.AquaSpec import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} -import aqua.parser.lift.LiftParser.Implicits.* +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType import cats.Id diff --git a/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala b/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala index dfefbfa3..6c418cf3 100644 --- a/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/ModuleSpec.scala @@ -3,10 +3,11 @@ package aqua.parser.head import aqua.AquaSpec import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} -import aqua.parser.lift.LiftParser.Implicits.* +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType import cats.Id +import cats.data.NonEmptyList import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers @@ -15,20 +16,17 @@ class ModuleSpec extends AnyFlatSpec with Matchers with AquaSpec { val myModule = ModuleExpr( ModuleExpr.Word[Id](Id(ModuleExpr.Word.Kind.Aqua)), - toAb("MyModule"), - None, - Nil, - Nil + toQName("MyModule"), + None ) val declaresAll = myModule.copy( - declareAll = Some(Token.lift[Id, Unit](())) + declares = Some(ModuleExpr.Declares.All(Token.lift[Id, Unit](()))) ) def declares(symbols: List[String]) = myModule.copy( - declareNames = symbols.filter(_.headOption.exists(_.isLower)).map(toName), - declareCustom = symbols.filter(_.headOption.exists(_.isUpper)).map(toAb) + declares = Some(ModuleExpr.Declares.Names(NonEmptyList.fromListUnsafe(symbols.map(toQName)))) ) def parseModuleExpr(expr: String): ModuleExpr[Id] = diff --git a/parser/src/test/scala/aqua/parser/head/UseSpec.scala b/parser/src/test/scala/aqua/parser/head/UseSpec.scala index a4321452..06cfe530 100644 --- a/parser/src/test/scala/aqua/parser/head/UseSpec.scala +++ b/parser/src/test/scala/aqua/parser/head/UseSpec.scala @@ -3,8 +3,9 @@ package aqua.parser.head import aqua.AquaSpec import aqua.parser.expr.func.ServiceIdExpr import aqua.parser.lexer.{LiteralToken, Token} -import aqua.parser.lift.LiftParser.Implicits.* +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType + import cats.Id import cats.data.NonEmptyList import org.scalatest.flatspec.AnyFlatSpec diff --git a/parser/src/test/scala/aqua/parser/lexer/PropertyOpSpec.scala b/parser/src/test/scala/aqua/parser/lexer/PropertyOpSpec.scala index 21f86cef..ae9b0879 100644 --- a/parser/src/test/scala/aqua/parser/lexer/PropertyOpSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/PropertyOpSpec.scala @@ -1,7 +1,8 @@ package aqua.parser.lexer -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType + import cats.Id import cats.data.{NonEmptyList, NonEmptyMap} import org.scalatest.EitherValues diff --git a/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala b/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala index f40f54c5..10ea49ce 100644 --- a/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/TypeTokenSpec.scala @@ -1,6 +1,6 @@ package aqua.parser.lexer -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given import aqua.types.ScalarType import cats.Id diff --git a/parser/src/test/scala/aqua/parser/lexer/ValueTokenSpec.scala b/parser/src/test/scala/aqua/parser/lexer/ValueTokenSpec.scala index 6a584d3c..38af030f 100644 --- a/parser/src/test/scala/aqua/parser/lexer/ValueTokenSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/ValueTokenSpec.scala @@ -1,13 +1,13 @@ package aqua.parser.lexer -import org.scalatest.EitherValues -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatest.matchers.should.Matchers -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given import aqua.types.LiteralType import cats.Id import cats.data.NonEmptyList +import org.scalatest.EitherValues +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers class ValueTokenSpec extends AnyFlatSpec with Matchers with EitherValues { diff --git a/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala b/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala index 1dab5e71..890d726d 100644 --- a/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala +++ b/parser/src/test/scala/aqua/parser/lexer/VarLambdaSpec.scala @@ -1,6 +1,7 @@ package aqua.parser.lexer -import aqua.parser.lift.LiftParser.Implicits.idLiftParser +import aqua.parser.lift.LiftParser.given + import cats.Id import cats.data.NonEmptyList import org.scalatest.EitherValues diff --git a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala index f5a1217d..8767a783 100644 --- a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala +++ b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala @@ -23,8 +23,8 @@ case class HeaderSem[S[_], C]( object HeaderSem { - def fromInit[S[_], C](init: C): HeaderSem[S, C] = - HeaderSem(init, c => c.validNec) + def fromInit[S[_], C: Monoid](init: C): HeaderSem[S, C] = + HeaderSem(init, _ => Monoid[C].empty.validNec) given [S[_]: Comonad, C](using rc: Monoid[C] diff --git a/semantics/src/main/scala/aqua/semantics/header/ModuleSem.scala b/semantics/src/main/scala/aqua/semantics/header/ModuleSem.scala index d7756a94..712b2243 100644 --- a/semantics/src/main/scala/aqua/semantics/header/ModuleSem.scala +++ b/semantics/src/main/scala/aqua/semantics/header/ModuleSem.scala @@ -1,5 +1,6 @@ package aqua.semantics.header +import aqua.helpers.data.PName import aqua.parser.head.ModuleExpr import aqua.semantics.header.HeaderHandler.{Res, error} import aqua.semantics.header.Picker.* @@ -19,40 +20,41 @@ class ModuleSem[S[_]: Comonad, C: Picker](expr: ModuleExpr[S])(using locations: LocationsAlgebra[S, State[C, *]] ) { - import expr.* - def headerSem: Res[S, C] = { lazy val sem = HeaderSem( // Save module header info - Picker[C].blank.setModule(name.value), + Picker[C].blank.setModule(expr.name.value.some), ctx => - // When file is handled, check that all the declarations exists - if (declareAll.nonEmpty) ctx.setDeclares(ctx.allNames).validNec - else { - val declares = declareNames.fproductLeft(_.value) ::: declareCustom.fproductLeft(_.value) - val names = declares.map { case (name, _) => name }.toSet - val res = ctx.setDeclares(names).addOccurences(declares) + expr.declares match { + case None => ctx.validNec + case Some(ModuleExpr.Declares.All(_)) => + val names = ctx.allNames.map(PName.simpleUnsafe).toSet + ctx.setDeclares(names).validNec + case Some(ModuleExpr.Declares.Names(declareNames)) => + val declares = declareNames.fproductLeft(_.value).toList + val names = declareNames.map(_.toPName).toList.toSet + val res = ctx.setDeclares(names).addOccurences(declares) - // summarize contexts to allow redeclaration of imports - declares.map { case (n, t) => - res - .pick(n, None, ctx.module.nonEmpty) - .toValidNec( - error( - t, - s"`$n` is expected to be declared, but declaration is not found in the file" + // summarize contexts to allow redeclaration of imports + declares.map { case (n, t) => + res + .pick(t.toPName, ctx.module.nonEmpty) + .toValidNec( + error( + t, + s"`$n` is expected to be declared, but declaration is not found in the file" + ) ) - ) - .void - // TODO: Should not it be possible to make `.combineAll` the final result? - // Seems like `.pick` does not return much information - }.combineAll.as(res) + .void + // TODO: Should not it be possible to make `.combineAll` the final result? + // Seems like `.pick` does not return much information + }.combineAll.as(res) } ) - word.value.fold( + expr.word.value.fold( module = error( - word, + expr.word, "Keyword `module` is deprecated, use `aqua` instead" ).invalidNec, aqua = sem.validNec diff --git a/semantics/src/main/scala/aqua/semantics/header/Picker.scala b/semantics/src/main/scala/aqua/semantics/header/Picker.scala index 79305af0..d6c25865 100644 --- a/semantics/src/main/scala/aqua/semantics/header/Picker.scala +++ b/semantics/src/main/scala/aqua/semantics/header/Picker.scala @@ -1,5 +1,6 @@ package aqua.semantics.header +import aqua.helpers.data.PName import aqua.raw.{RawContext, RawPart} import aqua.types.{AbilityType, ArrowType, Type} @@ -13,6 +14,7 @@ trait Picker[A] { def definedAbilityNames(ctx: A): Set[String] def blank: A def pick(ctx: A, name: String, rename: Option[String], declared: Boolean): Option[A] + def pick(ctx: A, name: PName, declared: Boolean): Option[A] def pickDeclared(ctx: A): A def pickHeader(ctx: A): A def module(ctx: A): Option[String] @@ -24,8 +26,8 @@ trait Picker[A] { def funcAcceptAbility(ctx: A, name: String): Boolean def setAbility(ctx: A, name: String, ctxAb: A): A def setImportPaths(ctx: A, importPaths: Map[String, String]): A - def setModule(ctx: A, name: String): A - def setDeclares(ctx: A, declares: Set[String]): A + def setModule(ctx: A, name: Option[String]): A + def setDeclares(ctx: A, declares: Set[PName]): A def setExports(ctx: A, exports: Map[String, Option[String]]): A def addPart(ctx: A, part: (A, RawPart)): A } @@ -41,6 +43,10 @@ object Picker { def pick(name: String, rename: Option[String], declared: Boolean): Option[A] = Picker[A].pick(p, name, rename, declared) + + def pick(name: PName, declared: Boolean): Option[A] = + Picker[A].pick(p, name, declared) + def pickDeclared: A = Picker[A].pickDeclared(p) def pickHeader: A = Picker[A].pickHeader(p) def module: Option[String] = Picker[A].module(p) @@ -65,10 +71,10 @@ object Picker { def addFreeParts(parts: List[RawPart]): A = parts.foldLeft(p) { case (ctx, part) => ctx.addPart(blank -> part) } - def setModule(name: String): A = + def setModule(name: Option[String]): A = Picker[A].setModule(p, name) - def setDeclares(declares: Set[String]): A = + def setDeclares(declares: Set[PName]): A = Picker[A].setDeclares(p, declares) def setExports(exports: Map[String, Option[String]]): A = @@ -130,10 +136,10 @@ object Picker { override def setImportPaths(ctx: RawContext, importPaths: Map[String, String]): RawContext = ctx - override def setModule(ctx: RawContext, name: String): RawContext = - ctx.copy(module = Some(name)) + override def setModule(ctx: RawContext, name: Option[String]): RawContext = + ctx.copy(module = name) - override def setDeclares(ctx: RawContext, declares: Set[String]): RawContext = + override def setDeclares(ctx: RawContext, declares: Set[PName]): RawContext = ctx.copy(declares = declares) override def setExports(ctx: RawContext, exports: Map[String, Option[String]]): RawContext = @@ -146,13 +152,39 @@ object Picker { declared: Boolean ): Option[RawContext] = Option - .when(!declared || ctx.declares(name)) { - RawContext.blank - .copy(parts = ctx.parts.filter(_._2.name == name).map { case (partContext, part) => - (partContext, rename.fold(part)(part.rename)) - }) + .when(!declared || ctx.declaredNames(name)) { + RawContext.fromParts( + ctx.parts.collect { + case (partContext, part) if part.name == name => + (partContext, rename.fold(part)(part.rename)) + } + ) } .filter(_.nonEmpty) + .map( + // Module and declares should not be lost when picking + // Because it affects later logic + _.setModule(ctx.module).setDeclares(Set(PName.simpleUnsafe(name))) + ) + + override def pick( + ctx: RawContext, + name: PName, + declared: Boolean + ): Option[RawContext] = + name.simple.fold( + name.splits.collectFirstSome { case (ab, field) => + for { + ability <- ctx.abilities.get(ab.value) + inner <- pick(ability, field, declared) + } yield RawContext + .fromAbilities(Map(ab.value -> inner)) + // Module and declares should not be lost when picking + // Because it affects later logic + .setModule(ctx.module) + .setDeclares(Set(name)) + } + )(pick(ctx, _, None, declared)) override def pickHeader(ctx: RawContext): RawContext = RawContext.blank.copy(module = ctx.module, declares = ctx.declares, exports = ctx.exports) @@ -161,7 +193,7 @@ object Picker { if (ctx.module.isEmpty) ctx else ctx.declares.toList - .flatMap(n => pick(ctx, n, None, ctx.module.nonEmpty)) + .flatMap(n => pick(ctx, n, ctx.module.nonEmpty)) .foldLeft(pickHeader(ctx))(_ |+| _) } diff --git a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala index 86c67c87..9f754475 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/ValuesAlgebra.scala @@ -154,7 +154,12 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](using .filterF(nv => T.resolveType(nv.typeName, mustBeDefined = false).map(_.isDefined)) .widen[ValueToken[S]] - callArrow.orElse(ability).orElse(namedValue).foldF(default)(valueToRaw) + callArrow + .orElse(ability) + .orElse(namedValue) + .foldF(default)( + valueToRaw + ) case dvt @ NamedValueToken(typeName, fields) => (for { diff --git a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala index 4f7604b5..e6d4c84f 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesInterpreter.scala @@ -13,8 +13,8 @@ import aqua.types.ArrowType import cats.data.* import cats.syntax.applicative.* import cats.syntax.apply.* -import cats.syntax.functor.* import cats.syntax.flatMap.* +import cats.syntax.functor.* import cats.syntax.option.* import monocle.Lens import monocle.macros.GenLens diff --git a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesState.scala b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesState.scala index 01dbfe0a..c1251d1f 100644 --- a/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesState.scala +++ b/semantics/src/main/scala/aqua/semantics/rules/abilities/AbilitiesState.scala @@ -66,6 +66,6 @@ object AbilitiesState { rootServiceIds = context.allServices.flatMap { case (name, service) => service.defaultId.map(name -> _) }, - abilities = context.abilities // TODO is it the right way to collect abilities? Why? + abilities = context.allAbilities ) } diff --git a/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala b/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala index 85bdea73..b04614fc 100644 --- a/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala +++ b/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala @@ -2,6 +2,7 @@ package aqua.semantics import aqua.parser.Ast import aqua.parser.head.{ExportExpr, FromExpr, HeaderExpr, ModuleExpr} +import aqua.parser.lexer.QName import aqua.parser.lexer.Token import aqua.parser.lexer.{Ability, Name} import aqua.raw.RawContext @@ -38,11 +39,9 @@ class HeaderSpec extends AnyFlatSpec with Matchers with Inside { Token.lift(()), Chain( ModuleExpr( - word = ModuleExpr.Word[Id](Id(ModuleExpr.Word.Kind.Aqua)), - name = Ability[Id]("TestModule"), - declareAll = None, - declareNames = Nil, - declareCustom = Nil + word = ModuleExpr.Word(ModuleExpr.Word.Kind.Aqua), + name = QName("TestModule", NonEmptyList.one("TestModule")), + declares = None ), ExportExpr(NonEmptyList.of(exp)) ) diff --git a/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala b/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala index 0e328f64..4f3a142b 100644 --- a/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala +++ b/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala @@ -28,7 +28,6 @@ class SemanticsSpec extends AnyFlatSpec with Matchers with Inside { val emptyCall = Call(Nil, Nil) - implicit val fileLift: LiftParser[Span.S] = Span.spanLiftParser val parser = Parser.parse(Parser.spanParser) val semantics = new RawSemantics[Span.S]() diff --git a/utils/helpers/src/main/scala/aqua/helpers/data/PName.scala b/utils/helpers/src/main/scala/aqua/helpers/data/PName.scala new file mode 100644 index 00000000..c09fdf98 --- /dev/null +++ b/utils/helpers/src/main/scala/aqua/helpers/data/PName.scala @@ -0,0 +1,39 @@ +package aqua.helpers.data + +import aqua.errors.Errors.internalError + +import cats.data.NonEmptyList +import cats.syntax.option.* + +/** + * Short for PathName. Represents name with parts separated by `.` + */ +final case class PName( + parts: NonEmptyList[String] +) { + + lazy val simple: Option[String] = + Option.when(parts.length == 1)(parts.head) + + lazy val isSimple: Boolean = simple.isDefined + + lazy val value: String = parts.toList.mkString(".") + + lazy val splits: List[(PName, PName)] = { + val partsList = parts.toList + (1 until parts.length).toList.map(i => + PName(NonEmptyList.fromListUnsafe(partsList.take(i))) -> + PName(NonEmptyList.fromListUnsafe(partsList.drop(i))) + ) + } + + override def toString(): String = value +} + +object PName { + + def simpleUnsafe(name: String): PName = + if (name.isEmpty || name.contains(".")) + internalError(s"Invalid PName: $name") + else PName(NonEmptyList.one(name)) +}