mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Arrows WIP
This commit is contained in:
parent
07155ecdbf
commit
05970c248c
@ -1,6 +1,6 @@
|
||||
package aqua
|
||||
|
||||
import aqua.context.{Abilities, AbilitiesResolve, ArgsAndVars, Types}
|
||||
import aqua.context.{Abilities, AbilitiesResolve, ArgsAndVars, Arrows, Types}
|
||||
import aqua.context.scope.ScopeWalker
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
@ -21,6 +21,7 @@ object Aqua {
|
||||
.andThen(new Types.ExpDef(_))
|
||||
.andThen(new Abilities.ExpDef(_))
|
||||
.andThen(new AbilitiesResolve.ExpDef(_))
|
||||
.andThen(new Arrows.ExpDef(_))
|
||||
|
||||
def parse(input: String): ValidatedNel[AquaError, List[Block[Span.F, walker.Out]]] =
|
||||
Validated
|
||||
|
105
src/main/scala/aqua/context/Arrows.scala
Normal file
105
src/main/scala/aqua/context/Arrows.scala
Normal file
@ -0,0 +1,105 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{AbilityArrow, ArrowMarker, FuncArrow, LocalArrow}
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.parser.{AbilityFuncCall, Block, DefFunc, DefService, Extract, FuncCall, FuncExpr}
|
||||
import aqua.parser.lexer.{ArrowName, ArrowType}
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
case class Arrows[F[_]](expDef: ExpectAndDefine[F, ArrowName[F], ArrowMarker[F]]) {
|
||||
|
||||
def clearLocal: Arrows[F] =
|
||||
copy(expDef.collectDefinitions {
|
||||
case fa: FuncArrow[F, _] => fa
|
||||
case aa: AbilityArrow[F, _] => aa
|
||||
})
|
||||
def clearExpectations: Arrows[F] = copy(expDef.clearExpectations)
|
||||
|
||||
def expect(a: ArrowName[F])(implicit F: Comonad[F]): Arrows[F] =
|
||||
copy(expDef.expect(Acc.one(a.name.extract, a)))
|
||||
|
||||
def defined(name: String, marker: ArrowMarker[F]): Arrows[F] =
|
||||
copy(expDef.defined(Acc.one(name, marker)))
|
||||
}
|
||||
|
||||
object Arrows {
|
||||
type Acc[F[_]] = ExpectAndDefine[F, ArrowName[F], ArrowMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, ArrowName[F], ArrowMarker[F]]
|
||||
def empty[F[_]]: Arrows[F] = Arrows[F](emptyAcc[F])
|
||||
|
||||
case class DuplicateArrow[F[_]](name: String, marker: ArrowMarker[F]) extends Walker.DupError[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
marker.toError(s"Duplicate function or arrow definition: ${name}")
|
||||
}
|
||||
|
||||
case class UnresolvedArrow[F[_]](name: String, usage: ArrowName[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Unresolved arrow $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O]) extends Walker[F, I, Arrows[F] :: O] {
|
||||
type Ctx = Arrows[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
(op match {
|
||||
case FuncCall(a, _, _) =>
|
||||
prev.head.expect(a)
|
||||
case afc: AbilityFuncCall[F, I] =>
|
||||
prev.head.expect(afc.abilityArrow)
|
||||
|
||||
case Extract(_, fc, _) =>
|
||||
fc match {
|
||||
case FuncCall(a, _, _) =>
|
||||
prev.head.expect(a)
|
||||
case afc: AbilityFuncCall[F, I] =>
|
||||
prev.head.expect(afc.abilityArrow)
|
||||
}
|
||||
case _ =>
|
||||
prev.head
|
||||
}) :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
(block match {
|
||||
case DefFunc(head, _, _) =>
|
||||
head.args
|
||||
.foldLeft(empty[F]) {
|
||||
case (acc, (k, _, at: ArrowType[F])) =>
|
||||
acc.defined(k, LocalArrow(at))
|
||||
case (acc, _) => acc
|
||||
}
|
||||
|
||||
case DefService(ab, funcs, _) =>
|
||||
val prefix = ab.name.extract + "."
|
||||
funcs.toNel.foldLeft(empty[F]) {
|
||||
case (acc, (n, at)) =>
|
||||
acc.defined(prefix + n, AbilityArrow(ab, at))
|
||||
}
|
||||
|
||||
case _ =>
|
||||
empty[F]
|
||||
|
||||
}) :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
Walker.collectDups(prev.head.expDef, next.head.expDef, DuplicateArrow[F]) ::: extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
Arrows(prev.head.expDef combineSeq block.head.expDef).clearLocal :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UnresolvedArrow[F])
|
||||
(curErrs ::: extErrs, Arrows(curExpDef) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.DefFunc
|
||||
import aqua.parser.lexer.{ArrowType, Token}
|
||||
import aqua.parser.lexer.{Ability, ArrowType, Token}
|
||||
|
||||
sealed trait ArrowMarker[F[_]] extends Marker[F]
|
||||
|
||||
@ -12,3 +12,7 @@ case class LocalArrow[F[_], L](arr: ArrowType[F]) extends ArrowMarker[F] {
|
||||
case class FuncArrow[F[_], L](funcDef: DefFunc[F, L]) extends ArrowMarker[F] {
|
||||
override def pointer: Token[F] = funcDef.head.name
|
||||
}
|
||||
|
||||
case class AbilityArrow[F[_], L](ability: Ability[F], arr: ArrowType[F]) extends ArrowMarker[F] {
|
||||
override def pointer: Token[F] = arr
|
||||
}
|
||||
|
86
src/test/scala/aqua/context/ArrowsSpec.scala
Normal file
86
src/test/scala/aqua/context/ArrowsSpec.scala
Normal file
@ -0,0 +1,86 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import cats.Id
|
||||
import cats.data.Validated.Invalid
|
||||
import cats.data.{NonEmptyList, Validated}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import shapeless._
|
||||
|
||||
class ArrowsSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
val walker = Walker.hnil[Id].andThen(new Arrows.ExpDef(_))
|
||||
|
||||
def parseBlocks(str: String): List[Block[Id, Arrows[Id] :: HNil]] =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
.toEither
|
||||
.right
|
||||
.value
|
||||
|
||||
def parseBlocksV(str: String) =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
|
||||
"Arrows walker" should "collect no ability resolutions from a function" in {
|
||||
val bs = parseBlocks("""
|
||||
|func some():
|
||||
| Peer "peer"
|
||||
| Peer.timestamp()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
bs.length should be(1)
|
||||
val ctx = bs.head.context
|
||||
val acc = ctx.head.expDef
|
||||
acc.expectAcc.keys should be('empty)
|
||||
acc.defineAcc.keys should be('empty)
|
||||
}
|
||||
|
||||
"Arrows walker" should "collect ability expectations from two functions" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| x <- First.arr()
|
||||
|
|
||||
|
|
||||
|func other(x: i32):
|
||||
| Peer "smth"
|
||||
| y <- Second.arr2(x)
|
||||
| Peer.timestamp()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
"Arrows walker" should "resolve abilities in a function" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| y <- Smth.foo()
|
||||
| x <- Ab.f(z, y)
|
||||
|
|
||||
|alias T: i32
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user