mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
ReturnExpr for functions
This commit is contained in:
parent
35a3c4fc86
commit
b4a9979278
@ -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
|
||||
),
|
||||
|
@ -5,10 +5,12 @@ service Local("local"):
|
||||
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")
|
||||
Local.onIn("Should be on root")
|
||||
<- true
|
@ -1,6 +1,6 @@
|
||||
package aqua
|
||||
|
||||
import aqua.ast.{Ast, Gen}
|
||||
import aqua.ast.{Ast, Compiler, Gen}
|
||||
import cats.data.ValidatedNel
|
||||
import aqua.parser.lift.Span
|
||||
|
||||
|
@ -1,34 +1,21 @@
|
||||
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.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 +39,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]
|
||||
}
|
@ -13,15 +13,14 @@ 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)
|
||||
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 (_, y: FuncBodyGen) => y.copy(op = SeqGen(x, y.op))
|
||||
case (_, y: ServiceCallGen) => SeqGen(x, y)
|
||||
case (_, y: ParGen) => ParGen(Some(x), y.right)
|
||||
case (x: AirGen, y: FuncBodyGen) => y.copy(op = SeqGen(x, y.op))
|
||||
case (x: AirGen, y: ServiceCallGen) => SeqGen(x, y)
|
||||
case (x: AirGen, y: ParGen) => ParGen(Some(x), y.right)
|
||||
|
||||
case (NoopGen, _) => y
|
||||
case (_, NoopGen) => x
|
||||
@ -30,24 +29,32 @@ object Gen {
|
||||
println(Console.RED + s"drop x: ${x} in favor of y: $y" + Console.RESET)
|
||||
y
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def noop: Gen = NoopGen
|
||||
def error: Gen = NoopGen
|
||||
}
|
||||
|
||||
sealed trait AirGen extends Gen {
|
||||
def last: AirGen = this
|
||||
}
|
||||
|
||||
case object NoopGen extends Gen
|
||||
|
||||
case class SeqGen(left: Gen, right: Gen) extends Gen
|
||||
case class SeqGen(left: AirGen, right: AirGen) extends AirGen {
|
||||
override def last: AirGen = right
|
||||
}
|
||||
|
||||
case class ServiceCallGen(peerId: String, serviceId: String, fnName: String, args: List[String], result: Option[String])
|
||||
extends Gen
|
||||
extends AirGen
|
||||
|
||||
case class FuncBodyGen(op: Gen) extends Gen
|
||||
case class FuncBodyGen(op: AirGen) 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
|
||||
case class ParGen(left: Option[AirGen], right: AirGen) extends AirGen {
|
||||
override def last: AirGen = right
|
||||
}
|
||||
|
@ -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,6 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, NoopGen, Prog}
|
||||
import aqua.ast.{Expr, Gen, Prog}
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.algebra.abilities.AbilitiesAlgebra
|
||||
import aqua.parser.lexer.Token._
|
||||
|
@ -54,7 +54,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,14 +1,16 @@
|
||||
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.{AirGen, Expr, FuncBodyGen, FuncGen, Gen, 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.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name}
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
|
||||
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._
|
||||
@ -16,11 +18,13 @@ import cats.{Applicative, Comonad}
|
||||
|
||||
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] =
|
||||
@ -46,25 +50,57 @@ 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 =>
|
||||
N.define(name, funcArrow, isRoot = true) as FuncGen(
|
||||
name.value, // TODO: handle return value
|
||||
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 l =>
|
||||
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,6 +1,6 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.{Expr, Gen, ParGen, Prog}
|
||||
import aqua.ast.{AirGen, Expr, Gen, ParGen, Prog}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
@ -10,7 +10,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) {
|
||||
|
23
src/main/scala/aqua/ast/expr/ReturnExpr.scala
Normal file
23
src/main/scala/aqua/ast/expr/ReturnExpr.scala
Normal file
@ -0,0 +1,23 @@
|
||||
package aqua.ast.expr
|
||||
|
||||
import aqua.ast.algebra.ValuesAlgebra
|
||||
import aqua.ast.{Expr, Gen, 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(_))
|
||||
}
|
@ -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