mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Merge pull request #1 from fluencelabs/init-gen
First approach to generators
This commit is contained in:
commit
0f6db200b6
@ -15,7 +15,6 @@ lazy val root = project
|
||||
"org.typelevel" %% "cats-effect" % "3.0.0-RC2",
|
||||
"org.typelevel" %% "cats-parse" % "0.3.1",
|
||||
"org.typelevel" %% "cats-free" % catsV,
|
||||
"com.chuusai" %% "shapeless" % "2.3.3",
|
||||
"com.github.julien-truffaut" %% "monocle-core" % monocleV,
|
||||
"com.github.julien-truffaut" %% "monocle-macro" % monocleV
|
||||
),
|
||||
|
@ -1,14 +1,27 @@
|
||||
service Local("local"):
|
||||
gt: u32, u32 -> bool
|
||||
onIn: string -> ()
|
||||
onBoolean: bool -> ()
|
||||
|
||||
func tryGen(in1: u32, in2: string) -> bool:
|
||||
on in2:
|
||||
Local.onIn(in2)
|
||||
Local.gt(in1, 25)
|
||||
v <- Local.gt(in1, 25)
|
||||
<- v
|
||||
|
||||
func generateComplex(value: string) -> bool:
|
||||
on "smth":
|
||||
Local "other"
|
||||
b <- tryGen(23, value)
|
||||
Local.onIn("Should be on root")
|
||||
t <- tryGen(24, "should be omitted")
|
||||
Local.onIn("Should be on other")
|
||||
Local.onIn("Should be on root")
|
||||
Local.onBoolean(b)
|
||||
<- b
|
||||
|
||||
func genArrows(arr: string -> bool):
|
||||
arr("hi there")
|
||||
|
||||
--func wrapGenArrows():
|
||||
-- on "some peer":
|
||||
-- genArrows(generateComplex)
|
||||
|
@ -1,9 +1,12 @@
|
||||
package aqua
|
||||
|
||||
import aqua.ast.{Ast, Gen}
|
||||
import aqua.ast.gen.{Gen, ScriptGen}
|
||||
import aqua.ast.{Ast, Compiler}
|
||||
import cats.data.ValidatedNel
|
||||
import aqua.parser.lift.Span
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
object Aqua {
|
||||
|
||||
def parse(input: String): ValidatedNel[AquaError, Ast[Span.F]] =
|
||||
@ -12,4 +15,9 @@ object Aqua {
|
||||
def compile(input: String): ValidatedNel[AquaError, Gen] =
|
||||
parse(input).andThen(ast => Compiler.compile(ast).leftMap(_.map(ts => CompilerError(ts._1.unit._1, ts._2))))
|
||||
|
||||
def generate(input: String): ValidatedNel[AquaError, Queue[String]] =
|
||||
compile(input).map {
|
||||
case g: ScriptGen => g.generateAir
|
||||
case _ => Queue.empty
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ object Main extends IOApp.Simple {
|
||||
override def run: IO[Unit] =
|
||||
IO {
|
||||
def process(str: String) =
|
||||
Aqua.compile(str) match {
|
||||
Aqua.generate(str) match {
|
||||
case Validated.Valid(v) ⇒
|
||||
println(v)
|
||||
println(Console.GREEN + "Aqua script processed successfully" + Console.RESET)
|
||||
|
@ -1,34 +1,22 @@
|
||||
package aqua
|
||||
package aqua.ast
|
||||
|
||||
import aqua.ast.algebra.ReportError
|
||||
import aqua.ast.expr.{
|
||||
AbilityIdExpr,
|
||||
AliasExpr,
|
||||
ArrowTypeExpr,
|
||||
CoalgebraExpr,
|
||||
DataStructExpr,
|
||||
FieldTypeExpr,
|
||||
FuncExpr,
|
||||
OnExpr,
|
||||
ParExpr,
|
||||
RootExpr,
|
||||
ServiceExpr
|
||||
}
|
||||
import aqua.ast.algebra.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
|
||||
import aqua.ast.algebra.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
|
||||
import aqua.ast.algebra.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
|
||||
import aqua.ast.algebra.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
|
||||
import aqua.ast.{Ast, Expr, Gen, Prog}
|
||||
import aqua.ast.expr._
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token
|
||||
import cats.Eval
|
||||
import cats.arrow.FunctionK
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{EitherK, NonEmptyList, State, ValidatedNel}
|
||||
import cats.Eval
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.semigroup._
|
||||
import monocle.Lens
|
||||
import monocle.macros.GenLens
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.semigroup._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
@ -52,6 +40,7 @@ object Compiler {
|
||||
case expr: FuncExpr[F] => expr.program[G]
|
||||
case expr: OnExpr[F] => expr.program[G]
|
||||
case expr: ParExpr[F] => expr.program[G]
|
||||
case expr: ReturnExpr[F] => expr.program[G]
|
||||
case expr: ServiceExpr[F] => expr.program[G]
|
||||
case expr: RootExpr[F] => expr.program[G]
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package aqua.ast
|
||||
|
||||
import cats.Semigroup
|
||||
import cats.free.Free
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
sealed trait Gen {
|
||||
def lift[F[_]]: Free[F, Gen] = Free.pure(this)
|
||||
}
|
||||
|
||||
object Gen {
|
||||
|
||||
implicit object GenSemigroup extends Semigroup[Gen] {
|
||||
|
||||
override def combine(x: Gen, y: Gen): Gen = {
|
||||
println(Console.BLUE + x + " " + Console.YELLOW + y + Console.RESET)
|
||||
(x, y) match {
|
||||
case (x: ScriptGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueueAll(x.funcs))
|
||||
case (x: FuncGen, y: FuncGen) => ScriptGen(Queue(x, y))
|
||||
case (x: FuncGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueue(x))
|
||||
case (_, y: FuncBodyGen) => y.copy(op = SeqGen(x, y.op))
|
||||
case (_, y: ServiceCallGen) => SeqGen(x, y)
|
||||
case (_, y: ParGen) => ParGen(Some(x), y.right)
|
||||
|
||||
case (NoopGen, _) => y
|
||||
case (_, NoopGen) => x
|
||||
|
||||
case (_, y) =>
|
||||
println(Console.RED + s"drop x: ${x} in favor of y: $y" + Console.RESET)
|
||||
y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def noop: Gen = NoopGen
|
||||
def error: Gen = NoopGen
|
||||
}
|
||||
|
||||
case object NoopGen extends Gen
|
||||
|
||||
case class SeqGen(left: Gen, right: Gen) extends Gen
|
||||
|
||||
case class ServiceCallGen(peerId: String, serviceId: String, fnName: String, args: List[String], result: Option[String])
|
||||
extends Gen
|
||||
|
||||
case class FuncBodyGen(op: Gen) extends Gen
|
||||
|
||||
case class FuncGen(name: String, body: FuncBodyGen) extends Gen
|
||||
|
||||
case class ScriptGen(funcs: Queue[FuncGen]) extends Gen
|
||||
|
||||
case class ParGen(left: Option[Gen], right: Gen) extends Gen
|
@ -9,18 +9,32 @@ import cats.syntax.apply._
|
||||
class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlgebra[F, Alg]) {
|
||||
|
||||
def ensureIsString(v: Value[F]): Free[Alg, Boolean] =
|
||||
ensureTypeMatches(v, LiteralType.string)
|
||||
|
||||
def ensureTypeMatches(v: Value[F], expected: Type): Free[Alg, Boolean] =
|
||||
resolveType(v).flatMap {
|
||||
case Some(vt) =>
|
||||
T.ensureTypeMatches(
|
||||
v match {
|
||||
case l: Literal[F] => l
|
||||
case VarLambda(n, lambda) => lambda.lastOption.getOrElse(n)
|
||||
},
|
||||
expected,
|
||||
vt
|
||||
)
|
||||
case None => Free.pure(false)
|
||||
}
|
||||
|
||||
def resolveType(v: Value[F]): Free[Alg, Option[Type]] =
|
||||
v match {
|
||||
case l: Literal[F] =>
|
||||
T.ensureTypeMatches(l, LiteralType.string, l.ts)
|
||||
case v @ VarLambda(n, lambda) =>
|
||||
Free pure [Alg, Option[Type]] Some(l.ts)
|
||||
case VarLambda(n, lambda) =>
|
||||
N.read(n).flatMap {
|
||||
case Some(t) =>
|
||||
T.resolveLambda(t, lambda).flatMap {
|
||||
case Some(vt) => T.ensureTypeMatches(v.lambda.lastOption.getOrElse(n), LiteralType.string, vt)
|
||||
case None => Free.pure(false)
|
||||
}
|
||||
T.resolveLambda(t, lambda)
|
||||
case None =>
|
||||
Free.pure(false)
|
||||
Free.pure(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.algebra.abilities
|
||||
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import cats.InjectK
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
@ -14,15 +15,18 @@ class AbilitiesAlgebra[F[_], Alg[_]](implicit A: InjectK[AbilityOp[F, *], Alg])
|
||||
def purgeArrows(token: Token[F]): Free[Alg, Option[NonEmptyList[(Name[F], ArrowType)]]] =
|
||||
Free.liftInject[Alg](PurgeArrows[F](token))
|
||||
|
||||
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowType]): Free[Alg, Boolean] =
|
||||
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineService[F](name, arrows))
|
||||
|
||||
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowGen]] =
|
||||
Free.liftInject[Alg](GetArrow[F](name, arrow))
|
||||
|
||||
def setServiceId(name: Ability[F], id: Value[F]): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](SetServiceId[F](name, id))
|
||||
|
||||
def getServiceId(name: String): Free[Alg, Option[Value[F]]] =
|
||||
Free.liftInject[Alg](GetServiceId[F](name))
|
||||
|
||||
def beginScope(token: Token[F]): Free[Alg, Unit] =
|
||||
Free.liftInject[Alg](BeginScope[F](token))
|
||||
|
||||
|
@ -2,7 +2,8 @@ package aqua.ast.algebra.abilities
|
||||
|
||||
import aqua.ast.algebra.{ReportError, StackInterpreter}
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.parser.lexer.{Name, Token, Value}
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State}
|
||||
import cats.~>
|
||||
import cats.syntax.functor._
|
||||
@ -14,7 +15,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
extends StackInterpreter[F, X, AbilitiesState[F], AbilityStackFrame[F]](GenLens[AbilitiesState[F]](_.stack))
|
||||
with (AbilityOp[F, *] ~> State[X, *]) {
|
||||
|
||||
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowType]]] =
|
||||
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowGen]]] =
|
||||
getState.map(_.services.get(name))
|
||||
|
||||
override def apply[A](fa: AbilityOp[F, A]): State[X, A] =
|
||||
@ -36,30 +37,46 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
case ga: GetArrow[F] =>
|
||||
getService(ga.name.value).flatMap {
|
||||
case Some(arrows) =>
|
||||
// TODO: must be resolved
|
||||
|
||||
arrows(ga.arrow.value)
|
||||
.fold(
|
||||
report(
|
||||
ga.arrow,
|
||||
s"Service found, but arrow is undefined, available: ${arrows.value.keys.toNonEmptyList.toList.mkString(", ")}"
|
||||
).as(Option.empty[ArrowType])
|
||||
).as(Option.empty[ArrowGen])
|
||||
)(a => State.pure(Some(a)))
|
||||
case None =>
|
||||
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType])
|
||||
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowGen])
|
||||
}
|
||||
|
||||
case s: SetServiceId[F] =>
|
||||
getService(s.name.value).flatMap {
|
||||
case Some(_) =>
|
||||
mapStackHead(
|
||||
modify(_.focus(_.rootServiceIds).index(s.name.value).replace(s.id)).as(true)
|
||||
modify(st => st.copy(rootServiceIds = st.rootServiceIds.updated(s.name.value, s.id))).as(true)
|
||||
)(h => h.copy(serviceIds = h.serviceIds.updated(s.name.value, s.id)) -> true)
|
||||
|
||||
case None =>
|
||||
report(s.name, "Service with this name is not registered, can't set its ID").as(false)
|
||||
}
|
||||
|
||||
case s: GetServiceId[F] =>
|
||||
getState.flatMap(st =>
|
||||
st.stack.flatMap(_.serviceIds.get(s.name)).headOption orElse st.rootServiceIds.get(s.name) match {
|
||||
case None =>
|
||||
st.stack.headOption
|
||||
.map(_.token)
|
||||
.fold(
|
||||
// TODO this should be an impossible error
|
||||
State.pure[X, Option[Value[F]]](Option.empty[Value[F]])
|
||||
)(t =>
|
||||
report(t, s"Service ID unresolved, use `${s.name} id` expression to set it")
|
||||
.as(Option.empty[Value[F]])
|
||||
)
|
||||
|
||||
case v => State.pure(v)
|
||||
}
|
||||
)
|
||||
|
||||
case da: DefineArrow[F] =>
|
||||
mapStackHeadE(
|
||||
report(da.arrow, "No abilities definition scope is found").as(false)
|
||||
@ -82,7 +99,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
|
||||
|
||||
case class AbilitiesState[F[_]](
|
||||
stack: List[AbilityStackFrame[F]] = Nil,
|
||||
services: Map[String, NonEmptyMap[String, ArrowType]] = Map.empty,
|
||||
services: Map[String, NonEmptyMap[String, ArrowGen]] = Map.empty,
|
||||
rootServiceIds: Map[String, Value[F]] = Map.empty[String, Value[F]]
|
||||
) {
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.algebra.abilities
|
||||
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Ability, Name, Token, Value}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
|
||||
@ -10,12 +11,14 @@ case class DefineArrow[F[_]](arrow: Name[F], `type`: ArrowType) extends AbilityO
|
||||
|
||||
case class PurgeArrows[F[_]](token: Token[F]) extends AbilityOp[F, Option[NonEmptyList[(Name[F], ArrowType)]]]
|
||||
|
||||
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowType]) extends AbilityOp[F, Boolean]
|
||||
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]) extends AbilityOp[F, Boolean]
|
||||
|
||||
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowType]]
|
||||
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowGen]]
|
||||
|
||||
case class SetServiceId[F[_]](name: Ability[F], id: Value[F]) extends AbilityOp[F, Boolean]
|
||||
|
||||
case class GetServiceId[F[_]](name: String) extends AbilityOp[F, Option[Value[F]]]
|
||||
|
||||
case class BeginScope[F[_]](token: Token[F]) extends AbilityOp[F, Unit]
|
||||
|
||||
case class EndScope[F[_]]() extends AbilityOp[F, Boolean]
|
||||
|
@ -1,15 +1,18 @@
|
||||
package aqua.ast.algebra.names
|
||||
|
||||
import aqua.ast.algebra.types.{ArrowType, Type}
|
||||
import aqua.ast.algebra.types.Type
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
|
||||
sealed trait NameOp[F[_], T]
|
||||
|
||||
case class ReadName[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowGen]]
|
||||
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type, isRoot: Boolean) extends NameOp[F, Boolean]
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
|
||||
|
||||
case class DefineArrow[F[_]](name: Name[F], gen: ArrowGen, isRoot: Boolean) extends NameOp[F, Boolean]
|
||||
|
||||
case class BeginScope[F[_]](token: Token[F]) extends NameOp[F, Unit]
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.algebra.names
|
||||
|
||||
import aqua.ast.algebra.types.{ArrowType, Type}
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.{Name, Token}
|
||||
import cats.InjectK
|
||||
import cats.free.Free
|
||||
@ -10,11 +11,14 @@ class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
||||
def read(name: Name[F]): Free[Alg, Option[Type]] =
|
||||
Free.liftInject[Alg](ReadName(name))
|
||||
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowGen]] =
|
||||
Free.liftInject[Alg](ReadArrow(name))
|
||||
|
||||
def define(name: Name[F], `type`: Type, isRoot: Boolean = false): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`, isRoot))
|
||||
def define(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`))
|
||||
|
||||
def defineArrow(name: Name[F], gen: ArrowGen, isRoot: Boolean): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineArrow(name, gen, isRoot))
|
||||
|
||||
def beginScope(token: Token[F]): Free[Alg, Unit] =
|
||||
Free.liftInject[Alg](BeginScope(token))
|
||||
|
@ -1,7 +1,8 @@
|
||||
package aqua.ast.algebra.names
|
||||
|
||||
import aqua.ast.algebra.types.{ArrowType, Type}
|
||||
import aqua.ast.algebra.types.Type
|
||||
import aqua.ast.algebra.{ReportError, StackInterpreter}
|
||||
import aqua.ast.gen.ArrowGen
|
||||
import aqua.parser.lexer.Token
|
||||
import cats.data.State
|
||||
import cats.~>
|
||||
@ -18,7 +19,13 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
getState.map { st =>
|
||||
st.stack.collectFirst {
|
||||
case frame if frame.names.contains(name) => frame.names(name)
|
||||
} orElse st.rootNames.get(name)
|
||||
case frame if frame.arrows.contains(name) => frame.arrows(name).`type`
|
||||
} orElse st.rootArrows.get(name).map(_.`type`)
|
||||
}
|
||||
|
||||
def readArrow(name: String): S[Option[ArrowGen]] =
|
||||
getState.map { st =>
|
||||
st.stack.flatMap(_.arrows.get(name)).headOption orElse st.rootArrows.get(name)
|
||||
}
|
||||
|
||||
override def apply[A](fa: NameOp[F, A]): State[X, A] =
|
||||
@ -30,29 +37,36 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
getState.flatMap(st => report(rn.name, "Undefined name, available: " + st.allNames.mkString(", ")))
|
||||
}
|
||||
case ra: ReadArrow[F] =>
|
||||
readName(ra.name.value).flatMap {
|
||||
case Some(t: ArrowType) =>
|
||||
State.pure(Option(t))
|
||||
case Some(t) =>
|
||||
report(ra.name, s"Arrow type expected, got: $t").as(Option.empty[ArrowType])
|
||||
readArrow(ra.name.value).flatMap {
|
||||
case Some(g) => State.pure(Option(g))
|
||||
case None =>
|
||||
getState.flatMap(st =>
|
||||
report(ra.name, "Undefined name, available: " + st.allNames.mkString(", ")).as(Option.empty[ArrowType])
|
||||
report(ra.name, "Undefined arrow, available: " + st.allNames.mkString(", "))
|
||||
.as(Option.empty[ArrowGen])
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
case dn: DefineName[F] =>
|
||||
readName(dn.name.value).flatMap {
|
||||
case Some(_) => report(dn.name, "This name was already defined in the scope").as(false)
|
||||
case None =>
|
||||
mapStackHead(
|
||||
if (dn.isRoot)
|
||||
modify(st => st.copy(rootNames = st.rootNames.updated(dn.name.value, dn.`type`)))
|
||||
report(dn.name, "Cannot define a variable in the root scope")
|
||||
.as(false)
|
||||
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
|
||||
}
|
||||
case da: DefineArrow[F] =>
|
||||
readName(da.name.value).flatMap {
|
||||
case Some(_) => report(da.name, "This name was already defined in the scope").as(false)
|
||||
case None =>
|
||||
mapStackHead(
|
||||
if (da.isRoot)
|
||||
modify(st => st.copy(rootArrows = st.rootArrows.updated(da.name.value, da.gen)))
|
||||
.as(true)
|
||||
else
|
||||
report(dn.name, "Cannot define a variable in the root scope")
|
||||
report(da.name, "Cannot define a variable in the root scope")
|
||||
.as(false)
|
||||
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
|
||||
)(fr => fr.addArrow(da.name.value, da.gen) -> true)
|
||||
}
|
||||
case bs: BeginScope[F] =>
|
||||
beginScope(NamesFrame(bs.token))
|
||||
@ -61,10 +75,20 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
}).asInstanceOf[State[X, A]]
|
||||
}
|
||||
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootNames: Map[String, Type] = Map.empty) {
|
||||
def allNames: LazyList[String] = LazyList.from(stack).flatMap(_.names.keys).appendedAll(rootNames.keys)
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[String, ArrowGen] = Map.empty) {
|
||||
|
||||
def allNames: LazyList[String] =
|
||||
LazyList.from(stack).flatMap(s => s.names.keys ++ s.arrows.keys).appendedAll(rootArrows.keys)
|
||||
|
||||
def allArrows: LazyList[String] =
|
||||
LazyList.from(stack).flatMap(_.arrows.keys).appendedAll(rootArrows.keys)
|
||||
}
|
||||
|
||||
case class NamesFrame[F[_]](token: Token[F], names: Map[String, Type] = Map.empty) {
|
||||
case class NamesFrame[F[_]](
|
||||
token: Token[F],
|
||||
names: Map[String, Type] = Map.empty,
|
||||
arrows: Map[String, ArrowGen] = Map.empty
|
||||
) {
|
||||
def addName(n: String, t: Type): NamesFrame[F] = copy[F](names = names.updated(n, t))
|
||||
def addArrow(n: String, g: ArrowGen): NamesFrame[F] = copy[F](arrows = arrows.updated(n, g))
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, NoopGen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
|
@ -1,7 +1,8 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{CustomTypeToken, TypeToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
|
@ -1,8 +1,9 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{ArrowTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
|
@ -1,10 +1,11 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog, ServiceCallGen}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.{Gen, ServiceCallGen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
@ -31,20 +32,13 @@ case class CoalgebraExpr[F[_]](
|
||||
.fold(N.readArrow(funcName))(A.getArrow(_, funcName))
|
||||
.flatMap {
|
||||
case Some(at) =>
|
||||
V.checkArguments(at, args) >> variable
|
||||
V.checkArguments(at.`type`, args) >> variable
|
||||
.fold(Free.pure[Alg, Boolean](true))(exportVar =>
|
||||
at.res.fold(
|
||||
at.`type`.res.fold(
|
||||
// TODO: error! we're trying to export variable, but function has no export type
|
||||
Free.pure[Alg, Boolean](false)
|
||||
)(resType => N.define(exportVar, resType))
|
||||
// TODO: if it's a service, get service id, etc
|
||||
) as (ServiceCallGen(
|
||||
peerId = "peerId",
|
||||
serviceId = "#" + ability.map(_.value).getOrElse("???"),
|
||||
fnName = funcName.value,
|
||||
args = args.map(_.toString),
|
||||
result = variable.map(_.value)
|
||||
): Gen)
|
||||
) >> at.gen[F, Alg](args, variable).widen[Gen]
|
||||
case None =>
|
||||
Gen.error.lift[Alg]
|
||||
}
|
||||
@ -54,7 +48,7 @@ case class CoalgebraExpr[F[_]](
|
||||
object CoalgebraExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[CoalgebraExpr[F]] =
|
||||
((Name.p[F] <* `<-`).backtrack.?.with1 ~
|
||||
((Name.p[F] <* ` <- `).backtrack.?.with1 ~
|
||||
((Ability.ab[F] <* `.`).?.with1 ~
|
||||
Name.p[F] ~
|
||||
comma0(Value.`value`[F]).between(`(`, `)`))).map {
|
||||
|
@ -1,8 +1,9 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.CustomTypeToken
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
|
@ -1,7 +1,8 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{DataTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
|
@ -1,26 +1,32 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, FuncBodyGen, FuncGen, Gen, Prog}
|
||||
import aqua.ast.Ast.Tree
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.{Expr, Indent, Prog}
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.scope.PeerIdAlgebra
|
||||
import aqua.ast.algebra.types.{ArrowType, Type, TypesAlgebra}
|
||||
import aqua.ast.algebra.types.{ArrowType, DataType, Type, TypesAlgebra}
|
||||
import aqua.ast.gen.DataView.InitPeerId
|
||||
import aqua.ast.gen.{AirContext, AirGen, ArrowGen, DataView, FuncBodyGen, FuncGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name}
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value, VarLambda}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.free.Free
|
||||
import cats.free.{Cofree, Free}
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.{Applicative, Comonad}
|
||||
import cats.{Applicative, Comonad, Eval}
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTypeToken[F]]) extends Expr[F] {
|
||||
case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTypeToken[F]], retValue: Option[Value[F]])
|
||||
extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit
|
||||
T: TypesAlgebra[F, Alg],
|
||||
N: NamesAlgebra[F, Alg],
|
||||
V: ValuesAlgebra[F, Alg],
|
||||
P: PeerIdAlgebra[F, Alg],
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
@ -37,6 +43,8 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
|
||||
// Resolve arg type, remember it
|
||||
f.flatMap(acc =>
|
||||
T.resolveType(argType).flatMap {
|
||||
case Some(t: ArrowType) =>
|
||||
N.defineArrow(argName, ArrowGen.arg(argName.value, t), isRoot = false).as(acc.enqueue(t))
|
||||
case Some(t) =>
|
||||
N.define(argName, t).as(acc.enqueue(t))
|
||||
case None =>
|
||||
@ -46,25 +54,84 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
|
||||
}
|
||||
.map(_.toList),
|
||||
// Resolve return type
|
||||
// TODO handle return VALUE!
|
||||
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_))
|
||||
)
|
||||
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2)),
|
||||
(funcArrow: ArrowType, bodyGen: Gen) =>
|
||||
// Check return value type
|
||||
((funcArrow.res, retValue) match {
|
||||
case (Some(t), Some(v)) =>
|
||||
V.resolveType(v).flatMap {
|
||||
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
||||
case None => Free.pure[Alg, Unit](())
|
||||
}
|
||||
case _ =>
|
||||
Free.pure[Alg, Unit](())
|
||||
})
|
||||
// Erase arguments and internal variables
|
||||
A.endScope() >> N.endScope() >> N.define(name, funcArrow, isRoot = true) as FuncGen(
|
||||
name.value,
|
||||
FuncBodyGen(bodyGen)
|
||||
)
|
||||
>> A.endScope() >> N.endScope() >> (bodyGen match {
|
||||
case bg: AirGen if ret.isDefined == retValue.isDefined =>
|
||||
val argNames = args.map(_.name.value)
|
||||
N.defineArrow(
|
||||
name,
|
||||
ArrowGen.func(funcArrow, argNames, retValue.map(ArrowGen.valueToData), FuncBodyGen(bg)),
|
||||
isRoot = true
|
||||
) as FuncGen(
|
||||
name.value,
|
||||
Eval.later {
|
||||
bg.generate(
|
||||
AirContext(
|
||||
data = argNames
|
||||
.zip(funcArrow.args)
|
||||
.collect { //TODO preload these variables
|
||||
case (an, _: DataType) =>
|
||||
an -> DataView.Variable(an)
|
||||
}
|
||||
.toMap,
|
||||
arrows = argNames
|
||||
.zip(funcArrow.args)
|
||||
.collect {
|
||||
case (an, _: ArrowType) =>
|
||||
an -> new ArrowGen.SrvCallableOnPeer(InitPeerId, DataView.StringScalar("callback"), an)
|
||||
}
|
||||
.toMap,
|
||||
vars = argNames.toSet
|
||||
)
|
||||
)
|
||||
._2
|
||||
},
|
||||
FuncBodyGen(bg)
|
||||
)
|
||||
case _ => Gen.noop.lift
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
object FuncExpr extends Expr.AndIndented(OnExpr, AbilityIdExpr, CoalgebraExpr, ParExpr) {
|
||||
object FuncExpr extends Expr.AndIndented(OnExpr, AbilityIdExpr, ReturnExpr, CoalgebraExpr, ParExpr) {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
||||
.between(`(`, `)`) ~ (`->` *> DataTypeToken.`datatypedef`).? <* ` : \n+`).map {
|
||||
case ((name, args), ret) => FuncExpr(name, args, ret)
|
||||
.between(`(`, `)`) ~ (` -> ` *> DataTypeToken.`datatypedef`).? <* ` : \n+`).map {
|
||||
case ((name, args), ret) => FuncExpr(name, args, ret, None)
|
||||
}
|
||||
|
||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): Parser[Tree[F]] =
|
||||
super.ast(ps).flatMap { tree =>
|
||||
tree.head match {
|
||||
case funcExpr: FuncExpr[F] if funcExpr.ret.isDefined =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(re: ReturnExpr[F]) =>
|
||||
Parser.pure(
|
||||
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
|
||||
)
|
||||
case _ =>
|
||||
Parser.failWith(
|
||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||
)
|
||||
}
|
||||
|
||||
case _ => Parser.pure(tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.scope.PeerIdAlgebra
|
||||
import aqua.ast.gen.{AirGen, ArrowGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
@ -21,7 +22,12 @@ case class OnExpr[F[_]](peerId: Value[F]) extends Expr[F] {
|
||||
): Prog[Alg, Gen] =
|
||||
Prog.around(
|
||||
V.ensureIsString(peerId) >> P.onPeerId(peerId) >> A.beginScope(peerId),
|
||||
(_: Unit, ops: Gen) => A.endScope() >> P.erasePeerId() as ops
|
||||
(_: Unit, ops: Gen) =>
|
||||
A.endScope() >> P.erasePeerId() as (ops match {
|
||||
case air: AirGen =>
|
||||
air.wrap(c => (c.copy(peerId = ArrowGen.valueToData(peerId)), _.copy(peerId = c.peerId)))
|
||||
case _ => ops
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, ParGen, Prog}
|
||||
import aqua.ast.gen.{AirGen, Gen, ParGen}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
@ -10,7 +11,10 @@ import cats.parse.Parser
|
||||
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]]: Prog[Alg, Gen] =
|
||||
Prog.after[Alg, Gen](g => ParGen(left = None, right = g).lift)
|
||||
Prog.after[Alg, Gen] {
|
||||
case g: AirGen => ParGen(left = None, right = g).lift
|
||||
case g => g.lift
|
||||
}
|
||||
}
|
||||
|
||||
object ParExpr extends Expr.AndThen(OnExpr, CoalgebraExpr) {
|
||||
|
24
src/main/scala/aqua/ast/expr/ReturnExpr.scala
Normal file
24
src/main/scala/aqua/ast/expr/ReturnExpr.scala
Normal file
@ -0,0 +1,24 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.gen.Gen
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class ReturnExpr[F[_]](value: Value[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit V: ValuesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
V.resolveType(value).as(Gen.noop)
|
||||
|
||||
}
|
||||
|
||||
object ReturnExpr extends Expr.Leaf {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] =
|
||||
(`<-` *> ` ` *> Value.`value`[F]).map(ReturnExpr(_))
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog, ScriptGen}
|
||||
import aqua.ast.gen.{Gen, ScriptGen}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import cats.syntax.semigroup._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
@ -1,10 +1,11 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.{Expr, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.names.NamesAlgebra
|
||||
import aqua.ast.algebra.types.TypesAlgebra
|
||||
import aqua.ast.gen.{ArrowGen, Gen}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
@ -28,7 +29,10 @@ case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Exp
|
||||
(_: Unit, body: Gen) =>
|
||||
(A.purgeArrows(name) <* A.endScope()).flatMap {
|
||||
case Some(nel) =>
|
||||
A.defineService(name, nel.map(kv => kv._1.value -> kv._2).toNem) >>
|
||||
A.defineService(
|
||||
name,
|
||||
nel.map(kv => kv._1.value -> ArrowGen.service(name.value, kv._1.value, kv._2)).toNem
|
||||
) >>
|
||||
id.fold(Free.pure[Alg, Gen](Gen.noop))(idV =>
|
||||
V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen.noop
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
package aqua.ir
|
||||
package aqua.ast.gen
|
||||
|
||||
import cats.Show
|
||||
import cats.syntax.show._
|
||||
@ -41,7 +41,9 @@ object DataView {
|
||||
|
||||
case class Stream(name: String) extends DataView
|
||||
|
||||
case class VarLens(name: String, lens: String) extends DataView
|
||||
case class VarLens(name: String, lens: String) extends DataView {
|
||||
def append(sublens: String): VarLens = copy(lens = lens + sublens)
|
||||
}
|
||||
|
||||
implicit val show: Show[DataView] = Show.show {
|
||||
case StringScalar(v) ⇒ v
|
||||
@ -49,7 +51,7 @@ object DataView {
|
||||
case LastError ⇒ "%last_error%"
|
||||
case Variable(name) ⇒ name
|
||||
case Stream(name) ⇒ name
|
||||
case VarLens(name, lens) ⇒ s"$name.$lens"
|
||||
case VarLens(name, lens) ⇒ name + ".$" + lens
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +65,7 @@ object Triplet {
|
||||
|
||||
implicit val show: Show[Triplet] = Show.show {
|
||||
case FromData(ps, fn) ⇒ s"${ps.show} " + "\"" + fn + "\""
|
||||
case Full(p, s, fn) ⇒ s"${p.show} (${s.show} " + "\"" + fn + "\""
|
||||
case Full(p, s, fn) ⇒ s"${p.show} (${s.show} " + "\"" + fn + "\")"
|
||||
}
|
||||
}
|
||||
|
21
src/main/scala/aqua/ast/gen/AirContext.scala
Normal file
21
src/main/scala/aqua/ast/gen/AirContext.scala
Normal file
@ -0,0 +1,21 @@
|
||||
package aqua.ast.gen
|
||||
|
||||
import DataView.InitPeerId
|
||||
|
||||
case class AirContext(
|
||||
data: Map[String, DataView] = Map.empty,
|
||||
arrows: Map[String, ArrowGen.Callable] = Map.empty,
|
||||
peerId: DataView = InitPeerId,
|
||||
vars: Set[String] = Set.empty,
|
||||
instrCounter: Int = 0
|
||||
) {
|
||||
|
||||
def mergePar(other: AirContext): AirContext =
|
||||
copy(
|
||||
instrCounter = instrCounter max other.instrCounter,
|
||||
data = data ++ other.data,
|
||||
vars = vars ++ other.vars
|
||||
)
|
||||
|
||||
def incr: AirContext = copy(instrCounter = instrCounter + 1)
|
||||
}
|
104
src/main/scala/aqua/ast/gen/ArrowGen.scala
Normal file
104
src/main/scala/aqua/ast/gen/ArrowGen.scala
Normal file
@ -0,0 +1,104 @@
|
||||
package aqua.ast.gen
|
||||
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.ast.algebra.types.ArrowType
|
||||
import DataView.InitPeerId
|
||||
import aqua.parser.lexer.{IntoArray, IntoField, LambdaOp, Literal, Name, Value, VarLambda}
|
||||
import cats.free.Free
|
||||
|
||||
abstract class ArrowGen(val `type`: ArrowType) {
|
||||
|
||||
def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen]
|
||||
}
|
||||
|
||||
object ArrowGen {
|
||||
|
||||
private def opsToLens[F[_]](ops: List[LambdaOp[F]]): String =
|
||||
ops match {
|
||||
case Nil => ""
|
||||
case (_: IntoArray[F]) :: tail => "[@" + opsToLens(tail) + "]"
|
||||
case (f: IntoField[F]) :: tail => "." + f.value + opsToLens(tail)
|
||||
}
|
||||
|
||||
def valueToData[F[_]](v: Value[F]): DataView =
|
||||
v match {
|
||||
case l: Literal[F] => DataView.StringScalar(l.value)
|
||||
case VarLambda(name, Nil) => DataView.Variable(name.value)
|
||||
case VarLambda(name, ops) => DataView.VarLens(name.value, opsToLens(ops))
|
||||
}
|
||||
|
||||
private def argsToData[F[_]](args: List[Value[F]]): List[DataView] = args.map(valueToData)
|
||||
|
||||
trait Callable {
|
||||
def toCallGen(args: List[DataView], result: Option[String]): AirGen
|
||||
}
|
||||
|
||||
class FuncCallable(argNames: List[String], retValue: Option[DataView], bodyGen: FuncBodyGen) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
bodyGen.op
|
||||
.wrap(c =>
|
||||
(
|
||||
c.copy(data = c.data ++ argNames.zip(args)),
|
||||
_.copy(data = c.data ++ result.zip(retValue))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class SrvCallable(srvId: DataView, fnName: String) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
ServiceCallGen(srvId, fnName, args, result)
|
||||
}
|
||||
|
||||
class SrvCallableOnPeer(peerId: DataView, srvId: DataView, fnName: String) extends Callable {
|
||||
|
||||
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
|
||||
ServiceCallGen(srvId, fnName, args, result).wrap(ctx => (ctx.copy(peerId = peerId), _.copy(peerId = ctx.peerId)))
|
||||
}
|
||||
|
||||
def func(`type`: ArrowType, argNames: List[String], retValue: Option[DataView], bodyGen: FuncBodyGen): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
Free.pure[Alg, AirGen](
|
||||
new FuncCallable(argNames, retValue, bodyGen).toCallGen(argsToData(args), result.map(_.value))
|
||||
)
|
||||
}
|
||||
|
||||
def service(name: String, fnName: String, `type`: ArrowType): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
// TODO it's really weird that we're losing token here
|
||||
A.getServiceId(name).map {
|
||||
case Some(sid) =>
|
||||
new SrvCallable(valueToData(sid), fnName).toCallGen(argsToData(args), result.map(_.value))
|
||||
case None =>
|
||||
NullGen
|
||||
}
|
||||
}
|
||||
|
||||
def arg(name: String, `type`: ArrowType): ArrowGen =
|
||||
new ArrowGen(`type`) {
|
||||
|
||||
override def gen[F[_], Alg[_]](args: List[Value[F]], result: Option[Name[F]])(implicit
|
||||
A: AbilitiesAlgebra[F, Alg]
|
||||
): Free[Alg, AirGen] =
|
||||
Free.pure[Alg, AirGen](
|
||||
new AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
println(Console.YELLOW + ctx + Console.RESET)
|
||||
ctx.arrows(name).toCallGen(argsToData(args), result.map(_.value)).generate(ctx)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
127
src/main/scala/aqua/ast/gen/Gen.scala
Normal file
127
src/main/scala/aqua/ast/gen/Gen.scala
Normal file
@ -0,0 +1,127 @@
|
||||
package aqua.ast.gen
|
||||
|
||||
import cats.{Eval, Semigroup}
|
||||
import cats.free.Free
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.show._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
sealed trait Gen {
|
||||
def lift[F[_]]: Free[F, Gen] = Free.pure(this)
|
||||
}
|
||||
|
||||
object Gen {
|
||||
|
||||
implicit object GenSemigroup extends Semigroup[Gen] {
|
||||
|
||||
override def combine(x: Gen, y: Gen): Gen =
|
||||
(x, y) match {
|
||||
case (x: ScriptGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueueAll(x.funcs))
|
||||
case (x: FuncGen, y: FuncGen) => ScriptGen(Queue(x, y))
|
||||
case (x: FuncGen, y: ScriptGen) => y.copy(funcs = y.funcs.enqueue(x))
|
||||
case (x: ScriptGen, y: FuncGen) => x.copy(funcs = x.funcs.enqueue(y))
|
||||
case (x: AirGen, y: FuncBodyGen) => y.copy(op = SeqGen(x, y.op))
|
||||
case (x: AirGen, y: ParGen) => ParGen(Some(x), y.right)
|
||||
case (x: AirGen, y: AirGen) => SeqGen(x, y)
|
||||
|
||||
case (NoopGen, _) => y
|
||||
case (_, NoopGen) => x
|
||||
|
||||
case (_, y) =>
|
||||
println(Console.RED + s"drop x: ${x} in favor of y: $y" + Console.RESET)
|
||||
y
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def noop: Gen = NoopGen
|
||||
def error: Gen = NoopGen
|
||||
}
|
||||
|
||||
trait AirGen extends Gen {
|
||||
self =>
|
||||
def generate(ctx: AirContext): (AirContext, Air)
|
||||
|
||||
def wrap(f: AirContext => (AirContext, AirContext => AirContext)): AirGen =
|
||||
new AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
val (setup, clean) = f(ctx)
|
||||
val (internal, res) = self.generate(setup)
|
||||
(clean(internal), res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object NullGen extends AirGen {
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = (ctx, Air.Null)
|
||||
}
|
||||
|
||||
case object NoopGen extends Gen
|
||||
|
||||
case class SeqGen(left: AirGen, right: AirGen) extends AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
println(Console.BLUE + ctx + Console.RESET)
|
||||
val (c, l) = left.generate(ctx)
|
||||
right.generate(c).swap.map(_.incr).swap.map(Air.Seq(l, _))
|
||||
}
|
||||
}
|
||||
|
||||
case class ServiceCallGen(
|
||||
srvId: DataView,
|
||||
fnName: String,
|
||||
args: List[DataView],
|
||||
result: Option[String]
|
||||
) extends AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) = {
|
||||
val (c, res) = result.fold(ctx -> Option.empty[String]) {
|
||||
case r if ctx.vars(r) =>
|
||||
val vn = r + ctx.instrCounter
|
||||
ctx.copy(vars = ctx.vars + vn, data = ctx.data.updated(r, DataView.Variable(vn))) -> Option(vn)
|
||||
case r =>
|
||||
ctx.copy(vars = ctx.vars + r, data = ctx.data.updated(r, DataView.Variable(r))) -> Option(r)
|
||||
}
|
||||
|
||||
c.incr -> Air.Call(
|
||||
Triplet.Full(ctx.peerId, srvId, fnName),
|
||||
args.map {
|
||||
case DataView.Variable(name) => ctx.data(name)
|
||||
case DataView.Stream(name) => ctx.data(name)
|
||||
case DataView.VarLens(name, lens) =>
|
||||
ctx.data(name) match {
|
||||
case DataView.Variable(n) => DataView.VarLens(n, lens)
|
||||
case DataView.Stream(n) => DataView.VarLens(n, lens)
|
||||
case vl: DataView.VarLens => vl.append(lens)
|
||||
case a => a // actually, it's an error
|
||||
}
|
||||
case a => a
|
||||
},
|
||||
res
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
case class FuncBodyGen(op: AirGen) extends Gen
|
||||
|
||||
case class FuncGen(name: String, air: Eval[Air], body: FuncBodyGen) extends Gen {
|
||||
def generateAir: Air = air.memoize.value
|
||||
}
|
||||
|
||||
case class ScriptGen(funcs: Queue[FuncGen]) extends Gen {
|
||||
|
||||
def generateAir: Queue[String] =
|
||||
funcs.map(_.generateAir.show)
|
||||
}
|
||||
|
||||
case class ParGen(left: Option[AirGen], right: AirGen) extends AirGen {
|
||||
|
||||
override def generate(ctx: AirContext): (AirContext, Air) =
|
||||
left.fold(right.generate(ctx)) { l =>
|
||||
val (lc, la) = l.generate(ctx)
|
||||
val (rc, ra) = right.generate(ctx.incr)
|
||||
(lc.mergePar(rc).incr, Air.Par(la, ra))
|
||||
}
|
||||
}
|
@ -41,8 +41,9 @@ object Token {
|
||||
val `*` : P[Unit] = P.char('*')
|
||||
val `(` : P[Unit] = ` `.?.with1 *> P.char('(') <* ` `.?
|
||||
val `)` : P[Unit] = ` `.?.with1 *> P.char(')') <* ` `.?
|
||||
val `->` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
||||
val `<-` : P[Unit] = (` `.?.with1 *> P.string("<-") <* ` `.?).backtrack
|
||||
val ` -> ` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
||||
val ` <- ` : P[Unit] = (` `.?.with1 *> P.string("<-") <* ` `.?).backtrack
|
||||
val `<-` : P[Unit] = P.string("<-").backtrack
|
||||
|
||||
def comma[T](p: P[T]): P[NonEmptyList[T]] =
|
||||
P.repSep(p, `,` <* ` \n+`.rep0)
|
||||
|
@ -62,7 +62,7 @@ case class ArrowTypeToken[F[_]: Comonad](
|
||||
object ArrowTypeToken {
|
||||
|
||||
def `arrowdef`[F[_]: LiftParser: Comonad]: P[ArrowTypeToken[F]] =
|
||||
(comma0(DataTypeToken.`datatypedef`).with1 ~ `->`.lift ~
|
||||
(comma0(DataTypeToken.`datatypedef`).with1 ~ ` -> `.lift ~
|
||||
(DataTypeToken.`datatypedef`
|
||||
.map(Some(_)) | P.string("()").as(None))).map {
|
||||
case ((args, point), res) ⇒ ArrowTypeToken(point, args, res)
|
||||
|
Loading…
Reference in New Issue
Block a user