diff --git a/src/main/resources/generate.aqua b/src/main/resources/generate.aqua new file mode 100644 index 00000000..15c6abff --- /dev/null +++ b/src/main/resources/generate.aqua @@ -0,0 +1,8 @@ +service Local("local"): + gt: u32, u32 -> bool + onIn: string -> () + +func tryGen(in1: u32, in2: string) -> bool: + on in2: + Local.onIn(in2) + Local.gt(in1, 25) \ No newline at end of file diff --git a/src/main/scala/aqua/Compiler.scala b/src/main/scala/aqua/Compiler.scala index 2574820f..996e2b85 100644 --- a/src/main/scala/aqua/Compiler.scala +++ b/src/main/scala/aqua/Compiler.scala @@ -23,9 +23,11 @@ import aqua.parser.lexer.Token import cats.arrow.FunctionK import cats.data.Validated.{Invalid, Valid} import cats.data.{EitherK, NonEmptyList, State, ValidatedNel} -import cats.{Comonad, Eval} +import cats.Eval import cats.free.Free import cats.syntax.flatMap._ +import cats.syntax.apply._ +import cats.syntax.semigroup._ import monocle.Lens import monocle.macros.GenLens @@ -52,7 +54,7 @@ object Compiler { case expr: OnExpr[F] => expr.program[G] case expr: ParExpr[F] => expr.program[G] case expr: ServiceExpr[F] => expr.program[G] - case _: RootExpr[F] => Free.pure[G, Gen](Gen("Root expr")) + case expr: RootExpr[F] => expr.program[G] } def folder[F[_], G[_]](implicit @@ -64,8 +66,9 @@ object Compiler { case (expr, inners) => Eval later exprToProg[F, G](expr) .apply( - // TODO: instead of >>, do >>= and merge Gens - inners.foldLeft(Free.pure[G, Gen](Gen("Folder begin")))(_ >> _) + inners + .reduceLeftOption[Free[G, Gen]]((a, b) => (a, b).mapN(_ |+| _)) + .getOrElse(Free.pure(Gen.noop)) ) } diff --git a/src/main/scala/aqua/Main.scala b/src/main/scala/aqua/Main.scala index 052e267e..231aeae8 100644 --- a/src/main/scala/aqua/Main.scala +++ b/src/main/scala/aqua/Main.scala @@ -19,7 +19,7 @@ object Main extends IOApp.Simple { println(Console.RED + s"Aqua script errored, total ${errs.length} problems found" + Console.RESET) } - val script = Source.fromResource("typecheck.aqua").mkString + val script = Source.fromResource("generate.aqua").mkString process(script) } diff --git a/src/main/scala/aqua/ast/Gen.scala b/src/main/scala/aqua/ast/Gen.scala index 7157fe58..4a2db0ea 100644 --- a/src/main/scala/aqua/ast/Gen.scala +++ b/src/main/scala/aqua/ast/Gen.scala @@ -1,13 +1,21 @@ package aqua.ast import aqua.ast.algebra.types.ArrowType +import cats.Semigroup import cats.free.Free -case class Gen(log: String) { +case class Gen(log: String, children: List[Gen] = Nil) { 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.copy(children = y :: x.children) + } + def noop = new Gen("noop") case class Arrow(`type`: ArrowType, gen: Gen) diff --git a/src/main/scala/aqua/ast/Prog.scala b/src/main/scala/aqua/ast/Prog.scala index 98de6835..33311764 100644 --- a/src/main/scala/aqua/ast/Prog.scala +++ b/src/main/scala/aqua/ast/Prog.scala @@ -31,4 +31,6 @@ object Prog { def around[Alg[_], R, A](before: Free[Alg, R], after: (R, A) => Free[Alg, A]): Prog[Alg, A] = RunAround(before, after) + def noop[Alg[_], A]: Prog[Alg, A] = + RunAround(Free.pure(()), (_: Unit, a: A) => Free.pure(a)) } diff --git a/src/main/scala/aqua/ast/algebra/abilities/AbilitiesInterpreter.scala b/src/main/scala/aqua/ast/algebra/abilities/AbilitiesInterpreter.scala index c6b42091..674e3066 100644 --- a/src/main/scala/aqua/ast/algebra/abilities/AbilitiesInterpreter.scala +++ b/src/main/scala/aqua/ast/algebra/abilities/AbilitiesInterpreter.scala @@ -8,6 +8,7 @@ import cats.~> import cats.syntax.functor._ import monocle.Lens import monocle.macros.GenLens +import monocle.macros.syntax.all._ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], error: ReportError[F, X]) extends StackInterpreter[F, X, AbilitiesState[F], AbilityStackFrame[F]](GenLens[AbilitiesState[F]](_.stack)) @@ -35,6 +36,8 @@ 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( @@ -50,7 +53,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e getService(s.name.value).flatMap { case Some(_) => mapStackHead( - report(s.name, "Trying to set service ID while out of the scope").as(false) + modify(_.focus(_.rootServiceIds).index(s.name.value).replace(s.id)).as(true) )(h => h.copy(serviceIds = h.serviceIds.updated(s.name.value, s.id)) -> true) case None => @@ -79,7 +82,8 @@ 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, ArrowType]] = Map.empty, + rootServiceIds: Map[String, Value[F]] = Map.empty[String, Value[F]] ) { def purgeArrows: Option[(NonEmptyList[(Name[F], ArrowType)], AbilitiesState[F])] = diff --git a/src/main/scala/aqua/ast/expr/AbilityIdExpr.scala b/src/main/scala/aqua/ast/expr/AbilityIdExpr.scala index 7d4056e6..465a26d3 100644 --- a/src/main/scala/aqua/ast/expr/AbilityIdExpr.scala +++ b/src/main/scala/aqua/ast/expr/AbilityIdExpr.scala @@ -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.noop + V.ensureIsString(id) >> A.setServiceId(ability, id) as Gen(s"Ability id is set for ${ability.value}") } diff --git a/src/main/scala/aqua/ast/expr/AliasExpr.scala b/src/main/scala/aqua/ast/expr/AliasExpr.scala index 111cafe9..fb3aed53 100644 --- a/src/main/scala/aqua/ast/expr/AliasExpr.scala +++ b/src/main/scala/aqua/ast/expr/AliasExpr.scala @@ -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.noop) - case None => Free.pure(Gen.noop) + 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")) } } diff --git a/src/main/scala/aqua/ast/expr/ArrowTypeExpr.scala b/src/main/scala/aqua/ast/expr/ArrowTypeExpr.scala index 5e842500..c5413b33 100644 --- a/src/main/scala/aqua/ast/expr/ArrowTypeExpr.scala +++ b/src/main/scala/aqua/ast/expr/ArrowTypeExpr.scala @@ -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.noop) - case None => Free.pure(Gen.noop) + 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")) } } diff --git a/src/main/scala/aqua/ast/expr/CoalgebraExpr.scala b/src/main/scala/aqua/ast/expr/CoalgebraExpr.scala index ddc9356b..6af7692d 100644 --- a/src/main/scala/aqua/ast/expr/CoalgebraExpr.scala +++ b/src/main/scala/aqua/ast/expr/CoalgebraExpr.scala @@ -38,7 +38,8 @@ 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("Coalgebra expression") + ) as Gen(s"(call peer (${ability.map(_.value).getOrElse("func")} ${funcName.value}) [${args + .mkString(", ")}]${variable.map(" " + _).getOrElse("")})") case None => Free.pure(Gen("Coalgebra expression errored")) } diff --git a/src/main/scala/aqua/ast/expr/DataStructExpr.scala b/src/main/scala/aqua/ast/expr/DataStructExpr.scala index 843d741b..16fed2dd 100644 --- a/src/main/scala/aqua/ast/expr/DataStructExpr.scala +++ b/src/main/scala/aqua/ast/expr/DataStructExpr.scala @@ -20,8 +20,8 @@ case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F] { Prog after T .purgeFields(name) .flatMap { - case Some(fields) => T.defineDataType(name, fields).as(Gen("Data struct created")) - case None => Free.pure(Gen.noop) + 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")) } } diff --git a/src/main/scala/aqua/ast/expr/FieldTypeExpr.scala b/src/main/scala/aqua/ast/expr/FieldTypeExpr.scala index e6dc03dd..b0fd93e1 100644 --- a/src/main/scala/aqua/ast/expr/FieldTypeExpr.scala +++ b/src/main/scala/aqua/ast/expr/FieldTypeExpr.scala @@ -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.noop) - case None => Free.pure(Gen.noop) + 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")) } } diff --git a/src/main/scala/aqua/ast/expr/FuncExpr.scala b/src/main/scala/aqua/ast/expr/FuncExpr.scala index 57a5425d..676a2a4c 100644 --- a/src/main/scala/aqua/ast/expr/FuncExpr.scala +++ b/src/main/scala/aqua/ast/expr/FuncExpr.scala @@ -53,7 +53,8 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp (funcArrow: ArrowType, bodyGen: Gen) => // Erase arguments and internal variables A.endScope() >> N.endScope() >> N.define(name, funcArrow, isRoot = true) as Gen( - "Function defined, wrap + " + bodyGen + s"func ${name.value}:", + bodyGen :: Nil ) ) diff --git a/src/main/scala/aqua/ast/expr/OnExpr.scala b/src/main/scala/aqua/ast/expr/OnExpr.scala index 26d7b12a..40bbbd46 100644 --- a/src/main/scala/aqua/ast/expr/OnExpr.scala +++ b/src/main/scala/aqua/ast/expr/OnExpr.scala @@ -21,7 +21,7 @@ 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 Gen("OnScope finished for" + ops) + (_: Unit, ops: Gen) => A.endScope() >> P.erasePeerId() as ops ) } diff --git a/src/main/scala/aqua/ast/expr/RootExpr.scala b/src/main/scala/aqua/ast/expr/RootExpr.scala index 7bc1c294..e76c56fa 100644 --- a/src/main/scala/aqua/ast/expr/RootExpr.scala +++ b/src/main/scala/aqua/ast/expr/RootExpr.scala @@ -1,7 +1,11 @@ package aqua.ast.expr -import aqua.ast.Expr +import aqua.ast.{Expr, Gen, Prog} -case class RootExpr[F[_]]() extends Expr[F] {} +case class RootExpr[F[_]]() extends Expr[F] { + + def program[Alg[_]]: Prog[Alg, Gen] = + Prog.noop +} object RootExpr diff --git a/src/main/scala/aqua/ast/expr/ServiceExpr.scala b/src/main/scala/aqua/ast/expr/ServiceExpr.scala index df7ec2c2..83a1adcf 100644 --- a/src/main/scala/aqua/ast/expr/ServiceExpr.scala +++ b/src/main/scala/aqua/ast/expr/ServiceExpr.scala @@ -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.noop))(idV => - V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen.noop + 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") ) case None => - Gen.noop.lift + Gen(s"Cannot create service ${name.value}").lift } )