Simplified CoalgebraModel

This commit is contained in:
dmitry 2021-03-19 14:33:57 +03:00
parent 48a5ab2fa5
commit 7dde8a5d07
45 changed files with 326 additions and 304 deletions

View File

@ -4,7 +4,7 @@ import DataView.InitPeerId
case class AirContext(
data: Map[String, DataView] = Map.empty,
arrows: Map[String, ArrowGen.Callable] = Map.empty,
arrows: Map[String, ArrowCallable] = Map.empty,
peerId: DataView = InitPeerId,
vars: Set[String] = Set.empty,
instrCounter: Int = 0

View File

@ -0,0 +1,29 @@
package aqua.generator
sealed trait ArrowCallable {
def toCallGen(args: List[DataView], result: Option[String]): AirGen
}
class FuncCallable(argNames: List[String], retValue: Option[DataView], bodyGen: FuncBodyGen) extends ArrowCallable {
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 ArrowCallable {
override def toCallGen(args: List[DataView], result: Option[String]): AirGen =
ServiceCallGen(srvId, fnName, args, result)
}
class SrvCallableOnPeer(peerId: DataView, srvId: DataView, fnName: String) extends ArrowCallable {
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)))
}

View File

@ -1,104 +0,0 @@
package aqua.generator
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.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)
}
}
)
}
}

View File

@ -106,14 +106,23 @@ case class ServiceCallGen(
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 FuncGen(
name: String,
air: Map[String, ArrowCallable] => Eval[Air],
body: FuncBodyGen,
callable: FuncCallable
) extends Gen {
def generateAir(acc: Map[String, ArrowCallable]): Air = air(acc).value
}
case class ScriptGen(funcs: Queue[FuncGen]) extends Gen {
def generateAir: Queue[String] =
funcs.map(_.generateAir.show)
funcs
.foldLeft((Map.empty[String, ArrowCallable], Queue.empty[String])) { case ((funcsAcc, outputAcc), func) =>
funcsAcc.updated(func.name, func.callable) -> outputAcc.enqueue(func.generateAir(funcsAcc).show)
}
._2
}
case class ParGen(left: Option[AirGen], right: AirGen) extends AirGen {

View File

@ -0,0 +1,7 @@
package aqua.model
import aqua.generator.DataView
sealed trait AbilityModel
case class ServiceModel(name: String, id: DataView) extends AbilityModel

View File

@ -0,0 +1,21 @@
package aqua.model
import aqua.generator.{AirContext, AirGen, DataView, SrvCallable}
import aqua.semantics.Type
case class CoalgebraModel(
ability: Option[AbilityModel],
funcName: String,
args: List[(DataView, Type)],
exportTo: Option[String]
) extends OpModel {
def arrowGen: AirGen =
ability match {
case Some(ServiceModel(_, id)) =>
new SrvCallable(id, funcName).toCallGen(args.map(_._1), exportTo)
case None =>
(ctx: AirContext) => ctx.arrows(funcName).toCallGen(args.map(_._1), exportTo).generate(ctx)
}
}

View File

@ -1,8 +1,8 @@
package aqua.model
import aqua.generator.DataView.InitPeerId
import aqua.generator.{AirContext, ArrowGen, DataView, FuncBodyGen, FuncGen}
import aqua.semantics.algebra.types.{ArrowType, DataType}
import aqua.generator.{AirContext, DataView, FuncBodyGen, FuncCallable, FuncGen, SrvCallableOnPeer}
import aqua.semantics.{ArrowType, DataType}
import cats.Eval
case class FuncModel(
@ -15,23 +15,29 @@ case class FuncModel(
def gen: FuncGen =
FuncGen(
name,
Eval.later {
body.op
.generate(
AirContext(
data = args.collect { //TODO preload these variables
case (an, Left(_)) =>
an -> DataView.Variable(an)
}.toMap,
arrows = args.collect { case (an, Right(_)) =>
an -> new ArrowGen.SrvCallableOnPeer(InitPeerId, DataView.StringScalar("callback"), an)
}.toMap,
vars = args.map(_._1).toSet
acc =>
Eval.later {
body.op
.generate(
AirContext(
data = args.collect { //TODO preload these variables
case (an, Left(_)) =>
an -> DataView.Variable(an)
}.toMap,
arrows = acc ++ args.collect { case (an, Right(_)) =>
an -> new SrvCallableOnPeer(InitPeerId, DataView.StringScalar("callback"), an)
}.toMap,
vars = args.map(_._1).toSet
)
)
)
._2
},
body
._2
},
body,
new FuncCallable(
args.map(_._1),
ret,
body
)
)
}

View File

@ -0,0 +1,3 @@
package aqua.model
trait OpModel {}

View File

@ -0,0 +1,5 @@
package aqua.model
import cats.data.NonEmptyList
case class SeqModel(ops: NonEmptyList[OpModel]) extends OpModel

View File

@ -1,9 +1,9 @@
package aqua.parser.lexer
import aqua.semantics.algebra.types.ScalarType
import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser
import aqua.parser.lift.LiftParser._
import aqua.semantics.ScalarType
import cats.{Comonad, Functor}
import cats.parse.{Parser => P}
import cats.syntax.functor._
@ -36,9 +36,8 @@ object BasicTypeToken {
def `basictypedef`[F[_]: LiftParser: Comonad]: P[BasicTypeToken[F]] =
P.oneOf(
ScalarType.all.map(n P.string(n.name).as(n)).toList
)
.lift
ScalarType.all.map(n P.string(n.name).as(n)).toList
).lift
.map(BasicTypeToken(_))
}
@ -64,8 +63,8 @@ object ArrowTypeToken {
def `arrowdef`[F[_]: LiftParser: Comonad]: P[ArrowTypeToken[F]] =
(comma0(DataTypeToken.`datatypedef`).with1 ~ ` -> `.lift ~
(DataTypeToken.`datatypedef`
.map(Some(_)) | P.string("()").as(None))).map {
case ((args, point), res) ArrowTypeToken(point, args, res)
.map(Some(_)) | P.string("()").as(None))).map { case ((args, point), res)
ArrowTypeToken(point, args, res)
}
}

View File

@ -1,9 +1,9 @@
package aqua.parser.lexer
import aqua.semantics.algebra.types.LiteralType
import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser
import aqua.parser.lift.LiftParser._
import aqua.semantics.LiteralType
import cats.{Comonad, Functor}
import cats.parse.{Numbers, Parser => P}
import cats.syntax.functor._
@ -25,8 +25,8 @@ object Value {
val notLambdaSymbols = Set(' ', ',', '\n', ')', ':')
def varLambda[F[_]: LiftParser: Comonad]: P[VarLambda[F]] =
(Name.p[F] ~ LambdaOp.ops[F].?).map {
case (n, l) VarLambda(n, l.fold[List[LambdaOp[F]]](Nil)(_.toList))
(Name.p[F] ~ LambdaOp.ops[F].?).map { case (n, l)
VarLambda(n, l.fold[List[LambdaOp[F]]](Nil)(_.toList))
}
def bool[F[_]: LiftParser: Functor: Comonad]: P[Literal[F]] =

View File

@ -3,10 +3,10 @@ package aqua.semantics
import aqua.generator.Gen
import aqua.parser.Expr
import aqua.parser.expr._
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.scope.PeerIdAlgebra
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.scope.PeerIdAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import aqua.semantics.expr._
object ExprSem {

View File

@ -3,11 +3,11 @@ package aqua.semantics
import aqua.generator.Gen
import aqua.parser.lexer.Token
import aqua.parser.{Ast, Expr}
import aqua.semantics.algebra.ReportError
import aqua.semantics.algebra.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
import aqua.semantics.algebra.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
import aqua.semantics.algebra.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
import aqua.semantics.algebra.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
import aqua.semantics.rules.ReportError
import aqua.semantics.rules.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
import aqua.semantics.rules.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
import aqua.semantics.rules.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
import aqua.semantics.rules.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
import cats.Eval
import cats.arrow.FunctionK
import cats.data.Validated.{Invalid, Valid}
@ -27,15 +27,14 @@ object Semantics {
N: NamesAlgebra[F, G],
P: PeerIdAlgebra[F, G],
T: TypesAlgebra[F, G]
): (Expr[F], List[Free[G, Gen]]) => Eval[Free[G, Gen]] = {
case (expr, inners) =>
Eval later ExprSem
.getProg[F, G](expr)
.apply(
inners
.reduceLeftOption[Free[G, Gen]]((a, b) => (a, b).mapN(_ |+| _))
.getOrElse(Free.pure(Gen.noop))
)
): (Expr[F], List[Free[G, Gen]]) => Eval[Free[G, Gen]] = { case (expr, inners) =>
Eval later ExprSem
.getProg[F, G](expr)
.apply(
inners
.reduceLeftOption[Free[G, Gen]]((a, b) => (a, b).mapN(_ |+| _))
.getOrElse(Free.pure(Gen.noop))
)
}
type Alg0[F[_], A] = EitherK[AbilityOp[F, *], NameOp[F, *], A]
@ -85,9 +84,8 @@ object Semantics {
def validate[F[_]](ast: Ast[F]): ValidatedNel[(Token[F], String), Gen] =
(transpile[F] _ andThen interpret[F])(ast)
.run(CompilerState[F]())
.map {
case (state, gen) =>
NonEmptyList.fromList(state.errors.toList).fold[ValidatedNel[(Token[F], String), Gen]](Valid(gen))(Invalid(_))
.map { case (state, gen) =>
NonEmptyList.fromList(state.errors.toList).fold[ValidatedNel[(Token[F], String), Gen]](Valid(gen))(Invalid(_))
}
.value
}

View File

@ -1,4 +1,4 @@
package aqua.semantics.algebra.types
package aqua.semantics
import cats.PartialOrder
import cats.data.NonEmptyMap
@ -48,7 +48,7 @@ object ScalarType {
}
}
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends Type {
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends DataType {
override def toString: String = name
}

View File

@ -3,8 +3,8 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.AbilityIdExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import cats.syntax.flatMap._
import cats.syntax.functor._

View File

@ -3,7 +3,7 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.AliasExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.syntax.functor._
class AliasSem[F[_]](val expr: AliasExpr[F]) extends AnyVal {

View File

@ -3,8 +3,8 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.ArrowTypeExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.syntax.functor._
class ArrowTypeSem[F[_]](val expr: ArrowTypeExpr[F]) extends AnyVal {

View File

@ -1,39 +1,83 @@
package aqua.semantics.expr
import aqua.generator.Gen
import aqua.generator.{DataView, Gen}
import aqua.model.{CoalgebraModel, ServiceModel}
import aqua.parser.expr.CoalgebraExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.{ArrowType, Prog, Type}
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.free.Free
import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.apply._
class CoalgebraSem[F[_]](val expr: CoalgebraExpr[F]) extends AnyVal {
import expr._
private def freeUnit[Alg[_]]: Free[Alg, Unit] = Free.pure[Alg, Unit](())
private def checkArgsRes[Alg[_]](
at: ArrowType
)(implicit N: NamesAlgebra[F, Alg], V: ValuesAlgebra[F, Alg]): Free[Alg, List[(DataView, Type)]] =
V.checkArguments(at, args) >> variable
.fold(freeUnit[Alg])(exportVar =>
at.res.fold(
// TODO: error! we're trying to export variable, but function has no export type
freeUnit[Alg]
)(resType => N.define(exportVar, resType).void)
) >> args.foldLeft(Free.pure[Alg, List[(DataView, Type)]](Nil)) { case (acc, v) =>
(acc, V.resolveType(v)).mapN((a, b) => a ++ b.map(ValuesAlgebra.valueToData(v) -> _))
}
private def toModel[Alg[_]](implicit
N: NamesAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg],
T: TypesAlgebra[F, Alg],
V: ValuesAlgebra[F, Alg]
): Free[Alg, Option[CoalgebraModel]] =
ability match {
case Some(ab) =>
(A.getArrow(ab, funcName), A.getServiceId(ab)).mapN {
case (Some(at), Some(sid)) =>
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
case _ => None
}.flatMap(_.fold(Free.pure[Alg, Option[CoalgebraModel]](None)) { case (arrowType, serviceId) =>
checkArgsRes(arrowType)
.map(argsResolved =>
CoalgebraModel(
ability = Some(ServiceModel(ab.value, ValuesAlgebra.valueToData(serviceId))),
funcName = funcName.value,
args = argsResolved,
exportTo = variable.map(_.value)
)
)
.map(Option(_))
})
case None =>
N.readArrow(funcName)
.flatMap(_.fold(Free.pure[Alg, Option[CoalgebraModel]](None)) { arrowType =>
checkArgsRes(arrowType)
.map(argsResolved =>
CoalgebraModel(
ability = None,
funcName = funcName.value,
args = argsResolved,
exportTo = variable.map(_.value)
)
)
.map(Option(_))
})
}
def program[Alg[_]](implicit
N: NamesAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg],
T: TypesAlgebra[F, Alg],
V: ValuesAlgebra[F, Alg]
): Prog[Alg, Gen] =
ability
.fold(N.readArrow(funcName))(A.getArrow(_, funcName))
.flatMap {
case Some(at) =>
V.checkArguments(at.`type`, args) >> variable
.fold(Free.pure[Alg, Boolean](true))(exportVar =>
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))
) >> at.gen[F, Alg](args, variable).widen[Gen]
case None =>
Gen.error.lift[Alg]
}
toModel[Alg].map(_.fold(Gen.noop)(_.arrowGen))
}

View File

@ -3,8 +3,8 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.DataStructExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.syntax.functor._
class DataStructSem[F[_]](val expr: DataStructExpr[F]) extends AnyVal {

View File

@ -3,7 +3,7 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.FieldTypeExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.syntax.functor._
class FieldTypeSem[F[_]](val expr: FieldTypeExpr[F]) extends AnyVal {

View File

@ -1,15 +1,15 @@
package aqua.semantics.expr
import aqua.generator.{AirGen, ArrowGen, FuncBodyGen, Gen}
import aqua.generator.{AirGen, FuncBodyGen, Gen}
import aqua.model.FuncModel
import aqua.parser.expr.FuncExpr
import aqua.parser.lexer.Arg
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.scope.PeerIdAlgebra
import aqua.semantics.algebra.types.{ArrowType, DataType, Type, TypesAlgebra}
import aqua.semantics.{ArrowType, DataType, Prog, Type}
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.scope.PeerIdAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.Applicative
import cats.free.Free
import cats.syntax.flatMap._
@ -39,7 +39,7 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
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))
N.defineArrow(argName, t, isRoot = false).as(acc.enqueue(t))
case Some(t) =>
N.define(argName, t).as(acc.enqueue(t))
case None =>
@ -83,13 +83,13 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
case (n, dt: DataType) => n -> Left(dt)
case (n, at: ArrowType) => n -> Right(at)
},
ret = retValue.map(ArrowGen.valueToData),
ret = retValue.map(ValuesAlgebra.valueToData),
body = FuncBodyGen(bg)
)
N.defineArrow(
name,
ArrowGen.func(funcArrow, argNames, retValue.map(ArrowGen.valueToData), FuncBodyGen(bg)),
funcArrow,
isRoot = true
) as model.gen
case _ => Gen.noop.lift

View File

@ -1,11 +1,11 @@
package aqua.semantics.expr
import aqua.generator.{AirGen, ArrowGen, Gen}
import aqua.generator.{AirGen, Gen}
import aqua.parser.expr.OnExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.scope.PeerIdAlgebra
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.scope.PeerIdAlgebra
import cats.syntax.flatMap._
import cats.syntax.functor._
@ -21,7 +21,7 @@ class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
(_: Unit, ops: Gen) =>
A.endScope() >> P.erasePeerId() as (ops match {
case air: AirGen =>
air.wrap(c => (c.copy(peerId = ArrowGen.valueToData(expr.peerId)), _.copy(peerId = c.peerId)))
air.wrap(c => (c.copy(peerId = ValuesAlgebra.valueToData(expr.peerId)), _.copy(peerId = c.peerId)))
case _ => ops
})
)

View File

@ -3,7 +3,7 @@ package aqua.semantics.expr
import aqua.generator.Gen
import aqua.parser.expr.ReturnExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.rules.ValuesAlgebra
import cats.syntax.functor._
class ReturnSem[F[_]](val expr: ReturnExpr[F]) extends AnyVal {

View File

@ -1,12 +1,12 @@
package aqua.semantics.expr
import aqua.generator.{ArrowGen, Gen}
import aqua.generator.Gen
import aqua.parser.expr.ServiceExpr
import aqua.semantics.Prog
import aqua.semantics.algebra.ValuesAlgebra
import aqua.semantics.algebra.abilities.AbilitiesAlgebra
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.types.TypesAlgebra
import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import cats.free.Free
import cats.syntax.apply._
import cats.syntax.flatMap._
@ -27,7 +27,7 @@ class ServiceSem[F[_]](val expr: ServiceExpr[F]) extends AnyVal {
case Some(nel) =>
A.defineService(
expr.name,
nel.map(kv => kv._1.value -> ArrowGen.service(expr.name.value, kv._1.value, kv._2)).toNem
nel.map(kv => kv._1.value -> kv._2).toNem
) >>
expr.id.fold(Free.pure[Alg, Gen](Gen.noop))(idV =>
V.ensureIsString(idV) >> A.setServiceId(expr.name, idV) as Gen.noop

View File

@ -1,4 +1,4 @@
package aqua.semantics.algebra
package aqua.semantics.rules
import aqua.parser.lexer.Token

View File

@ -1,4 +1,4 @@
package aqua.semantics.algebra
package aqua.semantics.rules
import aqua.parser.lexer.Token
import cats.data.State

View File

@ -1,8 +1,10 @@
package aqua.semantics.algebra
package aqua.semantics.rules
import aqua.semantics.algebra.names.NamesAlgebra
import aqua.semantics.algebra.types.{ArrowType, LiteralType, Type, TypesAlgebra}
import aqua.parser.lexer.{Literal, Token, Value, VarLambda}
import aqua.generator.DataView
import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra
import aqua.parser.lexer.{IntoArray, IntoField, LambdaOp, Literal, Token, Value, VarLambda}
import aqua.semantics.{ArrowType, LiteralType, Type}
import cats.free.Free
import cats.syntax.apply._
@ -52,22 +54,37 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge
.zip(arr.args)
.foldLeft(
Free.pure[Alg, Boolean](true)
) {
case (f, (ft, t)) =>
(
f,
ft.flatMap {
case None => Free.pure(false)
case Some((tkn, valType)) =>
T.ensureTypeMatches(tkn, t, valType)
}
).mapN(_ && _)
) { case (f, (ft, t)) =>
(
f,
ft.flatMap {
case None => Free.pure(false)
case Some((tkn, valType)) =>
T.ensureTypeMatches(tkn, t, valType)
}
).mapN(_ && _)
}
}
object ValuesAlgebra {
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)
implicit def deriveValuesAlgebra[F[_], Alg[_]](implicit
N: NamesAlgebra[F, Alg],
T: TypesAlgebra[F, Alg]

View File

@ -1,8 +1,7 @@
package aqua.semantics.algebra.abilities
package aqua.semantics.rules.abilities
import aqua.semantics.algebra.types.ArrowType
import aqua.generator.ArrowGen
import aqua.parser.lexer.{Ability, Name, Token, Value}
import aqua.semantics.ArrowType
import cats.InjectK
import cats.data.{NonEmptyList, NonEmptyMap}
import cats.free.Free
@ -15,16 +14,16 @@ 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, ArrowGen]): Free[Alg, Boolean] =
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowType]): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineService[F](name, arrows))
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowGen]] =
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowType]] =
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]]] =
def getServiceId(name: Ability[F]): Free[Alg, Option[Value[F]]] =
Free.liftInject[Alg](GetServiceId[F](name))
def beginScope(token: Token[F]): Free[Alg, Unit] =

View File

@ -1,21 +1,19 @@
package aqua.semantics.algebra.abilities
package aqua.semantics.rules.abilities
import aqua.semantics.algebra.{ReportError, StackInterpreter}
import aqua.semantics.algebra.types.ArrowType
import aqua.generator.ArrowGen
import aqua.parser.lexer.{Ability, Name, Token, Value}
import aqua.semantics.rules.{ReportError, StackInterpreter}
import aqua.parser.lexer.{Name, Token, Value}
import aqua.semantics.ArrowType
import cats.data.{NonEmptyList, NonEmptyMap, State}
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))
with (AbilityOp[F, *] ~> State[X, *]) {
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowGen]]] =
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowType]]] =
getState.map(_.services.get(name))
override def apply[A](fa: AbilityOp[F, A]): State[X, A] =
@ -42,10 +40,10 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
report(
ga.arrow,
s"Service found, but arrow is undefined, available: ${arrows.value.keys.toNonEmptyList.toList.mkString(", ")}"
).as(Option.empty[ArrowGen])
).as(Option.empty[ArrowType])
)(a => State.pure(Some(a)))
case None =>
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowGen])
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType])
}
case s: SetServiceId[F] =>
@ -61,17 +59,10 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
case s: GetServiceId[F] =>
getState.flatMap(st =>
st.stack.flatMap(_.serviceIds.get(s.name)).headOption orElse st.rootServiceIds.get(s.name) match {
st.stack.flatMap(_.serviceIds.get(s.name.value)).headOption orElse st.rootServiceIds.get(s.name.value) 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]])
)
report(s.name, s"Service ID unresolved, use `${s.name} id` expression to set it")
.as(Option.empty[Value[F]])
case v => State.pure(v)
}
@ -99,7 +90,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, ArrowGen]] = Map.empty,
services: Map[String, NonEmptyMap[String, ArrowType]] = Map.empty,
rootServiceIds: Map[String, Value[F]] = Map.empty[String, Value[F]]
) {

View File

@ -1,8 +1,7 @@
package aqua.semantics.algebra.abilities
package aqua.semantics.rules.abilities
import aqua.semantics.algebra.types.ArrowType
import aqua.generator.ArrowGen
import aqua.parser.lexer.{Ability, Name, Token, Value}
import aqua.semantics.ArrowType
import cats.data.{NonEmptyList, NonEmptyMap}
sealed trait AbilityOp[F[_], T]
@ -11,13 +10,13 @@ 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, ArrowGen]) extends AbilityOp[F, Boolean]
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowType]) extends AbilityOp[F, Boolean]
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowGen]]
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowType]]
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 GetServiceId[F[_]](name: Ability[F]) extends AbilityOp[F, Option[Value[F]]]
case class BeginScope[F[_]](token: Token[F]) extends AbilityOp[F, Unit]

View File

@ -1,18 +1,17 @@
package aqua.semantics.algebra.names
package aqua.semantics.rules.names
import aqua.semantics.algebra.types.Type
import aqua.generator.ArrowGen
import aqua.parser.lexer.{Name, Token}
import aqua.semantics.{ArrowType, Type}
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[ArrowGen]]
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
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 DefineArrow[F[_]](name: Name[F], gen: ArrowType, isRoot: Boolean) extends NameOp[F, Boolean]
case class BeginScope[F[_]](token: Token[F]) extends NameOp[F, Unit]

View File

@ -1,8 +1,7 @@
package aqua.semantics.algebra.names
package aqua.semantics.rules.names
import aqua.semantics.algebra.types.{ArrowType, Type}
import aqua.generator.ArrowGen
import aqua.parser.lexer.{Name, Token}
import aqua.semantics.{ArrowType, Type}
import cats.InjectK
import cats.free.Free
@ -11,13 +10,13 @@ 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[ArrowGen]] =
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
Free.liftInject[Alg](ReadArrow(name))
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] =
def defineArrow(name: Name[F], gen: ArrowType, isRoot: Boolean): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineArrow(name, gen, isRoot))
def beginScope(token: Token[F]): Free[Alg, Unit] =

View File

@ -1,9 +1,8 @@
package aqua.semantics.algebra.names
package aqua.semantics.rules.names
import aqua.semantics.algebra.types.Type
import aqua.semantics.algebra.{ReportError, StackInterpreter}
import aqua.generator.ArrowGen
import aqua.semantics.rules.{ReportError, StackInterpreter}
import aqua.parser.lexer.Token
import aqua.semantics.{ArrowType, Type}
import cats.data.State
import cats.~>
import monocle.Lens
@ -19,11 +18,11 @@ 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)
case frame if frame.arrows.contains(name) => frame.arrows(name).`type`
} orElse st.rootArrows.get(name).map(_.`type`)
case frame if frame.arrows.contains(name) => frame.arrows(name)
} orElse st.rootArrows.get(name)
}
def readArrow(name: String): S[Option[ArrowGen]] =
def readArrow(name: String): S[Option[ArrowType]] =
getState.map { st =>
st.stack.flatMap(_.arrows.get(name)).headOption orElse st.rootArrows.get(name)
}
@ -42,7 +41,7 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
case None =>
getState.flatMap(st =>
report(ra.name, "Undefined arrow, available: " + st.allNames.mkString(", "))
.as(Option.empty[ArrowGen])
.as(Option.empty[ArrowType])
)
}
@ -75,7 +74,7 @@ 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, rootArrows: Map[String, ArrowGen] = Map.empty) {
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[String, ArrowType] = Map.empty) {
def allNames: LazyList[String] =
LazyList.from(stack).flatMap(s => s.names.keys ++ s.arrows.keys).appendedAll(rootArrows.keys)
@ -87,8 +86,8 @@ case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[St
case class NamesFrame[F[_]](
token: Token[F],
names: Map[String, Type] = Map.empty,
arrows: Map[String, ArrowGen] = Map.empty
arrows: Map[String, ArrowType] = 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))
def addArrow(n: String, g: ArrowType): NamesFrame[F] = copy[F](arrows = arrows.updated(n, g))
}

View File

@ -1,4 +1,4 @@
package aqua.semantics.algebra.scope
package aqua.semantics.rules.scope
import aqua.parser.lexer.Value
import cats.InjectK

View File

@ -1,6 +1,6 @@
package aqua.semantics.algebra.scope
package aqua.semantics.rules.scope
import aqua.semantics.algebra.{ReportError, StackInterpreter}
import aqua.semantics.rules.{ReportError, StackInterpreter}
import aqua.parser.lexer.Value
import cats.data.State
import cats.~>

View File

@ -1,4 +1,4 @@
package aqua.semantics.algebra.scope
package aqua.semantics.rules.scope
import aqua.parser.lexer.Value

View File

@ -1,6 +1,7 @@
package aqua.semantics.algebra.types
package aqua.semantics.rules.types
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
import aqua.semantics.{ArrowType, Type}
import cats.data.{NonEmptyList, NonEmptyMap}
sealed trait TypeOp[F[_], T]

View File

@ -1,6 +1,7 @@
package aqua.semantics.algebra.types
package aqua.semantics.rules.types
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
import aqua.semantics.{ArrowType, Type}
import cats.InjectK
import cats.data.{NonEmptyList, NonEmptyMap}
import cats.free.Free

View File

@ -1,6 +1,6 @@
package aqua.semantics.algebra.types
package aqua.semantics.rules.types
import aqua.semantics.algebra.ReportError
import aqua.semantics.rules.ReportError
import aqua.parser.lexer.{
ArrayTypeToken,
ArrowTypeToken,
@ -13,6 +13,7 @@ import aqua.parser.lexer.{
Token,
TypeToken
}
import aqua.semantics.{ArrayType, ArrowType, DataType, ProductType, Type}
import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, NonEmptyMap, State, ValidatedNel}
import cats.~>
@ -49,8 +50,8 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
case Valid(t) => State.pure[X, Option[ArrowType]](Some(t))
case Invalid(errs) =>
errs
.foldLeft[S[Option[ArrowType]]](State.pure(None)) {
case (n, (tkn, hint)) => report(tkn, hint) >> n
.foldLeft[S[Option[ArrowType]]](State.pure(None)) { case (n, (tkn, hint)) =>
report(tkn, hint) >> n
}
}
@ -102,17 +103,17 @@ case class TypesState[F[_]](
def resolveTypeToken(tt: TypeToken[F]): Option[Type] =
tt match {
case ArrayTypeToken(_, dtt) =>
resolveTypeToken(dtt).collect {
case it: DataType => ArrayType(it)
resolveTypeToken(dtt).collect { case it: DataType =>
ArrayType(it)
}
case ctt: CustomTypeToken[F] => strict.get(ctt.value)
case btt: BasicTypeToken[F] => Some(btt.value)
case ArrowTypeToken(_, args, res) =>
val strictArgs = args.map(resolveTypeToken).collect {
case Some(dt: DataType) => dt
val strictArgs = args.map(resolveTypeToken).collect { case Some(dt: DataType) =>
dt
}
val strictRes = res.flatMap(resolveTypeToken).collect {
case dt: DataType => dt
val strictRes = res.flatMap(resolveTypeToken).collect { case dt: DataType =>
dt
}
Option.when(strictRes.isDefined == res.isDefined && strictArgs.length == args.length)(
ArrowType(strictArgs, strictRes)

View File

@ -1,6 +1,5 @@
package aqua.parser
import aqua.semantics.algebra.types.LiteralType
import aqua.parser.expr.{AbilityIdExpr, CoalgebraExpr, FuncExpr, OnExpr}
import aqua.parser.lexer.{Ability, IntoField, Literal, Name, VarLambda}
import cats.data.NonEmptyList
@ -8,6 +7,7 @@ import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.semantics.LiteralType
import cats.Id
import scala.language.implicitConversions

View File

@ -1,7 +1,6 @@
package aqua.parser
import aqua.semantics.algebra.types.ScalarType.{bool, u64}
import aqua.semantics.algebra.types.{LiteralType, ScalarType}
import aqua.semantics.ScalarType.{bool, u64}
import aqua.parser.expr.FuncExpr
import aqua.parser.lexer.{
Ability,
@ -19,13 +18,14 @@ import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.semantics.ScalarType
import cats.Id
import scala.language.implicitConversions
class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
import aqua.semantics.algebra.types.ScalarType.{string, u32}
import aqua.semantics.ScalarType.{string, u32}
implicit def scToBt(sc: ScalarType): BasicTypeToken[Id] = BasicTypeToken[Id](sc)

View File

@ -1,10 +1,10 @@
package aqua.parser.lexer
import aqua.semantics.algebra.types.ScalarType
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.semantics.ScalarType
import cats.Id
import scala.language.implicitConversions

View File

@ -1,10 +1,10 @@
package aqua.parser.lexer
import aqua.semantics.algebra.types.LiteralType
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.semantics.LiteralType
import cats.Id
class ValueSpec extends AnyFlatSpec with Matchers with EitherValues {

View File

@ -1,7 +1,6 @@
package aqua.semantics
import aqua.parser.expr.ArrowTypeExpr
import aqua.semantics.algebra.types.ScalarType
import aqua.parser.lexer.{ArrowTypeToken, BasicTypeToken, CustomTypeToken, DataTypeToken, Name}
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec

View File

@ -1,16 +1,16 @@
package aqua.semantics.algebra
package aqua.semantics.rules
import aqua.semantics.algebra.types.{ArrayType, ArrowType, DataType, LiteralType, ProductType, Type}
import aqua.semantics.{ArrayType, ArrowType, DataType, LiteralType, ProductType, Type}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import cats.syntax.partialOrder._
import aqua.semantics.algebra.types.Type.typesPartialOrder
import aqua.semantics.Type.typesPartialOrder
import cats.data.NonEmptyMap
import cats.kernel.PartialOrder
class TypeSpec extends AnyFlatSpec with Matchers {
import aqua.semantics.algebra.types.ScalarType._
import aqua.semantics.ScalarType._
def `[]`(t: DataType): DataType = ArrayType(t)