diff --git a/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala b/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala index 6b91fd389..979d25695 100644 --- a/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala +++ b/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala @@ -8,19 +8,19 @@ import aqua.parser.{Ast, ParserError} import aqua.raw.RawPart.Parts import aqua.raw.{RawContext, RawPart} import aqua.res.AquaRes -import aqua.semantics.{CompilerState, RawSemantics, Semantics} import aqua.semantics.header.{HeaderHandler, HeaderSem} +import aqua.semantics.{CompilerState, RawSemantics, Semantics} import cats.data.* -import cats.data.Validated.{invalid, validNec, Invalid, Valid} +import cats.data.Validated.{Invalid, Valid, invalid, validNec} import cats.parse.Parser0 import cats.syntax.applicative.* import cats.syntax.flatMap.* +import cats.syntax.foldable.* import cats.syntax.functor.* import cats.syntax.monoid.* -import cats.syntax.traverse.* import cats.syntax.semigroup.* -import cats.syntax.foldable.* -import cats.{~>, Comonad, Monad, Monoid, Order} +import cats.syntax.traverse.* +import cats.{Comonad, Monad, Monoid, Order, ~>} import scribe.Logging import scala.collection.MapView @@ -63,8 +63,6 @@ object CompilerAPI extends Logging { ) .rawContextMonoid - implicit val headerSemMonoid: Monoid[HeaderSem[S, RawContext]] = HeaderSem.headerSemMonoid[S] - val semantics = new RawSemantics[S]() new AquaCompiler[F, E, I, S, RawContext](new HeaderHandler[S, RawContext](), semantics) 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 72b002729..ad0303ad7 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 @@ -57,7 +57,7 @@ object LspContext { override def blank: LspContext[S] = LspContext[S](Picker[RawContext].blank, Map.empty) override def exports(ctx: LspContext[S]): Option[Map[String, Option[String]]] = ops(ctx).exports - override def funcReturnAbilityOrArrow(name: String, ctx: LspContext[S]): Boolean = + override def funcReturnAbilityOrArrow(ctx: LspContext[S], name: String): Boolean = ops(ctx).funcReturnAbilityOrArrow(name) override def funcNames(ctx: LspContext[S]): List[String] = ops(ctx).funcNames @@ -126,7 +126,7 @@ object LspContext { override def pickDeclared( ctx: LspContext[S] - )(implicit semi: Semigroup[LspContext[S]]): LspContext[S] = + )(using Semigroup[LspContext[S]]): LspContext[S] = ctx.copy(raw = ops(ctx).pickDeclared) } } diff --git a/semantics/src/main/scala/aqua/semantics/header/HeaderHandler.scala b/semantics/src/main/scala/aqua/semantics/header/HeaderHandler.scala index c615b3a63..f58d367e2 100644 --- a/semantics/src/main/scala/aqua/semantics/header/HeaderHandler.scala +++ b/semantics/src/main/scala/aqua/semantics/header/HeaderHandler.scala @@ -3,18 +3,18 @@ package aqua.semantics.header import aqua.parser.Ast import aqua.parser.head.* import aqua.parser.lexer.{Ability, Token} -import aqua.raw.RawContext import aqua.semantics.header.Picker.* import aqua.semantics.{HeaderError, SemanticError} -import cats.data.Validated.{invalidNec, validNec, Invalid, Valid} import cats.data.* +import cats.data.Validated.{invalidNec, validNec} import cats.free.Cofree import cats.instances.list.* import cats.instances.option.* import cats.kernel.Semigroup import cats.syntax.foldable.* -import cats.syntax.monoid +import cats.syntax.functor.* import cats.syntax.semigroup.* +import cats.syntax.validated.* import cats.{Comonad, Eval, Monoid} class HeaderHandler[S[_]: Comonad, C](implicit @@ -115,15 +115,15 @@ class HeaderHandler[S[_]: Comonad, C](implicit ctx .pick(n, None, ctx.module.nonEmpty) // We just validate, nothing more - .map(_ => validNec(1)) + .as(validNec(1)) .getOrElse( error( t, - s"`${n}` is expected to be declared, but declaration is not found in the file" + s"`$n` is expected to be declared, but declaration is not found in the file" ) ) }.combineAll - .map(_ => + .as( // TODO: why module name and declares is lost? where is it lost? ctx.setModule(name.value, declares = shouldDeclare) ) @@ -183,8 +183,7 @@ class HeaderHandler[S[_]: Comonad, C](implicit else sumCtx .pick(name, rename, declared = false) - .map(_ => Map(name -> rename)) - .map(validNec) + .as(Map(name -> rename).validNec) .getOrElse( error( token, diff --git a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala index 15e9887a4..1343b45a7 100644 --- a/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala +++ b/semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala @@ -18,19 +18,18 @@ case class HeaderSem[S[_], C]( object HeaderSem { - implicit def headerSemMonoid[S[_]: Comonad](implicit + given [S[_]: Comonad](using rc: Monoid[RawContext] - ): Monoid[HeaderSem[S, RawContext]] = - new Monoid[HeaderSem[S, RawContext]] { - override def empty: HeaderSem[S, RawContext] = HeaderSem(rc.empty, (c, _) => validNec(c)) + ): Monoid[HeaderSem[S, RawContext]] with { + override def empty: HeaderSem[S, RawContext] = HeaderSem(rc.empty, (c, _) => validNec(c)) - override def combine( - a: HeaderSem[S, RawContext], - b: HeaderSem[S, RawContext] - ): HeaderSem[S, RawContext] = - HeaderSem( - a.initCtx |+| b.initCtx, - (c, i) => a.finInitCtx(c, i).andThen(b.finInitCtx(_, i)) - ) - } + override def combine( + a: HeaderSem[S, RawContext], + b: HeaderSem[S, RawContext] + ): HeaderSem[S, RawContext] = + HeaderSem( + a.initCtx |+| b.initCtx, + (c, i) => a.finInitCtx(c, i).andThen(b.finInitCtx(_, i)) + ) + } } diff --git a/semantics/src/main/scala/aqua/semantics/header/Picker.scala b/semantics/src/main/scala/aqua/semantics/header/Picker.scala index 7f9121bae..d7a8e557b 100644 --- a/semantics/src/main/scala/aqua/semantics/header/Picker.scala +++ b/semantics/src/main/scala/aqua/semantics/header/Picker.scala @@ -16,7 +16,7 @@ trait Picker[A] { def pickHeader(ctx: A): A def module(ctx: A): Option[String] def exports(ctx: A): Option[Map[String, Option[String]]] - def funcReturnAbilityOrArrow(name: String, ctx: A): Boolean + def funcReturnAbilityOrArrow(ctx: A, name: String): Boolean def declares(ctx: A): Set[String] def setAbility(ctx: A, name: String, ctxAb: A): A def setModule(ctx: A, name: Option[String], declares: Set[String]): A @@ -37,7 +37,7 @@ final class PickerOps[A: Picker](p: A) { def pickHeader: A = Picker[A].pickHeader(p) def module: Option[String] = Picker[A].module(p) def exports: Option[Map[String, Option[String]]] = Picker[A].exports(p) - def funcReturnAbilityOrArrow(name: String): Boolean = Picker[A].funcReturnAbilityOrArrow(name, p) + def funcReturnAbilityOrArrow(name: String): Boolean = Picker[A].funcReturnAbilityOrArrow(p, name) def declares: Set[String] = Picker[A].declares(p) def setAbility(name: String, ctx: A): A = Picker[A].setAbility(p, name, ctx) def setInit(ctx: Option[A]): A = Picker[A].setInit(p, ctx) @@ -55,7 +55,7 @@ final class PickerOps[A: Picker](p: A) { object Picker { - def typeContainsAbilityOrArrow(arrowType: ArrowType): Boolean = { + def returnsAbilityOrArrow(arrowType: ArrowType): Boolean = { arrowType.codomain.toList.exists { case _: AbilityType => true case _: ArrowType => true @@ -72,8 +72,8 @@ object Picker { override def blank: RawContext = RawContext.blank override def exports(ctx: RawContext): Option[Map[String, Option[String]]] = ctx.exports - override def funcReturnAbilityOrArrow(name: String, ctx: RawContext): Boolean = - ctx.funcs.get(name).map(_.arrow.`type`).exists(typeContainsAbilityOrArrow) + override def funcReturnAbilityOrArrow(ctx: RawContext, name: String): Boolean = + ctx.funcs.get(name).map(_.arrow.`type`).exists(returnsAbilityOrArrow) override def funcNames(ctx: RawContext): List[String] = ctx.funcs.keys.toList override def addPart(ctx: RawContext, part: (RawContext, RawPart)): RawContext = diff --git a/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala b/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala index 57a7557ad..6852c6cf5 100644 --- a/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala +++ b/semantics/src/test/scala/aqua/semantics/HeaderSpec.scala @@ -8,19 +8,18 @@ import aqua.raw.ops.RawTag import aqua.raw.value.VarRaw import aqua.semantics.header.{HeaderHandler, HeaderSem} import aqua.types.{ArrowType, NilType, ProductType} -import cats.data.{Chain, NonEmptyList} +import cats.data.{Chain, NonEmptyList, Validated} import cats.free.Cofree import cats.{Eval, Id, Monoid} +import org.scalatest.Inside import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers -class HeaderSpec extends AnyFlatSpec with Matchers { +class HeaderSpec extends AnyFlatSpec with Matchers with Inside { "header handler" should "generate an error on exported function that returns arrow or ability" in { implicit val rc: Monoid[RawContext] = RawContext.implicits(RawContext.blank).rawContextMonoid - implicit val headerSemMonoid: Monoid[HeaderSem[Id, RawContext]] = HeaderSem.headerSemMonoid - val handler = new HeaderHandler[Id, RawContext]() val funcName = "funcName" @@ -42,9 +41,10 @@ class HeaderSpec extends AnyFlatSpec with Matchers { ) val result = handler.sem(Map.empty, ast).andThen(_.finCtx(initCtx)) - result.isInvalid shouldBe true - - val error = result.toEither.left.get.head - error shouldBe a [HeaderError[Id]] + + inside(result) { + case Validated.Invalid(errors) => + errors.head shouldBe a [HeaderError[Id]] + } } }