Generators WIP

This commit is contained in:
dmitry 2021-03-16 14:52:46 +03:00
parent a80c8cd571
commit 35a3c4fc86
15 changed files with 98 additions and 47 deletions

View File

@ -5,4 +5,10 @@ service Local("local"):
func tryGen(in1: u32, in2: string) -> bool:
on in2:
Local.onIn(in2)
Local.gt(in1, 25)
Local.gt(in1, 25)
func generateComplex(value: string) -> bool:
on "smth":
Local "other"
b <- tryGen(23, value)
Local.onIn("Should be on root")

View File

@ -25,7 +25,6 @@ import cats.data.Validated.{Invalid, Valid}
import cats.data.{EitherK, NonEmptyList, State, ValidatedNel}
import cats.Eval
import cats.free.Free
import cats.syntax.flatMap._
import cats.syntax.apply._
import cats.syntax.semigroup._
import monocle.Lens

View File

@ -1,10 +1,11 @@
package aqua.ast
import aqua.ast.algebra.types.ArrowType
import cats.Semigroup
import cats.free.Free
case class Gen(log: String, children: List[Gen] = Nil) {
import scala.collection.immutable.Queue
sealed trait Gen {
def lift[F[_]]: Free[F, Gen] = Free.pure(this)
}
@ -12,11 +13,41 @@ object Gen {
implicit object GenSemigroup extends Semigroup[Gen] {
override def combine(x: Gen, y: Gen): Gen =
x.copy(children = y :: x.children)
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 = new Gen("noop")
case class Arrow(`type`: ArrowType, gen: Gen)
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

View File

@ -25,8 +25,8 @@ object Prog {
implicit def leaf[Alg[_], A](prog: Free[Alg, A]): Prog[Alg, A] =
RunAfter(prog)
def after[Alg[_], A](prog: Free[Alg, A]): Prog[Alg, A] =
RunAfter(prog)
def after[Alg[_], A](prog: A => Free[Alg, A]): Prog[Alg, A] =
RunAround(Free.pure(()), (_: Unit, a: A) => prog(a))
def around[Alg[_], R, A](before: Free[Alg, R], after: (R, A) => Free[Alg, A]): Prog[Alg, A] =
RunAround(before, after)

View File

@ -7,7 +7,6 @@ import cats.data.State
import cats.~>
import monocle.Lens
import monocle.macros.GenLens
import monocle.macros.syntax.all._
import cats.syntax.functor._
import cats.syntax.flatMap._
@ -27,7 +26,8 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
case rn: ReadName[F] =>
readName(rn.name.value).flatTap {
case Some(_) => State.pure(())
case None => report(rn.name, "Undefined name")
case None =>
getState.flatMap(st => report(rn.name, "Undefined name, available: " + st.allNames.mkString(", ")))
}
case ra: ReadArrow[F] =>
readName(ra.name.value).flatMap {
@ -36,15 +36,22 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
case Some(t) =>
report(ra.name, s"Arrow type expected, got: $t").as(Option.empty[ArrowType])
case None =>
report(ra.name, "Undefined name").as(Option.empty[ArrowType])
getState.flatMap(st =>
report(ra.name, "Undefined name, available: " + st.allNames.mkString(", ")).as(Option.empty[ArrowType])
)
}
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(_.focus(_.rootNames).index(dn.name.value).replace(dn.`type`)).as(true)
else report(dn.name, "Cannot define a variable in the root scope").as(false)
if (dn.isRoot)
modify(st => st.copy(rootNames = st.rootNames.updated(dn.name.value, dn.`type`)))
.as(true)
else
report(dn.name, "Cannot define a variable in the root scope")
.as(false)
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
}
case bs: BeginScope[F] =>
@ -54,7 +61,9 @@ 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)
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 NamesFrame[F[_]](token: Token[F], names: Map[String, Type] = Map.empty) {
def addName(n: String, t: Type): NamesFrame[F] = copy[F](names = names.updated(n, t))

View File

@ -1,6 +1,6 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Gen, NoopGen, Prog}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.parser.lexer.Token._
@ -14,7 +14,7 @@ import cats.syntax.functor._
case class AbilityIdExpr[F[_]](ability: Ability[F], id: Value[F]) extends Expr[F] {
def program[Alg[_]](implicit A: AbilitiesAlgebra[F, Alg], V: ValuesAlgebra[F, Alg]): Prog[Alg, Gen] =
V.ensureIsString(id) >> A.setServiceId(ability, id) as Gen(s"Ability id is set for ${ability.value}")
V.ensureIsString(id) >> A.setServiceId(ability, id) as Gen.noop
}

View File

@ -14,8 +14,8 @@ case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F]) exten
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
T.resolveType(target).flatMap {
case Some(t) => T.defineAlias(name, t) as Gen(s"Alias ${name.value} defined")
case None => Free.pure(Gen(s"Alias ${name.value} can't be defined"))
case Some(t) => T.defineAlias(name, t) as Gen.noop
case None => Gen.error.lift
}
}

View File

@ -15,8 +15,8 @@ case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg], A: AbilitiesAlgebra[F, Alg]): Prog[Alg, Gen] =
T.resolveArrowDef(`type`).flatMap {
case Some(t) => A.defineArrow(name, t) as Gen(s"Arrow $name defined")
case None => Free.pure(Gen(s"Arrow $name can't be defined"))
case Some(t) => A.defineArrow(name, t) as Gen.noop
case None => Gen.error.lift
}
}

View File

@ -1,6 +1,6 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Gen, Prog, ServiceCallGen}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.names.NamesAlgebra
@ -38,10 +38,15 @@ case class CoalgebraExpr[F[_]](
Free.pure[Alg, Boolean](false)
)(resType => N.define(exportVar, resType))
// TODO: if it's a service, get service id, etc
) as Gen(s"(call peer (${ability.map(_.value).getOrElse("func")} ${funcName.value}) [${args
.mkString(", ")}]${variable.map(" " + _).getOrElse("")})")
) as (ServiceCallGen(
peerId = "peerId",
serviceId = "#" + ability.map(_.value).getOrElse("???"),
fnName = funcName.value,
args = args.map(_.toString),
result = variable.map(_.value)
): Gen)
case None =>
Free.pure(Gen("Coalgebra expression errored"))
Gen.error.lift[Alg]
}
}

View File

@ -17,12 +17,12 @@ case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F] {
N: NamesAlgebra[F, Alg],
T: TypesAlgebra[F, Alg]
): Prog[Alg, Gen] =
Prog after T
.purgeFields(name)
.flatMap {
case Some(fields) => T.defineDataType(name, fields) as Gen(s"Data struct ${name.value} created")
case None => Free.pure(Gen(s"Data struct ${name.value} can't be created"))
Prog.after((_: Gen) =>
T.purgeFields(name).flatMap {
case Some(fields) => T.defineDataType(name, fields) as Gen.noop // TODO it's not air gen, but ts gen
case None => Gen.error.lift
}
)
}

View File

@ -14,8 +14,8 @@ case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
T.resolveType(`type`).flatMap {
case Some(t) => T.defineField(name, t) as Gen(s"Field ${name.value} defined")
case None => Free.pure(Gen(s"Field ${name.value} can't be defined"))
case Some(t) => T.defineField(name, t) as Gen.noop
case None => Gen.error.lift
}
}

View File

@ -1,6 +1,6 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, FuncBodyGen, FuncGen, Gen, Prog}
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.names.NamesAlgebra
import aqua.ast.algebra.scope.PeerIdAlgebra
@ -52,9 +52,9 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2)),
(funcArrow: ArrowType, bodyGen: Gen) =>
// Erase arguments and internal variables
A.endScope() >> N.endScope() >> N.define(name, funcArrow, isRoot = true) as Gen(
s"func ${name.value}:",
bodyGen :: Nil
A.endScope() >> N.endScope() >> N.define(name, funcArrow, isRoot = true) as FuncGen(
name.value,
FuncBodyGen(bodyGen)
)
)

View File

@ -1,18 +1,16 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Gen, ParGen, Prog}
import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser
import aqua.parser.lift.LiftParser._
import cats.Comonad
import cats.free.Free
import cats.parse.Parser
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F] {
// TODO: implement par marker
def program[Alg[_]]: Prog[Alg, Gen] =
Free.pure[Alg, Gen](Gen("Par"))
Prog.after[Alg, Gen](g => ParGen(left = None, right = g).lift)
}
object ParExpr extends Expr.AndThen(OnExpr, CoalgebraExpr) {

View File

@ -1,11 +1,14 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Gen, Prog, ScriptGen}
import cats.syntax.semigroup._
import scala.collection.immutable.Queue
case class RootExpr[F[_]]() extends Expr[F] {
def program[Alg[_]]: Prog[Alg, Gen] =
Prog.noop
Prog.after(a => (a |+| ScriptGen(Queue.empty)).lift)
}
object RootExpr

View File

@ -29,11 +29,11 @@ case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Exp
(A.purgeArrows(name) <* A.endScope()).flatMap {
case Some(nel) =>
A.defineService(name, nel.map(kv => kv._1.value -> kv._2).toNem) >>
id.fold(Free.pure[Alg, Gen](Gen(s"Service ${name.value} created")))(idV =>
V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen(s"Service ${name.value} created with ID")
id.fold(Free.pure[Alg, Gen](Gen.noop))(idV =>
V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen.noop
)
case None =>
Gen(s"Cannot create service ${name.value}").lift
Gen.error.lift
}
)