mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-04-25 06:52:13 +00:00
Streams support (#87)
* #29 going to support streams * Added StreamName * StreamName removed * Streams support works * Debug println removed Co-authored-by: Dima <dmitry.shakhtarin@fluence.ai>
This commit is contained in:
parent
3b3ff24133
commit
27f2912c5f
@ -12,6 +12,7 @@ data User:
|
|||||||
service Test("test"):
|
service Test("test"):
|
||||||
getUserList: -> []User
|
getUserList: -> []User
|
||||||
doSomething: -> bool
|
doSomething: -> bool
|
||||||
|
check: bool -> ()
|
||||||
|
|
||||||
func initAfterJoin(me: User) -> []User:
|
func initAfterJoin(me: User) -> []User:
|
||||||
allUsers <- Test.getUserList()
|
allUsers <- Test.getUserList()
|
||||||
@ -26,3 +27,18 @@ func initAfterJoin(me: User) -> []User:
|
|||||||
Op.identity()
|
Op.identity()
|
||||||
par Test.doSomething()
|
par Test.doSomething()
|
||||||
<- allUsers
|
<- allUsers
|
||||||
|
|
||||||
|
func handleArr(arr: []bool):
|
||||||
|
for b <- arr:
|
||||||
|
Test.check(b)
|
||||||
|
|
||||||
|
|
||||||
|
func checkStreams(ch: []string) -> []bool:
|
||||||
|
stream: *bool
|
||||||
|
stream <- Peer.is_connected("write once")
|
||||||
|
stream <- Peer.is_connected("write twice")
|
||||||
|
for b <- ch:
|
||||||
|
on b:
|
||||||
|
stream <- Peer.is_connected(b)
|
||||||
|
handleArr(stream)
|
||||||
|
<- stream
|
@ -3,6 +3,7 @@ package aqua.backend.air
|
|||||||
import aqua.model._
|
import aqua.model._
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body._
|
import aqua.model.func.body._
|
||||||
|
import aqua.types.StreamType
|
||||||
import cats.Eval
|
import cats.Eval
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
@ -24,9 +25,13 @@ object AirGen {
|
|||||||
|
|
||||||
def valueToData(vm: ValueModel): DataView = vm match {
|
def valueToData(vm: ValueModel): DataView = vm match {
|
||||||
case LiteralModel(value) => DataView.StringScalar(value)
|
case LiteralModel(value) => DataView.StringScalar(value)
|
||||||
case VarModel(name, lambda) =>
|
case VarModel(name, t, lambda) =>
|
||||||
if (lambda.isEmpty) DataView.Variable(name)
|
val n = t match {
|
||||||
else DataView.VarLens(name, lambdaToString(lambda.toList))
|
case _: StreamType => "$" + name
|
||||||
|
case _ => name
|
||||||
|
}
|
||||||
|
if (lambda.isEmpty) DataView.Variable(n)
|
||||||
|
else DataView.VarLens(n, lambdaToString(lambda.toList))
|
||||||
}
|
}
|
||||||
|
|
||||||
def opsToSingle(ops: Chain[AirGen]): AirGen = ops.toList match {
|
def opsToSingle(ops: Chain[AirGen]): AirGen = ops.toList match {
|
||||||
@ -76,8 +81,11 @@ object AirGen {
|
|||||||
peerId.map(valueToData).getOrElse(DataView.InitPeerId),
|
peerId.map(valueToData).getOrElse(DataView.InitPeerId),
|
||||||
valueToData(serviceId),
|
valueToData(serviceId),
|
||||||
funcName,
|
funcName,
|
||||||
args.map(_.model).map(valueToData),
|
args.map(valueToData),
|
||||||
exportTo
|
exportTo.map {
|
||||||
|
case Call.Export(name, _: StreamType) => "$" + name
|
||||||
|
case Call.Export(name, _) => name
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ case class TypescriptFunc(func: FuncCallable) {
|
|||||||
}.mkString("\n")
|
}.mkString("\n")
|
||||||
|
|
||||||
val retType = func.ret
|
val retType = func.ret
|
||||||
.map(_.`type`)
|
.map(_._2)
|
||||||
.fold("void")(typeToTs)
|
.fold("void")(typeToTs)
|
||||||
|
|
||||||
val returnVal =
|
val returnVal =
|
||||||
@ -90,6 +90,7 @@ object TypescriptFunc {
|
|||||||
|
|
||||||
def typeToTs(t: Type): String = t match {
|
def typeToTs(t: Type): String = t match {
|
||||||
case ArrayType(t) => typeToTs(t) + "[]"
|
case ArrayType(t) => typeToTs(t) + "[]"
|
||||||
|
case StreamType(t) => typeToTs(t) + "[]"
|
||||||
case pt: ProductType =>
|
case pt: ProductType =>
|
||||||
s"{${pt.fields.map(typeToTs).toNel.map(kv => kv._1 + ":" + kv._2).toList.mkString(";")}}"
|
s"{${pt.fields.map(typeToTs).toNel.map(kv => kv._1 + ":" + kv._2).toList.mkString(";")}}"
|
||||||
case st: ScalarType if ScalarType.number(st) => "number"
|
case st: ScalarType if ScalarType.number(st) => "number"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package aqua.model
|
package aqua.model
|
||||||
|
|
||||||
|
import aqua.types.Type
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
|
|
||||||
sealed trait ValueModel {
|
sealed trait ValueModel {
|
||||||
@ -16,7 +17,8 @@ sealed trait LambdaModel
|
|||||||
case object IntoArrayModel extends LambdaModel
|
case object IntoArrayModel extends LambdaModel
|
||||||
case class IntoFieldModel(field: String) extends LambdaModel
|
case class IntoFieldModel(field: String) extends LambdaModel
|
||||||
|
|
||||||
case class VarModel(name: String, lambda: Chain[LambdaModel] = Chain.empty) extends ValueModel {
|
case class VarModel(name: String, `type`: Type, lambda: Chain[LambdaModel] = Chain.empty)
|
||||||
|
extends ValueModel {
|
||||||
def deriveFrom(vm: VarModel): VarModel = vm.copy(lambda = vm.lambda ++ lambda)
|
def deriveFrom(vm: VarModel): VarModel = vm.copy(lambda = vm.lambda ++ lambda)
|
||||||
|
|
||||||
override def resolveWith(map: Map[String, ValueModel]): ValueModel = {
|
override def resolveWith(map: Map[String, ValueModel]): ValueModel = {
|
||||||
@ -41,7 +43,7 @@ case class VarModel(name: String, lambda: Chain[LambdaModel] = Chain.empty) exte
|
|||||||
res <- two(variable)
|
res <- two(variable)
|
||||||
<- variable
|
<- variable
|
||||||
*/
|
*/
|
||||||
case vm @ VarModel(nn, _) if nn == name => deriveFrom(vm)
|
case vm @ VarModel(nn, _, _) if nn == name => deriveFrom(vm)
|
||||||
// it couldn't go to a cycle as long as the semantics protects it
|
// it couldn't go to a cycle as long as the semantics protects it
|
||||||
case _ => n.resolveWith(map)
|
case _ => n.resolveWith(map)
|
||||||
}
|
}
|
||||||
|
@ -9,20 +9,19 @@ import cats.syntax.functor._
|
|||||||
* @param args Argument definitions
|
* @param args Argument definitions
|
||||||
* @param callWith Values provided for arguments
|
* @param callWith Values provided for arguments
|
||||||
*/
|
*/
|
||||||
case class ArgsCall(args: List[ArgDef], callWith: List[Call.Arg]) {
|
case class ArgsCall(args: List[ArgDef], callWith: List[ValueModel]) {
|
||||||
// Both arguments (arg names and types how they seen from the function body)
|
// Both arguments (arg names and types how they seen from the function body)
|
||||||
// and values (value models and types how they seen on the call site)
|
// and values (value models and types how they seen on the call site)
|
||||||
lazy val zipped: List[(ArgDef, Call.Arg)] = args zip callWith
|
lazy val zipped: List[(ArgDef, ValueModel)] = args zip callWith
|
||||||
|
|
||||||
lazy val dataArgs: Map[String, ValueModel] =
|
lazy val dataArgs: Map[String, ValueModel] =
|
||||||
zipped.collect { case (ArgDef.Data(name, _), Call.Arg(value, _)) =>
|
zipped.collect { case (ArgDef.Data(name, _), value) =>
|
||||||
name -> value
|
name -> value
|
||||||
}.toMap
|
}.toMap
|
||||||
|
|
||||||
def arrowArgs(arrowsInScope: Map[String, FuncCallable]): Map[String, FuncCallable] =
|
def arrowArgs(arrowsInScope: Map[String, FuncCallable]): Map[String, FuncCallable] =
|
||||||
zipped.collect {
|
zipped.collect {
|
||||||
case (ArgDef.Arrow(name, _), Call.Arg(VarModel(value, _), _))
|
case (ArgDef.Arrow(name, _), VarModel(value, _, _)) if arrowsInScope.contains(value) =>
|
||||||
if arrowsInScope.contains(value) =>
|
|
||||||
name -> arrowsInScope(value)
|
name -> arrowsInScope(value)
|
||||||
}.toMap
|
}.toMap
|
||||||
}
|
}
|
||||||
@ -33,7 +32,7 @@ object ArgsCall {
|
|||||||
arrow: ArrowType,
|
arrow: ArrowType,
|
||||||
argPrefix: String = "arg",
|
argPrefix: String = "arg",
|
||||||
retName: String = "init_call_res"
|
retName: String = "init_call_res"
|
||||||
): (ArgsDef, Call, Option[Call.Arg]) = {
|
): (ArgsDef, Call, Option[Call.Export]) = {
|
||||||
val argNamesTypes = arrow.args.zipWithIndex.map(iv => iv.map(i => argPrefix + i).swap)
|
val argNamesTypes = arrow.args.zipWithIndex.map(iv => iv.map(i => argPrefix + i).swap)
|
||||||
|
|
||||||
val argsDef = ArgsDef(argNamesTypes.map {
|
val argsDef = ArgsDef(argNamesTypes.map {
|
||||||
@ -43,12 +42,12 @@ object ArgsCall {
|
|||||||
|
|
||||||
val call = Call(
|
val call = Call(
|
||||||
argNamesTypes.map { case (a, t) =>
|
argNamesTypes.map { case (a, t) =>
|
||||||
Call.Arg(VarModel(a), t)
|
VarModel(a, t)
|
||||||
},
|
},
|
||||||
arrow.res.as(retName)
|
arrow.res.map(Call.Export(retName, _))
|
||||||
)
|
)
|
||||||
|
|
||||||
(argsDef, call, arrow.res.map(t => Call.Arg(VarModel(retName), t)))
|
(argsDef, call, arrow.res.map(t => Call.Export(retName, t)))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,10 @@ case class ArgsDef(args: List[ArgDef]) {
|
|||||||
|
|
||||||
def types: List[Type] = args.map(_.`type`)
|
def types: List[Type] = args.map(_.`type`)
|
||||||
|
|
||||||
def toCallArgs: List[Call.Arg] = args.map(ad => Call.Arg(VarModel(ad.name), ad.`type`))
|
def toCallArgs: List[VarModel] = args.map(ad => VarModel(ad.name, ad.`type`))
|
||||||
|
|
||||||
lazy val dataArgNames: Chain[String] = Chain.fromSeq(args.collect { case ArgDef.Data(n, _) =>
|
lazy val dataArgs: Chain[ArgDef.Data] = Chain.fromSeq(args.collect { case ad: ArgDef.Data =>
|
||||||
n
|
ad
|
||||||
})
|
})
|
||||||
|
|
||||||
lazy val arrowArgs: Chain[ArgDef.Arrow] = Chain.fromSeq(args.collect { case ad: ArgDef.Arrow =>
|
lazy val arrowArgs: Chain[ArgDef.Arrow] = Chain.fromSeq(args.collect { case ad: ArgDef.Arrow =>
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package aqua.model.func
|
package aqua.model.func
|
||||||
|
|
||||||
import aqua.model.ValueModel
|
import aqua.model.{ValueModel, VarModel}
|
||||||
import aqua.types.Type
|
import aqua.types.Type
|
||||||
|
|
||||||
case class Call(args: List[Call.Arg], exportTo: Option[String]) {
|
case class Call(args: List[ValueModel], exportTo: Option[Call.Export]) {
|
||||||
|
|
||||||
def mapValues(f: ValueModel => ValueModel): Call =
|
def mapValues(f: ValueModel => ValueModel): Call =
|
||||||
Call(
|
Call(
|
||||||
args.map(_.mapValues(f)),
|
args.map(f),
|
||||||
exportTo
|
exportTo
|
||||||
)
|
)
|
||||||
|
|
||||||
def mapExport(f: String => String): Call = copy(exportTo = exportTo.map(f))
|
def mapExport(f: String => String): Call = copy(exportTo = exportTo.map(_.mapName(f)))
|
||||||
}
|
}
|
||||||
|
|
||||||
object Call {
|
object Call {
|
||||||
|
|
||||||
case class Arg(model: ValueModel, `type`: Type) {
|
case class Export(name: String, `type`: Type) {
|
||||||
|
def mapName(f: String => String): Export = copy(f(name))
|
||||||
|
|
||||||
def mapValues(f: ValueModel => ValueModel): Arg =
|
def model: ValueModel = VarModel(name, `type`)
|
||||||
copy(f(model))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package aqua.model.func
|
|||||||
|
|
||||||
import aqua.model.func.body.{CallArrowTag, FuncOp, OpTag}
|
import aqua.model.func.body.{CallArrowTag, FuncOp, OpTag}
|
||||||
import aqua.model.{ValueModel, VarModel}
|
import aqua.model.{ValueModel, VarModel}
|
||||||
import aqua.types.ArrowType
|
import aqua.types.{ArrowType, DataType, Type}
|
||||||
import cats.Eval
|
import cats.Eval
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
@ -11,7 +11,7 @@ case class FuncCallable(
|
|||||||
funcName: String,
|
funcName: String,
|
||||||
body: FuncOp,
|
body: FuncOp,
|
||||||
args: ArgsDef,
|
args: ArgsDef,
|
||||||
ret: Option[Call.Arg],
|
ret: Option[(ValueModel, Type)],
|
||||||
capturedArrows: Map[String, FuncCallable],
|
capturedArrows: Map[String, FuncCallable],
|
||||||
capturedValues: Map[String, ValueModel]
|
capturedValues: Map[String, ValueModel]
|
||||||
) {
|
) {
|
||||||
@ -19,7 +19,7 @@ case class FuncCallable(
|
|||||||
def arrowType: ArrowType =
|
def arrowType: ArrowType =
|
||||||
ArrowType(
|
ArrowType(
|
||||||
args.types,
|
args.types,
|
||||||
ret.map(_.`type`)
|
ret.map(_._2)
|
||||||
)
|
)
|
||||||
|
|
||||||
def findNewNames(forbidden: Set[String], introduce: Set[String]): Map[String, String] =
|
def findNewNames(forbidden: Set[String], introduce: Set[String]): Map[String, String] =
|
||||||
@ -52,7 +52,7 @@ case class FuncCallable(
|
|||||||
val treeWithValues = body.resolveValues(argsToData)
|
val treeWithValues = body.resolveValues(argsToData)
|
||||||
|
|
||||||
// Function body on its own defines some values; collect their names
|
// Function body on its own defines some values; collect their names
|
||||||
val treeDefines = treeWithValues.definesValueNames.value -- call.exportTo
|
val treeDefines = treeWithValues.definesValueNames.value -- call.exportTo.map(_.name)
|
||||||
|
|
||||||
// We have some names in scope (forbiddenNames), can't introduce them again; so find new names
|
// We have some names in scope (forbiddenNames), can't introduce them again; so find new names
|
||||||
val shouldRename = findNewNames(forbiddenNames, treeDefines)
|
val shouldRename = findNewNames(forbiddenNames, treeDefines)
|
||||||
@ -61,7 +61,7 @@ case class FuncCallable(
|
|||||||
if (shouldRename.isEmpty) treeWithValues else treeWithValues.rename(shouldRename)
|
if (shouldRename.isEmpty) treeWithValues else treeWithValues.rename(shouldRename)
|
||||||
|
|
||||||
// Result could be derived from arguments, or renamed; take care about that
|
// Result could be derived from arguments, or renamed; take care about that
|
||||||
val result = ret.map(_.model).map(_.resolveWith(argsToData)).map {
|
val result = ret.map(_._1).map(_.resolveWith(argsToData)).map {
|
||||||
case v: VarModel if shouldRename.contains(v.name) => v.copy(shouldRename(v.name))
|
case v: VarModel if shouldRename.contains(v.name) => v.copy(shouldRename(v.name))
|
||||||
case v => v
|
case v => v
|
||||||
}
|
}
|
||||||
@ -79,8 +79,8 @@ case class FuncCallable(
|
|||||||
case ((noNames, resolvedExports), CallArrowTag(fn, c)) if allArrows.contains(fn) =>
|
case ((noNames, resolvedExports), CallArrowTag(fn, c)) if allArrows.contains(fn) =>
|
||||||
// Apply arguments to a function – recursion
|
// Apply arguments to a function – recursion
|
||||||
val callResolved = c.mapValues(_.resolveWith(resolvedExports))
|
val callResolved = c.mapValues(_.resolveWith(resolvedExports))
|
||||||
val possibleArrowNames = callResolved.args.collect {
|
val possibleArrowNames = callResolved.args.collect { case VarModel(m, _: ArrowType, _) =>
|
||||||
case Call.Arg(VarModel(m, _), _: ArrowType) => m
|
m
|
||||||
}.toSet
|
}.toSet
|
||||||
|
|
||||||
val (appliedOp, value) =
|
val (appliedOp, value) =
|
||||||
@ -92,7 +92,10 @@ case class FuncCallable(
|
|||||||
// TODO: actually it's done and dropped – so keep and pass it instead
|
// TODO: actually it's done and dropped – so keep and pass it instead
|
||||||
val newNames = appliedOp.definesValueNames.value
|
val newNames = appliedOp.definesValueNames.value
|
||||||
// At the very end, will need to resolve what is used as results with the result values
|
// At the very end, will need to resolve what is used as results with the result values
|
||||||
(noNames ++ newNames, resolvedExports ++ c.exportTo.zip(value)) -> appliedOp.tree
|
(
|
||||||
|
noNames ++ newNames,
|
||||||
|
resolvedExports ++ c.exportTo.map(_.name).zip(value)
|
||||||
|
) -> appliedOp.tree
|
||||||
case (acc @ (_, resolvedExports), tag) =>
|
case (acc @ (_, resolvedExports), tag) =>
|
||||||
tag match {
|
tag match {
|
||||||
case CallArrowTag(fn, _) if !allArrows.contains(fn) =>
|
case CallArrowTag(fn, _) if !allArrows.contains(fn) =>
|
||||||
|
@ -2,11 +2,12 @@ package aqua.model.func
|
|||||||
|
|
||||||
import aqua.model.func.body.FuncOp
|
import aqua.model.func.body.FuncOp
|
||||||
import aqua.model.{Model, ValueModel}
|
import aqua.model.{Model, ValueModel}
|
||||||
|
import aqua.types.Type
|
||||||
|
|
||||||
case class FuncModel(
|
case class FuncModel(
|
||||||
name: String,
|
name: String,
|
||||||
args: ArgsDef,
|
args: ArgsDef,
|
||||||
ret: Option[Call.Arg],
|
ret: Option[(ValueModel, Type)],
|
||||||
body: FuncOp
|
body: FuncOp
|
||||||
) extends Model {
|
) extends Model {
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ case class FuncOp(tree: Cofree[Chain, OpTag]) extends Model {
|
|||||||
|
|
||||||
def definesValueNames: Eval[Set[String]] = cata[Set[String]] {
|
def definesValueNames: Eval[Set[String]] = cata[Set[String]] {
|
||||||
case (CallArrowTag(_, Call(_, Some(export))), acc) =>
|
case (CallArrowTag(_, Call(_, Some(export))), acc) =>
|
||||||
Eval.later(acc.foldLeft(Set(export))(_ ++ _))
|
Eval.later(acc.foldLeft(Set(export.name))(_ ++ _))
|
||||||
case (CallServiceTag(_, _, Call(_, Some(export)), _), acc) =>
|
case (CallServiceTag(_, _, Call(_, Some(export)), _), acc) =>
|
||||||
Eval.later(acc.foldLeft(Set(export))(_ ++ _))
|
Eval.later(acc.foldLeft(Set(export.name))(_ ++ _))
|
||||||
case (NextTag(export), acc) => Eval.later(acc.foldLeft(Set(export))(_ ++ _))
|
case (NextTag(export), acc) => Eval.later(acc.foldLeft(Set(export))(_ ++ _))
|
||||||
case (_, acc) => Eval.later(acc.foldLeft(Set.empty[String])(_ ++ _))
|
case (_, acc) => Eval.later(acc.foldLeft(Set.empty[String])(_ ++ _))
|
||||||
}
|
}
|
||||||
|
@ -3,23 +3,25 @@ package aqua.model.transform
|
|||||||
import aqua.model.ValueModel
|
import aqua.model.ValueModel
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body.{FuncOp, FuncOps}
|
import aqua.model.func.body.{FuncOp, FuncOps}
|
||||||
|
import aqua.types.DataType
|
||||||
|
|
||||||
trait ArgsProvider {
|
trait ArgsProvider {
|
||||||
def transform(op: FuncOp): FuncOp
|
def transform(op: FuncOp): FuncOp
|
||||||
}
|
}
|
||||||
|
|
||||||
case class ArgsFromService(dataServiceId: ValueModel, names: Seq[String]) extends ArgsProvider {
|
case class ArgsFromService(dataServiceId: ValueModel, names: List[(String, DataType)])
|
||||||
|
extends ArgsProvider {
|
||||||
|
|
||||||
def getDataOp(name: String): FuncOp =
|
def getDataOp(name: String, t: DataType): FuncOp =
|
||||||
FuncOps.callService(
|
FuncOps.callService(
|
||||||
dataServiceId,
|
dataServiceId,
|
||||||
name,
|
name,
|
||||||
Call(Nil, Some(name))
|
Call(Nil, Some(Call.Export(name, t)))
|
||||||
)
|
)
|
||||||
|
|
||||||
def transform(op: FuncOp): FuncOp =
|
def transform(op: FuncOp): FuncOp =
|
||||||
FuncOps.seq(
|
FuncOps.seq(
|
||||||
names.map(getDataOp) :+ op: _*
|
names.map((getDataOp _).tupled) :+ op: _*
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package aqua.model.transform
|
|||||||
import aqua.model.{LiteralModel, ValueModel}
|
import aqua.model.{LiteralModel, ValueModel}
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body.{FuncOp, FuncOps}
|
import aqua.model.func.body.{FuncOp, FuncOps}
|
||||||
import aqua.types.ScalarType.string
|
|
||||||
|
|
||||||
case class ErrorsCatcher(
|
case class ErrorsCatcher(
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
@ -28,7 +27,7 @@ case class ErrorsCatcher(
|
|||||||
|
|
||||||
object ErrorsCatcher {
|
object ErrorsCatcher {
|
||||||
// TODO not a string
|
// TODO not a string
|
||||||
val lastErrorArg: Call.Arg = Call.Arg(LiteralModel("%last_error%"), string)
|
val lastErrorArg: ValueModel = LiteralModel("%last_error%")
|
||||||
|
|
||||||
val lastErrorCall: Call = Call(
|
val lastErrorCall: Call = Call(
|
||||||
lastErrorArg :: Nil,
|
lastErrorArg :: Nil,
|
||||||
|
@ -5,6 +5,7 @@ import aqua.model.func.{ArgDef, ArgsCall, ArgsDef, Call, FuncCallable}
|
|||||||
import aqua.model.func.body.{FuncOp, FuncOps}
|
import aqua.model.func.body.{FuncOp, FuncOps}
|
||||||
import aqua.types.ArrowType
|
import aqua.types.ArrowType
|
||||||
import cats.Eval
|
import cats.Eval
|
||||||
|
import cats.syntax.apply._
|
||||||
|
|
||||||
case class ResolveFunc(
|
case class ResolveFunc(
|
||||||
transform: FuncOp => FuncOp,
|
transform: FuncOp => FuncOp,
|
||||||
@ -14,11 +15,11 @@ case class ResolveFunc(
|
|||||||
arrowCallbackPrefix: String = "init_peer_callable_"
|
arrowCallbackPrefix: String = "init_peer_callable_"
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def returnCallback(func: FuncCallable): Option[FuncOp] = func.ret.map { retArg =>
|
def returnCallback(func: FuncCallable): Option[FuncOp] = func.ret.map { case (retModel, _) =>
|
||||||
callback(
|
callback(
|
||||||
respFuncName,
|
respFuncName,
|
||||||
Call(
|
Call(
|
||||||
retArg :: Nil,
|
retModel :: Nil,
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -30,7 +31,7 @@ case class ResolveFunc(
|
|||||||
arrowCallbackPrefix + name,
|
arrowCallbackPrefix + name,
|
||||||
callback(name, call),
|
callback(name, call),
|
||||||
args,
|
args,
|
||||||
ret,
|
(ret.map(_.model), arrowType.res).mapN(_ -> _),
|
||||||
Map.empty,
|
Map.empty,
|
||||||
Map.empty
|
Map.empty
|
||||||
)
|
)
|
||||||
@ -63,7 +64,7 @@ case class ResolveFunc(
|
|||||||
def resolve(func: FuncCallable, funcArgName: String = "_func"): Eval[FuncOp] =
|
def resolve(func: FuncCallable, funcArgName: String = "_func"): Eval[FuncOp] =
|
||||||
wrap(func)
|
wrap(func)
|
||||||
.resolve(
|
.resolve(
|
||||||
Call(Call.Arg(VarModel(funcArgName), func.arrowType) :: Nil, None),
|
Call(VarModel(funcArgName, func.arrowType) :: Nil, None),
|
||||||
Map(funcArgName -> func),
|
Map(funcArgName -> func),
|
||||||
Set.empty
|
Set.empty
|
||||||
)
|
)
|
||||||
|
@ -3,6 +3,7 @@ package aqua.model.transform
|
|||||||
import aqua.model.func.body._
|
import aqua.model.func.body._
|
||||||
import aqua.model.func.FuncCallable
|
import aqua.model.func.FuncCallable
|
||||||
import aqua.model.VarModel
|
import aqua.model.VarModel
|
||||||
|
import aqua.types.ScalarType
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
|
|
||||||
@ -10,7 +11,7 @@ object Transform {
|
|||||||
|
|
||||||
def forClient(func: FuncCallable, conf: BodyConfig): Cofree[Chain, OpTag] = {
|
def forClient(func: FuncCallable, conf: BodyConfig): Cofree[Chain, OpTag] = {
|
||||||
val initCallable: InitPeerCallable = InitViaRelayCallable(
|
val initCallable: InitPeerCallable = InitViaRelayCallable(
|
||||||
Chain.one(VarModel(conf.relayVarName))
|
Chain.one(VarModel(conf.relayVarName, ScalarType.string))
|
||||||
)
|
)
|
||||||
val errorsCatcher = ErrorsCatcher(
|
val errorsCatcher = ErrorsCatcher(
|
||||||
enabled = conf.wrapWithXor,
|
enabled = conf.wrapWithXor,
|
||||||
@ -19,7 +20,12 @@ object Transform {
|
|||||||
initCallable
|
initCallable
|
||||||
)
|
)
|
||||||
val argsProvider: ArgsProvider =
|
val argsProvider: ArgsProvider =
|
||||||
ArgsFromService(conf.dataSrvId, conf.relayVarName +: func.args.dataArgNames.toList)
|
ArgsFromService(
|
||||||
|
conf.dataSrvId,
|
||||||
|
conf.relayVarName -> ScalarType.string :: func.args.dataArgs.toList.map(add =>
|
||||||
|
add.name -> add.dataType
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val transform =
|
val transform =
|
||||||
errorsCatcher.transform _ compose initCallable.transform compose argsProvider.transform
|
errorsCatcher.transform _ compose initCallable.transform compose argsProvider.transform
|
||||||
|
@ -1,16 +1,7 @@
|
|||||||
package aqua.model
|
package aqua.model
|
||||||
|
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body.{
|
import aqua.model.func.body._
|
||||||
CallServiceTag,
|
|
||||||
FuncOp,
|
|
||||||
FuncOps,
|
|
||||||
MatchMismatchTag,
|
|
||||||
OnTag,
|
|
||||||
OpTag,
|
|
||||||
SeqTag,
|
|
||||||
XorTag
|
|
||||||
}
|
|
||||||
import aqua.model.transform.BodyConfig
|
import aqua.model.transform.BodyConfig
|
||||||
import aqua.types.ScalarType
|
import aqua.types.ScalarType
|
||||||
import cats.Eval
|
import cats.Eval
|
||||||
@ -30,10 +21,9 @@ case class Node(tag: OpTag, ops: List[Node] = Nil) {
|
|||||||
else
|
else
|
||||||
Console.BLUE + left + Console.RED + " != " + Console.YELLOW + right)
|
Console.BLUE + left + Console.RED + " != " + Console.YELLOW + right)
|
||||||
|
|
||||||
private def diffArg(left: Call.Arg, right: Call.Arg): String =
|
private def diffArg(left: ValueModel, right: ValueModel): String =
|
||||||
Console.GREEN + "(" +
|
Console.GREEN + "(" +
|
||||||
equalOrNot(left.model, right.model) + Console.GREEN + ", " +
|
equalOrNot(left, right) + Console.GREEN + ")"
|
||||||
equalOrNot(left.`type`, right.`type`) + Console.GREEN + ")"
|
|
||||||
|
|
||||||
private def diffCall(left: Call, right: Call): String =
|
private def diffCall(left: Call, right: Call): String =
|
||||||
if (left == right) Console.GREEN + left + Console.RESET
|
if (left == right) Console.GREEN + left + Console.RESET
|
||||||
@ -95,7 +85,7 @@ object Node {
|
|||||||
Cofree(tree.tag, Eval.later(Chain.fromSeq(tree.ops.map(nodeToCof))))
|
Cofree(tree.tag, Eval.later(Chain.fromSeq(tree.ops.map(nodeToCof))))
|
||||||
|
|
||||||
val relay = LiteralModel("relay")
|
val relay = LiteralModel("relay")
|
||||||
val relayV = VarModel("relay")
|
val relayV = VarModel("relay", ScalarType.string)
|
||||||
val initPeer = LiteralModel.initPeerId
|
val initPeer = LiteralModel.initPeerId
|
||||||
val emptyCall = Call(Nil, None)
|
val emptyCall = Call(Nil, None)
|
||||||
val otherPeer = LiteralModel("other-peer")
|
val otherPeer = LiteralModel("other-peer")
|
||||||
@ -111,7 +101,7 @@ object Node {
|
|||||||
CallServiceTag(
|
CallServiceTag(
|
||||||
bc.errorHandlingCallback,
|
bc.errorHandlingCallback,
|
||||||
bc.errorFuncName,
|
bc.errorFuncName,
|
||||||
Call(Call.Arg(LiteralModel("%last_error%"), ScalarType.string) :: Nil, None),
|
Call(LiteralModel("%last_error%") :: Nil, None),
|
||||||
Option(on)
|
Option(on)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -120,7 +110,7 @@ object Node {
|
|||||||
CallServiceTag(
|
CallServiceTag(
|
||||||
bc.callbackSrvId,
|
bc.callbackSrvId,
|
||||||
bc.respFuncName,
|
bc.respFuncName,
|
||||||
Call(Call.Arg(value, ScalarType.string) :: Nil, None),
|
Call(value :: Nil, None),
|
||||||
Option(on)
|
Option(on)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -129,7 +119,7 @@ object Node {
|
|||||||
CallServiceTag(
|
CallServiceTag(
|
||||||
bc.dataSrvId,
|
bc.dataSrvId,
|
||||||
name,
|
name,
|
||||||
Call(Nil, Some(name)),
|
Call(Nil, Some(Call.Export(name, ScalarType.string))),
|
||||||
Option(on)
|
Option(on)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -19,7 +19,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
|||||||
"ret",
|
"ret",
|
||||||
FuncOp(on(otherPeer, Nil, call(1))),
|
FuncOp(on(otherPeer, Nil, call(1))),
|
||||||
ArgsDef.empty,
|
ArgsDef.empty,
|
||||||
Some(Call.Arg(ret, ScalarType.string)),
|
Some((ret, ScalarType.string)),
|
||||||
Map.empty,
|
Map.empty,
|
||||||
Map.empty
|
Map.empty
|
||||||
)
|
)
|
||||||
@ -57,7 +57,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
|||||||
"ret",
|
"ret",
|
||||||
FuncOp(seq(call(0), on(otherPeer, Nil, call(1)))),
|
FuncOp(seq(call(0), on(otherPeer, Nil, call(1)))),
|
||||||
ArgsDef.empty,
|
ArgsDef.empty,
|
||||||
Some(Call.Arg(ret, ScalarType.string)),
|
Some((ret, ScalarType.string)),
|
||||||
Map.empty,
|
Map.empty,
|
||||||
Map.empty
|
Map.empty
|
||||||
)
|
)
|
||||||
@ -104,9 +104,18 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
|||||||
val f1: FuncCallable =
|
val f1: FuncCallable =
|
||||||
FuncCallable(
|
FuncCallable(
|
||||||
"f1",
|
"f1",
|
||||||
FuncOp(Node(CallServiceTag(LiteralModel("\"srv1\""), "foo", Call(Nil, Some("v")), None))),
|
FuncOp(
|
||||||
|
Node(
|
||||||
|
CallServiceTag(
|
||||||
|
LiteralModel("\"srv1\""),
|
||||||
|
"foo",
|
||||||
|
Call(Nil, Some(Call.Export("v", ScalarType.string))),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
ArgsDef.empty,
|
ArgsDef.empty,
|
||||||
Some(Call.Arg(VarModel("v"), ScalarType.string)),
|
Some((VarModel("v", ScalarType.string), ScalarType.string)),
|
||||||
Map.empty,
|
Map.empty,
|
||||||
Map.empty
|
Map.empty
|
||||||
)
|
)
|
||||||
@ -115,10 +124,10 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
|||||||
FuncCallable(
|
FuncCallable(
|
||||||
"f2",
|
"f2",
|
||||||
FuncOp(
|
FuncOp(
|
||||||
Node(CallArrowTag("callable", Call(Nil, Some("v"))))
|
Node(CallArrowTag("callable", Call(Nil, Some(Call.Export("v", ScalarType.string)))))
|
||||||
),
|
),
|
||||||
ArgsDef.empty,
|
ArgsDef.empty,
|
||||||
Some(Call.Arg(VarModel("v"), ScalarType.string)),
|
Some((VarModel("v", ScalarType.string), ScalarType.string)),
|
||||||
Map("callable" -> f1),
|
Map("callable" -> f1),
|
||||||
Map.empty
|
Map.empty
|
||||||
)
|
)
|
||||||
@ -134,12 +143,17 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
|||||||
seq(
|
seq(
|
||||||
dataCall(bc, "relay", initPeer),
|
dataCall(bc, "relay", initPeer),
|
||||||
Node(
|
Node(
|
||||||
CallServiceTag(LiteralModel("\"srv1\""), "foo", Call(Nil, Some("v")), Some(initPeer))
|
CallServiceTag(
|
||||||
|
LiteralModel("\"srv1\""),
|
||||||
|
"foo",
|
||||||
|
Call(Nil, Some(Call.Export("v", ScalarType.string))),
|
||||||
|
Some(initPeer)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
on(
|
on(
|
||||||
initPeer,
|
initPeer,
|
||||||
relayV :: Nil,
|
relayV :: Nil,
|
||||||
respCall(bc, VarModel("v"), initPeer)
|
respCall(bc, VarModel("v", ScalarType.string), initPeer)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,8 @@ case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends
|
|||||||
object ArrowTypeExpr extends Expr.Leaf {
|
object ArrowTypeExpr extends Expr.Leaf {
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[ArrowTypeExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[ArrowTypeExpr[F]] =
|
||||||
(Name.p[F] ~ ((` : ` *> ArrowTypeToken.`arrowdef`[F]) | ArrowTypeToken.`arrowWithNames`)).map {
|
(Name
|
||||||
|
.p[F] ~ ((` : ` *> ArrowTypeToken.`arrowdef`[F]) | ArrowTypeToken.`arrowWithNames`)).map {
|
||||||
case (name, t) =>
|
case (name, t) =>
|
||||||
ArrowTypeExpr(name, t)
|
ArrowTypeExpr(name, t)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package aqua.parser.expr
|
||||||
|
|
||||||
|
import aqua.parser.Expr
|
||||||
|
import aqua.parser.lexer.{Name, Token, TypeToken}
|
||||||
|
import aqua.parser.lift.LiftParser
|
||||||
|
import cats.Comonad
|
||||||
|
import cats.parse.Parser
|
||||||
|
import Token._
|
||||||
|
|
||||||
|
case class DeclareStreamExpr[F[_]](name: Name[F], `type`: TypeToken[F]) extends Expr[F]
|
||||||
|
|
||||||
|
object DeclareStreamExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
override def p[F[_]: LiftParser: Comonad]: Parser[DeclareStreamExpr[F]] =
|
||||||
|
((Name.p[F] <* ` : `) ~ TypeToken.`typedef`[F]).map { case (name, t) =>
|
||||||
|
DeclareStreamExpr(name, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -12,7 +12,7 @@ case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends
|
|||||||
object FieldTypeExpr extends Expr.Leaf {
|
object FieldTypeExpr extends Expr.Leaf {
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[FieldTypeExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[FieldTypeExpr[F]] =
|
||||||
((Name.p[F] <* ` : `) ~ DataTypeToken.`datatypedef`[F]).map {
|
((Name.p[F] <* ` : `) ~ DataTypeToken.`datatypedef`[F]).map { case (name, t) =>
|
||||||
case (name, t) => FieldTypeExpr(name, t)
|
FieldTypeExpr(name, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,8 @@ object FuncExpr
|
|||||||
ParExpr,
|
ParExpr,
|
||||||
ForExpr,
|
ForExpr,
|
||||||
IfExpr,
|
IfExpr,
|
||||||
ElseOtherwiseExpr
|
ElseOtherwiseExpr,
|
||||||
|
DeclareStreamExpr
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||||
|
@ -10,7 +10,7 @@ case class Arg[F[_]](name: Name[F], `type`: TypeToken[F])
|
|||||||
object Arg {
|
object Arg {
|
||||||
|
|
||||||
def p[F[_]: LiftParser: Comonad]: P[Arg[F]] =
|
def p[F[_]: LiftParser: Comonad]: P[Arg[F]] =
|
||||||
((Name.p[F] <* ` : `) ~ TypeToken.`typedef`[F]).map {
|
((Name.p[F] <* ` : `) ~ TypeToken.`typedef`[F]).map { case (name, t) =>
|
||||||
case (name, t) => Arg(name, t)
|
Arg(name, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,7 @@ object Token {
|
|||||||
val `:` : P[Unit] = P.char(':')
|
val `:` : P[Unit] = P.char(':')
|
||||||
val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?)
|
val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?)
|
||||||
|
|
||||||
val `name`: P[String] = (P.charIn(az) ~ P.charsWhile(anum_).?).map { case (c, s) ⇒
|
val `name`: P[String] = (P.charIn(az) ~ P.charsWhile(anum_).?).string
|
||||||
c.toString ++ s.getOrElse("")
|
|
||||||
}
|
|
||||||
|
|
||||||
val `Class`: P[String] = (P.charIn(AZ) ~ P.charsWhile(anum_).?).map { case (c, s) ⇒
|
val `Class`: P[String] = (P.charIn(AZ) ~ P.charsWhile(anum_).?).map { case (c, s) ⇒
|
||||||
c.toString ++ s.getOrElse("")
|
c.toString ++ s.getOrElse("")
|
||||||
@ -59,8 +57,10 @@ object Token {
|
|||||||
val `.` : P[Unit] = P.char('.')
|
val `.` : P[Unit] = P.char('.')
|
||||||
val `"` : P[Unit] = P.char('"')
|
val `"` : P[Unit] = P.char('"')
|
||||||
val `*` : P[Unit] = P.char('*')
|
val `*` : P[Unit] = P.char('*')
|
||||||
|
val `[]` : P[Unit] = P.string("[]")
|
||||||
val `(` : P[Unit] = ` `.?.with1 *> P.char('(') <* ` `.?
|
val `(` : P[Unit] = ` `.?.with1 *> P.char('(') <* ` `.?
|
||||||
val `)` : P[Unit] = ` `.?.with1 *> P.char(')') <* ` `.?
|
val `)` : P[Unit] = ` `.?.with1 *> P.char(')') <* ` `.?
|
||||||
|
val `()` : P[Unit] = P.string("()")
|
||||||
val ` -> ` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
val ` -> ` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
||||||
val ` <- ` : P[Unit] = (` `.?.with1 *> P.string("<-") <* ` `.?).backtrack
|
val ` <- ` : P[Unit] = (` `.?.with1 *> P.string("<-") <* ` `.?).backtrack
|
||||||
val `=` : P[Unit] = P.string("=")
|
val `=` : P[Unit] = P.string("=")
|
||||||
|
@ -17,6 +17,18 @@ case class ArrayTypeToken[F[_]: Comonad](override val unit: F[Unit], data: DataT
|
|||||||
override def as[T](v: T): F[T] = unit.as(v)
|
override def as[T](v: T): F[T] = unit.as(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class StreamTypeToken[F[_]: Comonad](override val unit: F[Unit], data: DataTypeToken[F])
|
||||||
|
extends DataTypeToken[F] {
|
||||||
|
override def as[T](v: T): F[T] = unit.as(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
object StreamTypeToken {
|
||||||
|
|
||||||
|
def `streamtypedef`[F[_]: LiftParser: Comonad]: P[StreamTypeToken[F]] =
|
||||||
|
(`*`.lift ~ DataTypeToken.`datatypedef`[F]).map(ud => StreamTypeToken(ud._1, ud._2))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
case class CustomTypeToken[F[_]: Comonad](name: F[String]) extends DataTypeToken[F] {
|
case class CustomTypeToken[F[_]: Comonad](name: F[String]) extends DataTypeToken[F] {
|
||||||
override def as[T](v: T): F[T] = name.as(v)
|
override def as[T](v: T): F[T] = name.as(v)
|
||||||
|
|
||||||
@ -64,7 +76,7 @@ object ArrowTypeToken {
|
|||||||
def `arrowdef`[F[_]: LiftParser: Comonad]: P[ArrowTypeToken[F]] =
|
def `arrowdef`[F[_]: LiftParser: Comonad]: P[ArrowTypeToken[F]] =
|
||||||
(comma0(DataTypeToken.`datatypedef`).with1 ~ ` -> `.lift ~
|
(comma0(DataTypeToken.`datatypedef`).with1 ~ ` -> `.lift ~
|
||||||
(DataTypeToken.`datatypedef`
|
(DataTypeToken.`datatypedef`
|
||||||
.map(Some(_)) | P.string("()").as(None))).map { case ((args, point), res) ⇒
|
.map(Some(_)) | `()`.as(None))).map { case ((args, point), res) ⇒
|
||||||
ArrowTypeToken(point, args, res)
|
ArrowTypeToken(point, args, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,27 +87,23 @@ object ArrowTypeToken {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AquaArrowType[F[_]](args: List[TypeToken[F]], res: Option[DataTypeToken[F]])
|
|
||||||
extends ArrowDef[F] {
|
|
||||||
override def argTypes: List[TypeToken[F]] = args
|
|
||||||
|
|
||||||
override def resType: Option[DataTypeToken[F]] = res
|
|
||||||
}
|
|
||||||
|
|
||||||
object DataTypeToken {
|
object DataTypeToken {
|
||||||
|
|
||||||
def `arraytypedef`[F[_]: LiftParser: Comonad]: P[ArrayTypeToken[F]] =
|
def `arraytypedef`[F[_]: LiftParser: Comonad]: P[ArrayTypeToken[F]] =
|
||||||
(P.string("[]").lift ~ `datatypedef`[F]).map(ud => ArrayTypeToken(ud._1, ud._2))
|
(`[]`.lift ~ `datatypedef`[F]).map(ud => ArrayTypeToken(ud._1, ud._2))
|
||||||
|
|
||||||
def `datatypedef`[F[_]: LiftParser: Comonad]: P[DataTypeToken[F]] =
|
def `datatypedef`[F[_]: LiftParser: Comonad]: P[DataTypeToken[F]] =
|
||||||
P.oneOf(
|
P.oneOf(
|
||||||
P.defer(`arraytypedef`[F]) :: BasicTypeToken.`basictypedef`[F] :: CustomTypeToken.ct[F] :: Nil
|
P.defer(`arraytypedef`[F]) :: P.defer(StreamTypeToken.`streamtypedef`) :: BasicTypeToken
|
||||||
|
.`basictypedef`[F] :: CustomTypeToken.ct[F] :: Nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object TypeToken {
|
object TypeToken {
|
||||||
|
|
||||||
def `typedef`[F[_]: LiftParser: Comonad]: P[TypeToken[F]] =
|
def `typedef`[F[_]: LiftParser: Comonad]: P[TypeToken[F]] =
|
||||||
P.oneOf(ArrowTypeToken.`arrowdef`.backtrack :: DataTypeToken.`datatypedef` :: Nil)
|
P.oneOf(
|
||||||
|
ArrowTypeToken.`arrowdef`.backtrack :: DataTypeToken.`datatypedef` :: Nil
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ object ExprSem {
|
|||||||
case expr: AbilityIdExpr[F] => new AbilityIdSem(expr).program[G]
|
case expr: AbilityIdExpr[F] => new AbilityIdSem(expr).program[G]
|
||||||
case expr: AliasExpr[F] => new AliasSem(expr).program[G]
|
case expr: AliasExpr[F] => new AliasSem(expr).program[G]
|
||||||
case expr: ConstantExpr[F] => new ConstantSem(expr).program[G]
|
case expr: ConstantExpr[F] => new ConstantSem(expr).program[G]
|
||||||
|
case expr: DeclareStreamExpr[F] => new DeclareStreamSem(expr).program[G]
|
||||||
case expr: ArrowTypeExpr[F] => new ArrowTypeSem(expr).program[G]
|
case expr: ArrowTypeExpr[F] => new ArrowTypeSem(expr).program[G]
|
||||||
case expr: CallArrowExpr[F] => new CallArrowSem(expr).program[G]
|
case expr: CallArrowExpr[F] => new CallArrowSem(expr).program[G]
|
||||||
case expr: DataStructExpr[F] => new DataStructSem(expr).program[G]
|
case expr: DataStructExpr[F] => new DataStructSem(expr).program[G]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package aqua.semantics.expr
|
package aqua.semantics.expr
|
||||||
|
|
||||||
import aqua.model.Model
|
import aqua.model.{Model, ValueModel}
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||||
import aqua.parser.expr.CallArrowExpr
|
import aqua.parser.expr.CallArrowExpr
|
||||||
@ -9,7 +9,7 @@ import aqua.semantics.rules.ValuesAlgebra
|
|||||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||||
import aqua.semantics.rules.names.NamesAlgebra
|
import aqua.semantics.rules.names.NamesAlgebra
|
||||||
import aqua.semantics.rules.types.TypesAlgebra
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
import aqua.types.ArrowType
|
import aqua.types.{ArrowType, ScalarType, StreamType, Type}
|
||||||
import cats.free.Free
|
import cats.free.Free
|
||||||
import cats.syntax.apply._
|
import cats.syntax.apply._
|
||||||
import cats.syntax.flatMap._
|
import cats.syntax.flatMap._
|
||||||
@ -25,16 +25,29 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
|||||||
at: ArrowType
|
at: ArrowType
|
||||||
)(implicit
|
)(implicit
|
||||||
N: NamesAlgebra[F, Alg],
|
N: NamesAlgebra[F, Alg],
|
||||||
|
T: TypesAlgebra[F, Alg],
|
||||||
V: ValuesAlgebra[F, Alg]
|
V: ValuesAlgebra[F, Alg]
|
||||||
): Free[Alg, List[Call.Arg]] =
|
): Free[Alg, (List[ValueModel], Option[Type])] =
|
||||||
V.checkArguments(expr.funcName, at, args) >> variable
|
V.checkArguments(expr.funcName, at, args) >> variable
|
||||||
.fold(freeUnit[Alg])(exportVar =>
|
.fold(freeUnit[Alg].as(Option.empty[Type]))(exportVar =>
|
||||||
at.res.fold(
|
at.res.fold(
|
||||||
// TODO: error! we're trying to export variable, but function has no export type
|
// TODO: error! we're trying to export variable, but function has no export type
|
||||||
freeUnit[Alg]
|
freeUnit[Alg].as(Option.empty[Type])
|
||||||
)(resType => N.define(exportVar, resType).void)
|
)(resType =>
|
||||||
) >> args.foldLeft(Free.pure[Alg, List[Call.Arg]](Nil)) { case (acc, v) =>
|
N.read(exportVar, mustBeDefined = false).flatMap {
|
||||||
(acc, V.resolveType(v)).mapN((a, b) => a ++ b.map(Call.Arg(ValuesAlgebra.valueToModel(v), _)))
|
case Some(t @ StreamType(st)) =>
|
||||||
|
T.ensureTypeMatches(exportVar, st, resType).as(Option(t))
|
||||||
|
case _ => N.define(exportVar, resType).as(at.res)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) >>= { (v: Option[Type]) =>
|
||||||
|
args
|
||||||
|
.foldLeft(Free.pure[Alg, List[ValueModel]](Nil)) { case (acc, v) =>
|
||||||
|
(acc, V.resolveType(v)).mapN((a, b) =>
|
||||||
|
a ++ b.map(bt => ValuesAlgebra.valueToModel(v, bt))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.map(_ -> v)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def toModel[Alg[_]](implicit
|
private def toModel[Alg[_]](implicit
|
||||||
@ -50,30 +63,29 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
|||||||
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
|
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
|
||||||
case _ => None
|
case _ => None
|
||||||
}.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { case (arrowType, serviceId) =>
|
}.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { case (arrowType, serviceId) =>
|
||||||
checkArgsRes(arrowType)
|
checkArgsRes(arrowType).map { case (argsResolved, t) =>
|
||||||
.map(argsResolved =>
|
FuncOp.leaf(
|
||||||
FuncOp.leaf(
|
CallServiceTag(
|
||||||
CallServiceTag(
|
// TODO service id type should not be hardcoded
|
||||||
serviceId = ValuesAlgebra.valueToModel(serviceId),
|
serviceId = ValuesAlgebra.valueToModel(serviceId, ScalarType.string),
|
||||||
funcName = funcName.value,
|
funcName = funcName.value,
|
||||||
Call(argsResolved, variable.map(_.value))
|
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
.map(Option(_))
|
.map(Option(_))
|
||||||
})
|
})
|
||||||
case None =>
|
case None =>
|
||||||
N.readArrow(funcName)
|
N.readArrow(funcName)
|
||||||
.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { arrowType =>
|
.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { arrowType =>
|
||||||
checkArgsRes(arrowType)
|
checkArgsRes(arrowType).map { case (argsResolved, t) =>
|
||||||
.map(argsResolved =>
|
FuncOp.leaf(
|
||||||
FuncOp.leaf(
|
CallArrowTag(
|
||||||
CallArrowTag(
|
funcName = funcName.value,
|
||||||
funcName = funcName.value,
|
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||||
Call(argsResolved, variable.map(_.value))
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
.map(Option(_))
|
.map(Option(_))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -84,6 +96,6 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
|||||||
T: TypesAlgebra[F, Alg],
|
T: TypesAlgebra[F, Alg],
|
||||||
V: ValuesAlgebra[F, Alg]
|
V: ValuesAlgebra[F, Alg]
|
||||||
): Prog[Alg, Model] =
|
): Prog[Alg, Model] =
|
||||||
toModel[Alg].map(_.getOrElse(Model.error("Coalgebra can't be converted to Model")))
|
toModel[Alg].map(_.getOrElse(Model.error("CallArrow can't be converted to Model")))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ class ConstantSem[F[_]](val expr: ConstantExpr[F]) extends AnyVal {
|
|||||||
case (_, Some(t), _) =>
|
case (_, Some(t), _) =>
|
||||||
N.defineConstant(expr.name, t) as (ConstantModel(
|
N.defineConstant(expr.name, t) as (ConstantModel(
|
||||||
expr.name.value,
|
expr.name.value,
|
||||||
ValuesAlgebra.valueToModel(expr.value)
|
ValuesAlgebra.valueToModel(expr.value, t)
|
||||||
): Model)
|
): Model)
|
||||||
}
|
}
|
||||||
} yield model
|
} yield model
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package aqua.semantics.expr
|
||||||
|
|
||||||
|
import aqua.model.Model
|
||||||
|
import aqua.parser.expr.DeclareStreamExpr
|
||||||
|
import aqua.semantics.Prog
|
||||||
|
import aqua.semantics.rules.names.NamesAlgebra
|
||||||
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
|
import aqua.types.{ArrayType, StreamType}
|
||||||
|
import cats.free.Free
|
||||||
|
|
||||||
|
class DeclareStreamSem[F[_]](val expr: DeclareStreamExpr[F]) {
|
||||||
|
|
||||||
|
def program[Alg[_]](implicit
|
||||||
|
N: NamesAlgebra[F, Alg],
|
||||||
|
T: TypesAlgebra[F, Alg]
|
||||||
|
): Prog[Alg, Model] =
|
||||||
|
Prog.leaf(
|
||||||
|
T.resolveType(expr.`type`)
|
||||||
|
.flatMap {
|
||||||
|
case Some(t: StreamType) =>
|
||||||
|
N.define(expr.name, t)
|
||||||
|
case Some(at @ ArrayType(t)) =>
|
||||||
|
T.ensureTypeMatches(expr.`type`, StreamType(t), at)
|
||||||
|
case Some(t) =>
|
||||||
|
T.ensureTypeMatches(expr.`type`, StreamType(t), t)
|
||||||
|
case None =>
|
||||||
|
Free.pure[Alg, Boolean](false)
|
||||||
|
}
|
||||||
|
.map {
|
||||||
|
case true => Model.empty(s"Name `${expr.name.value}` defined successfully")
|
||||||
|
case false => Model.error(s"Name `${expr.name.value}` not defined")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
@ -7,7 +7,7 @@ import aqua.semantics.Prog
|
|||||||
import aqua.semantics.rules.ValuesAlgebra
|
import aqua.semantics.rules.ValuesAlgebra
|
||||||
import aqua.semantics.rules.names.NamesAlgebra
|
import aqua.semantics.rules.names.NamesAlgebra
|
||||||
import aqua.semantics.rules.types.TypesAlgebra
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
import aqua.types.{ArrayType, DataType}
|
import aqua.types.{ArrayType, StreamType, Type}
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.free.Free
|
import cats.free.Free
|
||||||
import cats.syntax.flatMap._
|
import cats.syntax.flatMap._
|
||||||
@ -21,18 +21,20 @@ class ForSem[F[_]](val expr: ForExpr[F]) extends AnyVal {
|
|||||||
T: TypesAlgebra[F, Alg]
|
T: TypesAlgebra[F, Alg]
|
||||||
): Prog[Alg, Model] =
|
): Prog[Alg, Model] =
|
||||||
Prog.around(
|
Prog.around(
|
||||||
N.beginScope(expr.item) >> V.resolveType(expr.iterable).flatMap {
|
N.beginScope(expr.item) >> V.resolveType(expr.iterable).flatMap[Option[Type]] {
|
||||||
case Some(ArrayType(t)) =>
|
case Some(at @ ArrayType(t)) =>
|
||||||
N.define(expr.item, t).void
|
N.define(expr.item, t).as(Option(at))
|
||||||
case Some(dt: DataType) => T.ensureTypeMatches(expr.iterable, ArrayType(dt), dt).void
|
case Some(st @ StreamType(t)) =>
|
||||||
case _ => Free.pure[Alg, Unit](())
|
N.define(expr.item, t).as(Option(st))
|
||||||
|
case Some(dt: Type) =>
|
||||||
|
T.ensureTypeMatches(expr.iterable, ArrayType(dt), dt).as(Option.empty[Type])
|
||||||
|
case _ => Free.pure[Alg, Option[Type]](None)
|
||||||
},
|
},
|
||||||
(_: Unit, ops: Model) =>
|
(stOpt: Option[Type], ops: Model) =>
|
||||||
// TODO streams should escape the scope
|
N.endScope() as ((stOpt, ops) match {
|
||||||
N.endScope() as (ops match {
|
case (Some(t), op: FuncOp) =>
|
||||||
case op: FuncOp =>
|
|
||||||
FuncOp.wrap(
|
FuncOp.wrap(
|
||||||
ForTag(expr.item.value, ValuesAlgebra.valueToModel(expr.iterable)),
|
ForTag(expr.item.value, ValuesAlgebra.valueToModel(expr.iterable, t)),
|
||||||
FuncOp.node(
|
FuncOp.node(
|
||||||
expr.par.fold[OpTag](SeqTag)(_ => ParTag),
|
expr.par.fold[OpTag](SeqTag)(_ => ParTag),
|
||||||
Chain(op, FuncOp.leaf(NextTag(expr.item.value)))
|
Chain(op, FuncOp.leaf(NextTag(expr.item.value)))
|
||||||
|
@ -16,6 +16,7 @@ import cats.data.Chain
|
|||||||
import cats.free.Free
|
import cats.free.Free
|
||||||
import cats.syntax.flatMap._
|
import cats.syntax.flatMap._
|
||||||
import cats.syntax.functor._
|
import cats.syntax.functor._
|
||||||
|
import cats.syntax.apply._
|
||||||
|
|
||||||
class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||||
import expr._
|
import expr._
|
||||||
@ -61,41 +62,43 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
|||||||
// Check return value type
|
// Check return value type
|
||||||
((funcArrow.res, retValue) match {
|
((funcArrow.res, retValue) match {
|
||||||
case (Some(t), Some(v)) =>
|
case (Some(t), Some(v)) =>
|
||||||
V.resolveType(v).flatMap {
|
V.resolveType(v).flatTap {
|
||||||
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
||||||
case None => Free.pure[Alg, Unit](())
|
case None => Free.pure[Alg, Unit](())
|
||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
Free.pure[Alg, Unit](())
|
Free.pure[Alg, Option[Type]](None)
|
||||||
|
|
||||||
// Erase arguments and internal variables
|
// Erase arguments and internal variables
|
||||||
}) >> A.endScope() >> N.endScope() >> (bodyGen match {
|
}).flatMap(retType =>
|
||||||
case bg: FuncOp if ret.isDefined == retValue.isDefined =>
|
A.endScope() >> N.endScope() >> (bodyGen match {
|
||||||
val argNames = args.map(_.name.value)
|
case bg: FuncOp if ret.isDefined == retValue.isDefined =>
|
||||||
|
val argNames = args.map(_.name.value)
|
||||||
|
|
||||||
val model = FuncModel(
|
val model = FuncModel(
|
||||||
name = name.value,
|
name = name.value,
|
||||||
args = ArgsDef(
|
args = ArgsDef(
|
||||||
argNames
|
argNames
|
||||||
.zip(funcArrow.args)
|
.zip(funcArrow.args)
|
||||||
.map {
|
.map {
|
||||||
case (n, dt: DataType) => ArgDef.Data(n, dt)
|
case (n, dt: DataType) => ArgDef.Data(n, dt)
|
||||||
case (n, at: ArrowType) => ArgDef.Arrow(n, at)
|
case (n, at: ArrowType) => ArgDef.Arrow(n, at)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
ret = retValue
|
ret = (retValue, retType, funcArrow.res).mapN { case (retV, retT, resT) =>
|
||||||
.map(ValuesAlgebra.valueToModel)
|
ValuesAlgebra.valueToModel(retV, retT) -> resT
|
||||||
.flatMap(vd => funcArrow.res.map(Call.Arg(vd, _))),
|
},
|
||||||
body = bg
|
body = bg
|
||||||
)
|
)
|
||||||
|
|
||||||
N.defineArrow(
|
N.defineArrow(
|
||||||
name,
|
name,
|
||||||
funcArrow,
|
funcArrow,
|
||||||
isRoot = true
|
isRoot = true
|
||||||
) as model
|
) as model
|
||||||
case m => Free.pure[Alg, Model](Model.error("Function body is not a funcOp, it's " + m))
|
case m => Free.pure[Alg, Model](Model.error("Function body is not a funcOp, it's " + m))
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
|
||||||
def program[Alg[_]](implicit
|
def program[Alg[_]](implicit
|
||||||
T: TypesAlgebra[F, Alg],
|
T: TypesAlgebra[F, Alg],
|
||||||
|
@ -6,6 +6,7 @@ import aqua.parser.expr.IfExpr
|
|||||||
import aqua.semantics.rules.ValuesAlgebra
|
import aqua.semantics.rules.ValuesAlgebra
|
||||||
import aqua.semantics.rules.types.TypesAlgebra
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
import aqua.semantics.Prog
|
import aqua.semantics.Prog
|
||||||
|
import aqua.types.Type
|
||||||
import cats.free.Free
|
import cats.free.Free
|
||||||
import cats.syntax.functor._
|
import cats.syntax.functor._
|
||||||
|
|
||||||
@ -21,26 +22,30 @@ class IfSem[F[_]](val expr: IfExpr[F]) extends AnyVal {
|
|||||||
V.resolveType(expr.right).flatMap {
|
V.resolveType(expr.right).flatMap {
|
||||||
case Some(rt) =>
|
case Some(rt) =>
|
||||||
T.ensureTypeMatches(expr.right, lt, rt)
|
T.ensureTypeMatches(expr.right, lt, rt)
|
||||||
|
.map(m => Some(lt -> rt).filter(_ => m))
|
||||||
case None =>
|
case None =>
|
||||||
Free.pure[Alg, Boolean](false)
|
Free.pure[Alg, Option[(Type, Type)]](None)
|
||||||
}
|
}
|
||||||
case None =>
|
case None =>
|
||||||
V.resolveType(expr.right).as(false)
|
V.resolveType(expr.right).as[Option[(Type, Type)]](None)
|
||||||
},
|
},
|
||||||
(r: Boolean, ops: Model) =>
|
(r: Option[(Type, Type)], ops: Model) =>
|
||||||
ops match {
|
r.fold(Free.pure[Alg, Model](Model.error("If expression errored in matching types"))) {
|
||||||
case op: FuncOp if r =>
|
case (lt, rt) =>
|
||||||
Free.pure[Alg, Model](
|
ops match {
|
||||||
FuncOp.wrap(
|
case op: FuncOp =>
|
||||||
MatchMismatchTag(
|
Free.pure[Alg, Model](
|
||||||
ValuesAlgebra.valueToModel(expr.left),
|
FuncOp.wrap(
|
||||||
ValuesAlgebra.valueToModel(expr.right),
|
MatchMismatchTag(
|
||||||
expr.eqOp.value
|
ValuesAlgebra.valueToModel(expr.left, lt),
|
||||||
),
|
ValuesAlgebra.valueToModel(expr.right, rt),
|
||||||
op
|
expr.eqOp.value
|
||||||
)
|
),
|
||||||
)
|
op
|
||||||
case _ => Free.pure[Alg, Model](Model.error("If expression errored"))
|
)
|
||||||
|
)
|
||||||
|
case _ => Free.pure[Alg, Model](Model.error("Wrong body of the if expression"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import aqua.parser.expr.OnExpr
|
|||||||
import aqua.semantics.Prog
|
import aqua.semantics.Prog
|
||||||
import aqua.semantics.rules.ValuesAlgebra
|
import aqua.semantics.rules.ValuesAlgebra
|
||||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||||
|
import aqua.types.ScalarType
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.syntax.flatMap._
|
import cats.syntax.flatMap._
|
||||||
import cats.syntax.functor._
|
import cats.syntax.functor._
|
||||||
@ -28,8 +29,8 @@ class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
|||||||
case op: FuncOp =>
|
case op: FuncOp =>
|
||||||
FuncOp.wrap(
|
FuncOp.wrap(
|
||||||
OnTag(
|
OnTag(
|
||||||
ValuesAlgebra.valueToModel(expr.peerId),
|
ValuesAlgebra.valueToModel(expr.peerId, ScalarType.string),
|
||||||
Chain.fromSeq(expr.via).map(ValuesAlgebra.valueToModel)
|
Chain.fromSeq(expr.via).map(ValuesAlgebra.valueToModel(_, ScalarType.string))
|
||||||
),
|
),
|
||||||
op
|
op
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@ import aqua.model._
|
|||||||
import aqua.parser.lexer._
|
import aqua.parser.lexer._
|
||||||
import aqua.semantics.rules.names.NamesAlgebra
|
import aqua.semantics.rules.names.NamesAlgebra
|
||||||
import aqua.semantics.rules.types.TypesAlgebra
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
import aqua.types.{ArrowType, LiteralType, Type}
|
import aqua.types.{ArrowType, LiteralType, StreamType, Type}
|
||||||
import cats.data.Chain
|
import cats.data.Chain
|
||||||
import cats.free.Free
|
import cats.free.Free
|
||||||
import cats.syntax.apply._
|
import cats.syntax.apply._
|
||||||
@ -82,10 +82,10 @@ object ValuesAlgebra {
|
|||||||
case (f: IntoField[F]) :: tail => opsToModel(tail).prepend(IntoFieldModel(f.value))
|
case (f: IntoField[F]) :: tail => opsToModel(tail).prepend(IntoFieldModel(f.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
def valueToModel[F[_]](v: Value[F]): ValueModel =
|
def valueToModel[F[_]](v: Value[F], t: Type): ValueModel =
|
||||||
v match {
|
v match {
|
||||||
case l: Literal[F] => LiteralModel(l.value)
|
case l: Literal[F] => LiteralModel(l.value)
|
||||||
case VarLambda(name, ops) => VarModel(name.value, opsToModel(ops))
|
case VarLambda(name, ops) => VarModel(name.value, t, opsToModel(ops))
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit def deriveValuesAlgebra[F[_], Alg[_]](implicit
|
implicit def deriveValuesAlgebra[F[_], Alg[_]](implicit
|
||||||
|
@ -5,7 +5,7 @@ import aqua.types.{ArrowType, Type}
|
|||||||
|
|
||||||
sealed trait NameOp[F[_], T]
|
sealed trait NameOp[F[_], T]
|
||||||
|
|
||||||
case class ReadName[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
case class ReadName[F[_]](name: Name[F], mustBeDefined: Boolean) extends NameOp[F, Option[Type]]
|
||||||
case class ConstantDefined[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
case class ConstantDefined[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||||
|
|
||||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
||||||
|
@ -7,9 +7,10 @@ import cats.free.Free
|
|||||||
|
|
||||||
class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
||||||
|
|
||||||
def read(name: Name[F]): Free[Alg, Option[Type]] =
|
def read(name: Name[F], mustBeDefined: Boolean = true): Free[Alg, Option[Type]] =
|
||||||
Free.liftInject[Alg](ReadName(name))
|
Free.liftInject[Alg](ReadName(name, mustBeDefined))
|
||||||
|
|
||||||
|
// TODO can be implemented via read?
|
||||||
def constantDefined(name: Name[F]): Free[Alg, Option[Type]] =
|
def constantDefined(name: Name[F]): Free[Alg, Option[Type]] =
|
||||||
Free.liftInject[Alg](ConstantDefined(name))
|
Free.liftInject[Alg](ConstantDefined(name))
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
|||||||
.orElseF(readName(rn.name.value))
|
.orElseF(readName(rn.name.value))
|
||||||
.value
|
.value
|
||||||
.flatTap {
|
.flatTap {
|
||||||
case Some(_) => State.pure(())
|
case None if rn.mustBeDefined =>
|
||||||
case None =>
|
|
||||||
getState.flatMap(st =>
|
getState.flatMap(st =>
|
||||||
report(rn.name, "Undefined name, available: " + st.allNames.mkString(", "))
|
report(rn.name, "Undefined name, available: " + st.allNames.mkString(", "))
|
||||||
)
|
)
|
||||||
|
case _ => State.pure(())
|
||||||
}
|
}
|
||||||
case rn: ConstantDefined[F] =>
|
case rn: ConstantDefined[F] =>
|
||||||
constantDefined(rn.name.value)
|
constantDefined(rn.name.value)
|
||||||
|
@ -99,6 +99,7 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
case etm: EnsureTypeMatches[F] =>
|
case etm: EnsureTypeMatches[F] =>
|
||||||
|
// TODO in case of two literals, check for types intersection?
|
||||||
if (etm.expected.acceptsValueOf(etm.`given`)) State.pure(true)
|
if (etm.expected.acceptsValueOf(etm.`given`)) State.pure(true)
|
||||||
else
|
else
|
||||||
report(etm.token, s"Types mismatch, expected: ${etm.expected}, given: ${etm.`given`}")
|
report(etm.token, s"Types mismatch, expected: ${etm.expected}, given: ${etm.`given`}")
|
||||||
|
@ -9,10 +9,11 @@ import aqua.parser.lexer.{
|
|||||||
IntoField,
|
IntoField,
|
||||||
LambdaOp,
|
LambdaOp,
|
||||||
Name,
|
Name,
|
||||||
|
StreamTypeToken,
|
||||||
Token,
|
Token,
|
||||||
TypeToken
|
TypeToken
|
||||||
}
|
}
|
||||||
import aqua.types.{ArrayType, ArrowType, DataType, ProductType, Type}
|
import aqua.types.{ArrayType, ArrowType, DataType, ProductType, StreamType, Type}
|
||||||
import cats.data.Validated.{Invalid, Valid}
|
import cats.data.Validated.{Invalid, Valid}
|
||||||
import cats.data.{Chain, NonEmptyChain, ValidatedNec}
|
import cats.data.{Chain, NonEmptyChain, ValidatedNec}
|
||||||
import cats.kernel.Monoid
|
import cats.kernel.Monoid
|
||||||
@ -30,6 +31,10 @@ case class TypesState[F[_]](
|
|||||||
resolveTypeToken(dtt).collect { case it: DataType =>
|
resolveTypeToken(dtt).collect { case it: DataType =>
|
||||||
ArrayType(it)
|
ArrayType(it)
|
||||||
}
|
}
|
||||||
|
case StreamTypeToken(_, dtt) =>
|
||||||
|
resolveTypeToken(dtt).collect { case it: DataType =>
|
||||||
|
StreamType(it)
|
||||||
|
}
|
||||||
case ctt: CustomTypeToken[F] => strict.get(ctt.value)
|
case ctt: CustomTypeToken[F] => strict.get(ctt.value)
|
||||||
case btt: BasicTypeToken[F] => Some(btt.value)
|
case btt: BasicTypeToken[F] => Some(btt.value)
|
||||||
case ArrowTypeToken(_, args, res) =>
|
case ArrowTypeToken(_, args, res) =>
|
||||||
|
@ -73,15 +73,9 @@ case class ProductType(name: String, fields: NonEmptyMap[String, Type]) extends
|
|||||||
s"$name{${fields.map(_.toString).toNel.toList.map(kv => kv._1 + ": " + kv._2).mkString(", ")}}"
|
s"$name{${fields.map(_.toString).toNel.toList.map(kv => kv._1 + ": " + kv._2).mkString(", ")}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait CallableType extends Type {
|
case class ArrowType(args: List[Type], res: Option[Type]) extends Type {
|
||||||
def acceptsAsArguments(valueTypes: List[Type]): Boolean
|
|
||||||
def args: List[Type]
|
|
||||||
def res: Option[Type]
|
|
||||||
}
|
|
||||||
|
|
||||||
case class ArrowType(args: List[Type], res: Option[Type]) extends CallableType {
|
def acceptsAsArguments(valueTypes: List[Type]): Boolean =
|
||||||
|
|
||||||
override def acceptsAsArguments(valueTypes: List[Type]): Boolean =
|
|
||||||
(args.length == valueTypes.length) && args
|
(args.length == valueTypes.length) && args
|
||||||
.zip(valueTypes)
|
.zip(valueTypes)
|
||||||
.forall(av => av._1.acceptsValueOf(av._2))
|
.forall(av => av._1.acceptsValueOf(av._2))
|
||||||
@ -90,6 +84,8 @@ case class ArrowType(args: List[Type], res: Option[Type]) extends CallableType {
|
|||||||
args.map(_.toString).mkString(", ") + " -> " + res.map(_.toString).getOrElse("()")
|
args.map(_.toString).mkString(", ") + " -> " + res.map(_.toString).getOrElse("()")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class StreamType(element: Type) extends DataType
|
||||||
|
|
||||||
object Type {
|
object Type {
|
||||||
import Double.NaN
|
import Double.NaN
|
||||||
|
|
||||||
@ -132,9 +128,11 @@ object Type {
|
|||||||
case (x: ScalarType, LiteralType(ys, _)) if ys == Set(x) => 0.0
|
case (x: ScalarType, LiteralType(ys, _)) if ys == Set(x) => 0.0
|
||||||
case (x: ScalarType, LiteralType(ys, _)) if ys(x) => 1.0
|
case (x: ScalarType, LiteralType(ys, _)) if ys(x) => 1.0
|
||||||
case (x: ArrayType, y: ArrayType) => cmp(x.element, y.element)
|
case (x: ArrayType, y: ArrayType) => cmp(x.element, y.element)
|
||||||
|
case (x: ArrayType, y: StreamType) => cmp(x.element, y.element)
|
||||||
|
case (x: StreamType, y: StreamType) => cmp(x.element, y.element)
|
||||||
case (ProductType(_, xFields), ProductType(_, yFields)) =>
|
case (ProductType(_, xFields), ProductType(_, yFields)) =>
|
||||||
cmpProd(xFields, yFields)
|
cmpProd(xFields, yFields)
|
||||||
case (l: CallableType, r: CallableType) =>
|
case (l: ArrowType, r: ArrowType) =>
|
||||||
val argL = l.args
|
val argL = l.args
|
||||||
val resL = l.res
|
val resL = l.res
|
||||||
val argR = r.args
|
val argR = r.args
|
||||||
|
@ -94,4 +94,13 @@ class TypeSpec extends AnyFlatSpec with Matchers {
|
|||||||
accepts(four, one) should be(false)
|
accepts(four, one) should be(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"streams" should "be accepted as an array, but not vice versa" in {
|
||||||
|
val stream: Type = StreamType(bool)
|
||||||
|
val array: Type = ArrayType(bool)
|
||||||
|
|
||||||
|
accepts(array, stream) should be(true)
|
||||||
|
accepts(stream, array) should be(false)
|
||||||
|
accepts(stream, stream) should be(true)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user