FuncSem WIP

This commit is contained in:
dmitry 2021-03-19 11:53:00 +03:00
parent b45c61f5c8
commit d0d4db7bf5

View File

@ -20,6 +20,94 @@ import scala.collection.immutable.Queue
class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
import expr._
def before[Alg[_]](implicit
T: TypesAlgebra[F, Alg],
N: NamesAlgebra[F, Alg],
V: ValuesAlgebra[F, Alg],
P: PeerIdAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg]
): Free[Alg, ArrowType] =
A.beginScope(name) >> Applicative[Free[Alg, *]]
.product(
// Collect argument types, define local variables
args
.foldLeft(
// Begin scope -- for mangling
N.beginScope(name).as[Queue[Type]](Queue.empty)
) {
case (f, Arg(argName, argType)) =>
// 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 =>
Free.pure(acc)
}
)
}
.map(_.toList),
// Resolve return type
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_))
)
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2))
def after[Alg](funcArrow: ArrowType, bodyGen: Gen)(implicit
T: TypesAlgebra[F, Alg],
N: NamesAlgebra[F, Alg],
V: ValuesAlgebra[F, Alg],
P: PeerIdAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg]
): Free[Alg, 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() >> (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
})
def program[Alg[_]](implicit
T: TypesAlgebra[F, Alg],
N: NamesAlgebra[F, Alg],
@ -28,79 +116,8 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
A: AbilitiesAlgebra[F, Alg]
): Prog[Alg, Gen] =
Prog.around(
A.beginScope(name) >> Applicative[Free[Alg, *]]
.product(
// Collect argument types, define local variables
args
.foldLeft(
// Begin scope -- for mangling
N.beginScope(name).as[Queue[Type]](Queue.empty)
) {
case (f, Arg(argName, argType)) =>
// 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 =>
Free.pure(acc)
}
)
}
.map(_.toList),
// Resolve return type
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() >> (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
})
before[Alg],
after[Alg]
)
}