mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
Added bang op to get array items by index (#144)
This commit is contained in:
parent
6ba9c13c63
commit
378d154ff7
4
.github/workflows/test_branch.yml
vendored
4
.github/workflows/test_branch.yml
vendored
@ -50,7 +50,9 @@ jobs:
|
||||
- name: Integration test
|
||||
run: |
|
||||
git clone https://github.com/fluencelabs/aqua-playground.git
|
||||
sbt "cli/run -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples"
|
||||
cd aqua-playground
|
||||
npm i
|
||||
cd ..
|
||||
sbt "cli/run -i aqua-playground/aqua/examples -o aqua-playground/src/compiled/examples -m aqua-playground/node_modules"
|
||||
cd aqua-playground
|
||||
npm run examples
|
||||
|
@ -13,15 +13,19 @@ service Test("test"):
|
||||
getUserList: -> []User
|
||||
doSomething: -> bool
|
||||
|
||||
func betterMessage(relay: string):
|
||||
func betterMessage(relay: string, arr: []string) -> string:
|
||||
on relay:
|
||||
Peer.is_connected("something")
|
||||
par isOnline <- Peer.is_connected(relay)
|
||||
par on "quray":
|
||||
Peer.is_connected("qurara")
|
||||
|
||||
stream: *string
|
||||
|
||||
if isOnline:
|
||||
try:
|
||||
Test.doSomething()
|
||||
else:
|
||||
Peer.is_connected("else")
|
||||
Peer.is_connected(stream!)
|
||||
|
||||
<- stream!2
|
@ -17,14 +17,16 @@ object AirGen {
|
||||
|
||||
def lambdaToString(ls: List[LambdaModel]): String = ls match {
|
||||
case Nil => ""
|
||||
case IntoArrayModel :: tail =>
|
||||
case IntoArrayModel(_) :: tail =>
|
||||
s"[@${lambdaToString(tail)}]"
|
||||
case IntoFieldModel(field) :: tail =>
|
||||
case IntoFieldModel(field, _) :: tail =>
|
||||
s".$field${lambdaToString(tail)}"
|
||||
case IntoIndexModel(idx, _) :: tail =>
|
||||
s".[$idx]${lambdaToString(tail)}"
|
||||
}
|
||||
|
||||
def valueToData(vm: ValueModel): DataView = vm match {
|
||||
case LiteralModel(value) => DataView.StringScalar(value)
|
||||
case LiteralModel(value, _) => DataView.StringScalar(value)
|
||||
case VarModel(name, t, lambda) =>
|
||||
val n = t match {
|
||||
case _: StreamType => "$" + name
|
||||
|
@ -22,7 +22,7 @@ val declineEnumV = "1.3.0"
|
||||
name := "aqua-hll"
|
||||
|
||||
val commons = Seq(
|
||||
baseAquaVersion := "0.1.2",
|
||||
baseAquaVersion := "0.1.3",
|
||||
version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"),
|
||||
scalaVersion := dottyVersion,
|
||||
libraryDependencies ++= Seq(
|
||||
|
@ -1,10 +1,14 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.types.Type
|
||||
import aqua.types.{ScalarType, Type}
|
||||
import cats.Eq
|
||||
import cats.data.Chain
|
||||
|
||||
sealed trait ValueModel {
|
||||
def `type`: Type
|
||||
|
||||
def lastType: Type
|
||||
|
||||
def resolveWith(map: Map[String, ValueModel]): ValueModel = this
|
||||
}
|
||||
|
||||
@ -15,20 +19,29 @@ object ValueModel {
|
||||
}
|
||||
}
|
||||
|
||||
case class LiteralModel(value: String) extends ValueModel
|
||||
|
||||
object LiteralModel {
|
||||
val initPeerId: LiteralModel = LiteralModel("%init_peer_id%")
|
||||
case class LiteralModel(value: String, `type`: Type) extends ValueModel {
|
||||
override def lastType: Type = `type`
|
||||
}
|
||||
|
||||
sealed trait LambdaModel
|
||||
case object IntoArrayModel extends LambdaModel
|
||||
case class IntoFieldModel(field: String) extends LambdaModel
|
||||
object LiteralModel {
|
||||
def quote(str: String): LiteralModel = LiteralModel("\"" + str + "\"", ScalarType.string)
|
||||
|
||||
val initPeerId: LiteralModel = LiteralModel("%init_peer_id%", ScalarType.string)
|
||||
}
|
||||
|
||||
sealed trait LambdaModel {
|
||||
def `type`: Type
|
||||
}
|
||||
case class IntoArrayModel(`type`: Type) extends LambdaModel
|
||||
case class IntoFieldModel(field: String, `type`: Type) extends LambdaModel
|
||||
case class IntoIndexModel(idx: Int, `type`: Type) extends LambdaModel
|
||||
|
||||
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)
|
||||
|
||||
override val lastType: Type = lambda.lastOption.map(_.`type`).getOrElse(`type`)
|
||||
|
||||
override def resolveWith(map: Map[String, ValueModel]): ValueModel = {
|
||||
map.get(name) match {
|
||||
case Some(vv: VarModel) =>
|
||||
|
@ -8,7 +8,7 @@ import cats.free.Cofree
|
||||
object FuncOps {
|
||||
|
||||
def noop(peerId: ValueModel): FuncOp =
|
||||
FuncOp.leaf(CallServiceTag(LiteralModel("\"op\""), "identity", Call(Nil, None), Some(peerId)))
|
||||
FuncOp.leaf(CallServiceTag(LiteralModel.quote("op"), "identity", Call(Nil, None), Some(peerId)))
|
||||
|
||||
def callService(srvId: ValueModel, funcName: String, call: Call): FuncOp =
|
||||
FuncOp.leaf(
|
||||
|
@ -12,9 +12,9 @@ case class BodyConfig(
|
||||
wrapWithXor: Boolean = true
|
||||
) {
|
||||
|
||||
val errorId: ValueModel = LiteralModel("\"" + errorFuncName + "\"")
|
||||
val errorHandlingCallback: ValueModel = LiteralModel("\"" + errorHandlingService + "\"")
|
||||
val callbackSrvId: ValueModel = LiteralModel("\"" + callbackService + "\"")
|
||||
val dataSrvId: ValueModel = LiteralModel("\"" + getDataService + "\"")
|
||||
val errorId: ValueModel = LiteralModel.quote(errorFuncName)
|
||||
val errorHandlingCallback: ValueModel = LiteralModel.quote(errorHandlingService)
|
||||
val callbackSrvId: ValueModel = LiteralModel.quote(callbackService)
|
||||
val dataSrvId: ValueModel = LiteralModel.quote(getDataService)
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package aqua.model.transform
|
||||
import aqua.model.{LiteralModel, ValueModel}
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.func.body.{FuncOp, FuncOps, MatchMismatchTag, OnTag, OpTag, XorTag}
|
||||
import aqua.types.LiteralType
|
||||
import cats.Eval
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
@ -53,10 +54,10 @@ case class ErrorsCatcher(
|
||||
|
||||
object ErrorsCatcher {
|
||||
// TODO not a string
|
||||
val lastErrorArg: ValueModel = LiteralModel("%last_error%")
|
||||
val lastErrorArg: ValueModel = LiteralModel("%last_error%", LiteralType.string)
|
||||
|
||||
def lastErrorCall(i: Int): Call = Call(
|
||||
lastErrorArg :: LiteralModel(i.toString) :: Nil,
|
||||
lastErrorArg :: LiteralModel(i.toString, LiteralType.number) :: Nil,
|
||||
None
|
||||
)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package aqua.model
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.func.body._
|
||||
import aqua.model.transform.BodyConfig
|
||||
import aqua.types.ScalarType
|
||||
import aqua.types.{LiteralType, ScalarType}
|
||||
import cats.Eval
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
@ -84,24 +84,30 @@ object Node {
|
||||
implicit def nodeToCof(tree: Node): Cof =
|
||||
Cofree(tree.tag, Eval.later(Chain.fromSeq(tree.ops.map(nodeToCof))))
|
||||
|
||||
val relay = LiteralModel("-relay-")
|
||||
val relay = LiteralModel("-relay-", ScalarType.string)
|
||||
val relayV = VarModel("-relay-", ScalarType.string)
|
||||
val initPeer = LiteralModel.initPeerId
|
||||
val emptyCall = Call(Nil, None)
|
||||
val otherPeer = LiteralModel("other-peer")
|
||||
val otherRelay = LiteralModel("other-relay")
|
||||
val otherPeer2 = LiteralModel("other-peer-2")
|
||||
val otherRelay2 = LiteralModel("other-relay-2")
|
||||
val otherPeer = LiteralModel("other-peer", ScalarType.string)
|
||||
val otherRelay = LiteralModel("other-relay", ScalarType.string)
|
||||
val otherPeer2 = LiteralModel("other-peer-2", ScalarType.string)
|
||||
val otherRelay2 = LiteralModel("other-relay-2", ScalarType.string)
|
||||
|
||||
def call(i: Int, on: ValueModel = null) = Node(
|
||||
CallServiceTag(LiteralModel(s"srv$i"), s"fn$i", Call(Nil, None), Option(on))
|
||||
CallServiceTag(LiteralModel(s"srv$i", ScalarType.string), s"fn$i", Call(Nil, None), Option(on))
|
||||
)
|
||||
|
||||
def errorCall(bc: BodyConfig, i: Int, on: ValueModel = null) = Node(
|
||||
CallServiceTag(
|
||||
bc.errorHandlingCallback,
|
||||
bc.errorFuncName,
|
||||
Call(LiteralModel("%last_error%") :: LiteralModel(i.toString) :: Nil, None),
|
||||
Call(
|
||||
LiteralModel("%last_error%", LiteralType.string) :: LiteralModel(
|
||||
i.toString,
|
||||
LiteralType.number
|
||||
) :: Nil,
|
||||
None
|
||||
),
|
||||
Option(on)
|
||||
)
|
||||
)
|
||||
|
@ -12,7 +12,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
"transform.forClient" should "work well with function 1 (no calls before on)" in {
|
||||
|
||||
val ret = LiteralModel("\"return this\"")
|
||||
val ret = LiteralModel.quote("return this")
|
||||
|
||||
val func: FuncCallable =
|
||||
FuncCallable(
|
||||
@ -64,7 +64,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
"transform.forClient" should "work well with function 2 (with a call before on)" in {
|
||||
|
||||
val ret = LiteralModel("\"return this\"")
|
||||
val ret = LiteralModel.quote("return this")
|
||||
|
||||
val func: FuncCallable = FuncCallable(
|
||||
"ret",
|
||||
@ -112,7 +112,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
FuncOp(
|
||||
Node(
|
||||
CallServiceTag(
|
||||
LiteralModel("\"srv1\""),
|
||||
LiteralModel.quote("srv1"),
|
||||
"foo",
|
||||
Call(Nil, Some(Call.Export("v", ScalarType.string))),
|
||||
None
|
||||
@ -146,7 +146,7 @@ class TransformSpec extends AnyFlatSpec with Matchers {
|
||||
dataCall(bc, "-relay-", initPeer),
|
||||
Node(
|
||||
CallServiceTag(
|
||||
LiteralModel("\"srv1\""),
|
||||
LiteralModel.quote("srv1"),
|
||||
"foo",
|
||||
Call(Nil, Some(Call.Export("v", ScalarType.string))),
|
||||
Some(initPeer)
|
||||
|
@ -4,7 +4,7 @@ import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.parse.{Numbers, Parser => P, Parser0 => P0}
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
import cats.{Comonad, Functor}
|
||||
@ -17,6 +17,12 @@ case class IntoField[F[_]: Comonad](name: F[String]) extends LambdaOp[F] {
|
||||
def value: String = name.extract
|
||||
}
|
||||
|
||||
case class IntoIndex[F[_]: Comonad](idx: F[Int]) extends LambdaOp[F] {
|
||||
override def as[T](v: T): F[T] = idx.as(v)
|
||||
|
||||
def value: Int = idx.extract
|
||||
}
|
||||
|
||||
case class IntoArray[F[_]: Functor](override val unit: F[Unit]) extends LambdaOp[F] {
|
||||
override def as[T](v: T): F[T] = unit.as(v)
|
||||
}
|
||||
@ -25,10 +31,16 @@ object LambdaOp {
|
||||
|
||||
private def parseField[F[_]: LiftParser: Comonad]: P[LambdaOp[F]] =
|
||||
(`.` *> `name`).lift.map(IntoField(_))
|
||||
|
||||
private def parseArr[F[_]: LiftParser: Comonad]: P[LambdaOp[F]] = `*`.lift.map(IntoArray(_))
|
||||
|
||||
private val intP0: P0[Int] = Numbers.nonNegativeIntString.map(_.toInt).?.map(_.getOrElse(0))
|
||||
|
||||
private def parseIdx[F[_]: LiftParser: Comonad]: P[LambdaOp[F]] =
|
||||
((`!`: P[Unit]) *> intP0).lift.map(IntoIndex(_))
|
||||
|
||||
private def parseOp[F[_]: LiftParser: Comonad]: P[LambdaOp[F]] =
|
||||
P.oneOf(parseField.backtrack :: parseArr :: Nil)
|
||||
P.oneOf(parseField.backtrack :: parseArr :: parseIdx :: Nil)
|
||||
|
||||
def ops[F[_]: LiftParser: Comonad]: P[NonEmptyList[LambdaOp[F]]] =
|
||||
parseOp.rep
|
||||
|
@ -58,6 +58,7 @@ 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.string("[]")
|
||||
val `(` : P[Unit] = P.char('(').surroundedBy(` `.?)
|
||||
val `)` : P[Unit] = P.char(')').surroundedBy(` `.?)
|
||||
|
@ -10,6 +10,7 @@ import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.types.{ArrowType, ScalarType, StreamType, Type}
|
||||
import cats.Traverse
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.flatMap._
|
||||
@ -41,13 +42,7 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
||||
}
|
||||
)
|
||||
) >>= { (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)
|
||||
Traverse[List].traverse(args)(V.valueToModel).map(_.flatten).map(_ -> v)
|
||||
}
|
||||
|
||||
private def toModel[Alg[_]](implicit
|
||||
@ -63,18 +58,21 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
||||
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
|
||||
case _ => None
|
||||
}.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { case (arrowType, serviceId) =>
|
||||
checkArgsRes(arrowType).map { case (argsResolved, t) =>
|
||||
FuncOp.leaf(
|
||||
CallServiceTag(
|
||||
// TODO service id type should not be hardcoded
|
||||
serviceId = ValuesAlgebra.valueToModel(serviceId, ScalarType.string),
|
||||
funcName = funcName.value,
|
||||
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||
(checkArgsRes(arrowType), V.valueToModel(serviceId)).mapN {
|
||||
case ((argsResolved, t), Some(serviceIdM)) =>
|
||||
Option(
|
||||
FuncOp.leaf(
|
||||
CallServiceTag(
|
||||
serviceId = serviceIdM,
|
||||
funcName = funcName.value,
|
||||
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
case _ => None
|
||||
|
||||
}
|
||||
.map(Option(_))
|
||||
})
|
||||
case None =>
|
||||
N.readArrow(funcName)
|
||||
|
@ -18,9 +18,9 @@ class ConstantSem[F[_]](val expr: ConstantExpr[F]) extends AnyVal {
|
||||
): Prog[Alg, Model] = {
|
||||
for {
|
||||
defined <- N.constantDefined(expr.name)
|
||||
t <- V.resolveType(expr.value)
|
||||
model <- (defined, t, expr.skipIfAlreadyDefined) match {
|
||||
case (Some(definedType), Some(actualType), true) =>
|
||||
v <- V.valueToModel(expr.value)
|
||||
model <- (defined, v.map(v => v -> v.lastType), expr.skipIfAlreadyDefined) match {
|
||||
case (Some(definedType), Some((vm, actualType)), true) =>
|
||||
T.ensureTypeMatches(expr.value, definedType, actualType).map {
|
||||
case true =>
|
||||
Model.empty(s"Constant with name ${expr.name} was already defined, skipping")
|
||||
@ -32,9 +32,9 @@ class ConstantSem[F[_]](val expr: ConstantExpr[F]) extends AnyVal {
|
||||
case (_, None, _) =>
|
||||
Free.pure[Alg, Model](Model.error(s"There is no such variable ${expr.value}"))
|
||||
case (_, Some(t), _) =>
|
||||
N.defineConstant(expr.name, t) as (ConstantModel(
|
||||
N.defineConstant(expr.name, t._2) as (ConstantModel(
|
||||
expr.name.value,
|
||||
ValuesAlgebra.valueToModel(expr.value, t)
|
||||
t._1
|
||||
): Model)
|
||||
}
|
||||
} yield model
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.model.{Model, ValueModel}
|
||||
import aqua.model.func.body._
|
||||
import aqua.parser.expr.ForExpr
|
||||
import aqua.semantics.Prog
|
||||
@ -21,20 +21,24 @@ class ForSem[F[_]](val expr: ForExpr[F]) extends AnyVal {
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.around(
|
||||
N.beginScope(expr.item) >> V.resolveType(expr.iterable).flatMap[Option[Type]] {
|
||||
case Some(at @ ArrayType(t)) =>
|
||||
N.define(expr.item, t).as(Option(at))
|
||||
case Some(st @ StreamType(t)) =>
|
||||
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)
|
||||
N.beginScope(expr.item) >> V.valueToModel(expr.iterable).flatMap[Option[ValueModel]] {
|
||||
case Some(vm) =>
|
||||
vm.lastType match {
|
||||
case at @ ArrayType(t) =>
|
||||
N.define(expr.item, t).as(Option(vm))
|
||||
case st @ StreamType(t) =>
|
||||
N.define(expr.item, t).as(Option(vm))
|
||||
case dt =>
|
||||
T.ensureTypeMatches(expr.iterable, ArrayType(dt), dt).as(Option.empty[ValueModel])
|
||||
}
|
||||
|
||||
case _ => Free.pure[Alg, Option[ValueModel]](None)
|
||||
},
|
||||
(stOpt: Option[Type], ops: Model) =>
|
||||
(stOpt: Option[ValueModel], ops: Model) =>
|
||||
N.endScope() as ((stOpt, ops) match {
|
||||
case (Some(t), op: FuncOp) =>
|
||||
case (Some(vm), op: FuncOp) =>
|
||||
FuncOp.wrap(
|
||||
ForTag(expr.item.value, ValuesAlgebra.valueToModel(expr.iterable, t)),
|
||||
ForTag(expr.item.value, vm),
|
||||
FuncOp.node(
|
||||
expr.mode.map(_._2).fold[OpTag](SeqTag) {
|
||||
case ForExpr.ParMode => ParTag
|
||||
|
@ -1,8 +1,8 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.func.body.FuncOp
|
||||
import aqua.model.Model
|
||||
import aqua.model.func.{ArgDef, ArgsDef, Call, FuncModel}
|
||||
import aqua.model.{Model, ValueModel}
|
||||
import aqua.model.func.{ArgDef, ArgsDef, FuncModel}
|
||||
import aqua.parser.expr.FuncExpr
|
||||
import aqua.parser.lexer.Arg
|
||||
import aqua.semantics.Prog
|
||||
@ -16,7 +16,6 @@ import cats.data.Chain
|
||||
import cats.free.Free
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.apply._
|
||||
|
||||
class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||
import expr._
|
||||
@ -62,15 +61,15 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||
// Check return value type
|
||||
((funcArrow.res, retValue) match {
|
||||
case (Some(t), Some(v)) =>
|
||||
V.resolveType(v).flatTap {
|
||||
case Some(vt) => T.ensureTypeMatches(v, t, vt).void
|
||||
V.valueToModel(v).flatTap {
|
||||
case Some(vt) => T.ensureTypeMatches(v, t, vt.lastType).void
|
||||
case None => Free.pure[Alg, Unit](())
|
||||
}
|
||||
case _ =>
|
||||
Free.pure[Alg, Option[Type]](None)
|
||||
Free.pure[Alg, Option[ValueModel]](None)
|
||||
|
||||
// Erase arguments and internal variables
|
||||
}).flatMap(retType =>
|
||||
}).flatMap(retModel =>
|
||||
A.endScope() >> N.endScope() >> (bodyGen match {
|
||||
case bg: FuncOp if ret.isDefined == retValue.isDefined =>
|
||||
val argNames = args.map(_.name.value)
|
||||
@ -85,9 +84,7 @@ class FuncSem[F[_]](val expr: FuncExpr[F]) extends AnyVal {
|
||||
case (n, at: ArrowType) => ArgDef.Arrow(n, at)
|
||||
}
|
||||
),
|
||||
ret = (retValue, retType, funcArrow.res).mapN { case (retV, retT, resT) =>
|
||||
ValuesAlgebra.valueToModel(retV, retT) -> resT
|
||||
},
|
||||
ret = retModel zip funcArrow.res,
|
||||
body = bg
|
||||
)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.Model
|
||||
import aqua.model.{Model, ValueModel}
|
||||
import aqua.model.func.body.{FuncOp, MatchMismatchTag, XorTag}
|
||||
import aqua.parser.expr.IfExpr
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
@ -17,19 +17,19 @@ class IfSem[F[_]](val expr: IfExpr[F]) extends AnyVal {
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Model] =
|
||||
Prog.around(
|
||||
V.resolveType(expr.left).flatMap {
|
||||
V.valueToModel(expr.left).flatMap {
|
||||
case Some(lt) =>
|
||||
V.resolveType(expr.right).flatMap {
|
||||
V.valueToModel(expr.right).flatMap {
|
||||
case Some(rt) =>
|
||||
T.ensureTypeMatches(expr.right, lt, rt)
|
||||
T.ensureTypeMatches(expr.right, lt.lastType, rt.lastType)
|
||||
.map(m => Some(lt -> rt).filter(_ => m))
|
||||
case None =>
|
||||
Free.pure[Alg, Option[(Type, Type)]](None)
|
||||
Free.pure[Alg, Option[(ValueModel, ValueModel)]](None)
|
||||
}
|
||||
case None =>
|
||||
V.resolveType(expr.right).as[Option[(Type, Type)]](None)
|
||||
V.resolveType(expr.right).as[Option[(ValueModel, ValueModel)]](None)
|
||||
},
|
||||
(r: Option[(Type, Type)], ops: Model) =>
|
||||
(r: Option[(ValueModel, ValueModel)], ops: Model) =>
|
||||
r.fold(Free.pure[Alg, Model](Model.error("If expression errored in matching types"))) {
|
||||
case (lt, rt) =>
|
||||
ops match {
|
||||
@ -39,8 +39,8 @@ class IfSem[F[_]](val expr: IfExpr[F]) extends AnyVal {
|
||||
XorTag.LeftBiased,
|
||||
FuncOp.wrap(
|
||||
MatchMismatchTag(
|
||||
ValuesAlgebra.valueToModel(expr.left, lt),
|
||||
ValuesAlgebra.valueToModel(expr.right, rt),
|
||||
lt,
|
||||
rt,
|
||||
expr.eqOp.value
|
||||
),
|
||||
op
|
||||
|
@ -6,10 +6,11 @@ import aqua.parser.expr.OnExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.types.ScalarType
|
||||
import cats.Traverse
|
||||
import cats.data.Chain
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
import cats.syntax.flatMap._
|
||||
import cats.syntax.functor._
|
||||
|
||||
class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
||||
|
||||
@ -25,16 +26,25 @@ class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
||||
}
|
||||
>> A.beginScope(expr.peerId),
|
||||
(_: Unit, ops: Model) =>
|
||||
A.endScope() as (ops match {
|
||||
A.endScope() >> (ops match {
|
||||
case op: FuncOp =>
|
||||
FuncOp.wrap(
|
||||
OnTag(
|
||||
ValuesAlgebra.valueToModel(expr.peerId, ScalarType.string),
|
||||
Chain.fromSeq(expr.via).map(ValuesAlgebra.valueToModel(_, ScalarType.string))
|
||||
),
|
||||
op
|
||||
)
|
||||
case m => Model.error("On body is not an op, it's " + m)
|
||||
(
|
||||
V.valueToModel(expr.peerId),
|
||||
Traverse[List].traverse(expr.via)(V.valueToModel).map(_.flatten)
|
||||
).mapN {
|
||||
case (Some(om), via) =>
|
||||
FuncOp.wrap(
|
||||
OnTag(
|
||||
om,
|
||||
Chain.fromSeq(via)
|
||||
),
|
||||
op
|
||||
)
|
||||
case _ =>
|
||||
Model.error("OnSem: Impossible error")
|
||||
}
|
||||
|
||||
case m => Free.pure[Alg, Model](Model.error("On body is not an op, it's " + m))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import aqua.model._
|
||||
import aqua.parser.lexer._
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.types.{ArrowType, LiteralType, StreamType, Type}
|
||||
import aqua.types.{ArrowType, LiteralType, Type}
|
||||
import cats.data.Chain
|
||||
import cats.free.Free
|
||||
import cats.syntax.apply._
|
||||
@ -29,13 +29,15 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge
|
||||
}
|
||||
|
||||
def resolveType(v: Value[F]): Free[Alg, Option[Type]] =
|
||||
valueToModel(v).map(_.map(_.lastType))
|
||||
|
||||
def valueToModel(v: Value[F]): Free[Alg, Option[ValueModel]] =
|
||||
v match {
|
||||
case l: Literal[F] =>
|
||||
Free pure [Alg, Option[Type]] Some(l.ts)
|
||||
case VarLambda(n, lambda) =>
|
||||
N.read(n).flatMap {
|
||||
case l: Literal[F] => Free.pure(Some(LiteralModel(l.value, l.ts)))
|
||||
case VarLambda(name, ops) =>
|
||||
N.read(name).flatMap {
|
||||
case Some(t) =>
|
||||
T.resolveLambda(t, lambda)
|
||||
T.resolveLambda(t, ops).map(Chain.fromSeq).map(VarModel(name.value, t, _)).map(Some(_))
|
||||
case None =>
|
||||
Free.pure(None)
|
||||
}
|
||||
@ -46,14 +48,9 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge
|
||||
case false => Free.pure[Alg, Boolean](false)
|
||||
case true =>
|
||||
args
|
||||
.map[Free[Alg, Option[(Token[F], Type)]]] {
|
||||
case l: Literal[F] => Free.pure(Some(l -> l.ts))
|
||||
case VarLambda(n, ops) =>
|
||||
N.read(n).flatMap {
|
||||
case Some(t) => T.resolveLambda(t, ops).map(_.map(ops.lastOption.getOrElse(n) -> _))
|
||||
case None => Free.pure(None)
|
||||
}
|
||||
}
|
||||
.map[Free[Alg, Option[(Token[F], Type)]]](tkn =>
|
||||
resolveType(tkn).map(_.map(t => tkn -> t))
|
||||
)
|
||||
.zip(arr.args)
|
||||
.foldLeft(
|
||||
Free.pure[Alg, Boolean](true)
|
||||
@ -75,19 +72,6 @@ class ValuesAlgebra[F[_], Alg[_]](implicit N: NamesAlgebra[F, Alg], T: TypesAlge
|
||||
|
||||
object ValuesAlgebra {
|
||||
|
||||
private def opsToModel[F[_]](ops: List[LambdaOp[F]]): Chain[LambdaModel] =
|
||||
ops match {
|
||||
case Nil => Chain.empty
|
||||
case (_: IntoArray[F]) :: tail => opsToModel(tail).prepend(IntoArrayModel)
|
||||
case (f: IntoField[F]) :: tail => opsToModel(tail).prepend(IntoFieldModel(f.value))
|
||||
}
|
||||
|
||||
def valueToModel[F[_]](v: Value[F], t: Type): ValueModel =
|
||||
v match {
|
||||
case l: Literal[F] => LiteralModel(l.value)
|
||||
case VarLambda(name, ops) => VarModel(name.value, t, opsToModel(ops))
|
||||
}
|
||||
|
||||
implicit def deriveValuesAlgebra[F[_], Alg[_]](implicit
|
||||
N: NamesAlgebra[F, Alg],
|
||||
T: TypesAlgebra[F, Alg]
|
||||
|
@ -1,5 +1,6 @@
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.model.LambdaModel
|
||||
import aqua.parser.lexer.{ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.types.{ArrowType, Type}
|
||||
import cats.data.NonEmptyMap
|
||||
@ -16,7 +17,8 @@ case class DefineDataType[F[_]](name: CustomTypeToken[F], fields: NonEmptyMap[St
|
||||
extends TypeOp[F, Boolean]
|
||||
case class DefineAlias[F[_]](name: CustomTypeToken[F], target: Type) extends TypeOp[F, Boolean]
|
||||
|
||||
case class ResolveLambda[F[_]](root: Type, ops: List[LambdaOp[F]]) extends TypeOp[F, Option[Type]]
|
||||
case class ResolveLambda[F[_]](root: Type, ops: List[LambdaOp[F]])
|
||||
extends TypeOp[F, List[LambdaModel]]
|
||||
|
||||
case class EnsureTypeMatches[F[_]](token: Token[F], expected: Type, given: Type)
|
||||
extends TypeOp[F, Boolean]
|
||||
|
@ -1,5 +1,6 @@
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.model.LambdaModel
|
||||
import aqua.parser.lexer.{ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.types.{ArrowType, Type}
|
||||
import cats.InjectK
|
||||
@ -29,7 +30,7 @@ class TypesAlgebra[F[_], Alg[_]](implicit T: InjectK[TypeOp[F, *], Alg]) {
|
||||
def defineAlias(name: CustomTypeToken[F], target: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineAlias(name, target))
|
||||
|
||||
def resolveLambda(root: Type, ops: List[LambdaOp[F]]): Free[Alg, Option[Type]] =
|
||||
def resolveLambda(root: Type, ops: List[LambdaOp[F]]): Free[Alg, List[LambdaModel]] =
|
||||
Free.liftInject[Alg](ResolveLambda(root, ops))
|
||||
|
||||
def ensureTypeMatches(token: Token[F], expected: Type, given: Type): Free[Alg, Boolean] =
|
||||
|
@ -94,8 +94,8 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
|
||||
|
||||
case rl: ResolveLambda[F] =>
|
||||
getState.map(_.resolveOps(rl.root, rl.ops)).flatMap {
|
||||
case Left((tkn, hint)) => report(tkn, hint).as(None)
|
||||
case Right(t) => State.pure(Some(t))
|
||||
case Left((tkn, hint)) => report(tkn, hint).as(Nil)
|
||||
case Right(ts) => State.pure(ts)
|
||||
}
|
||||
|
||||
case etm: EnsureTypeMatches[F] =>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package aqua.semantics.rules.types
|
||||
|
||||
import aqua.model.{IntoArrayModel, IntoFieldModel, IntoIndexModel, LambdaModel}
|
||||
import aqua.parser.lexer.{
|
||||
ArrayTypeToken,
|
||||
ArrowTypeToken,
|
||||
@ -7,6 +8,7 @@ import aqua.parser.lexer.{
|
||||
CustomTypeToken,
|
||||
IntoArray,
|
||||
IntoField,
|
||||
IntoIndex,
|
||||
LambdaOp,
|
||||
Name,
|
||||
StreamTypeToken,
|
||||
@ -69,22 +71,36 @@ case class TypesState[F[_]](
|
||||
Invalid(NonEmptyChain.one(ad.resType.getOrElse(ad) -> "Cannot resolve the result type"))
|
||||
}
|
||||
|
||||
def resolveOps(rootT: Type, ops: List[LambdaOp[F]]): Either[(Token[F], String), Type] =
|
||||
ops.headOption.fold[Either[(Token[F], String), Type]](Right(rootT)) {
|
||||
case i @ IntoArray(f) =>
|
||||
def resolveOps(
|
||||
rootT: Type,
|
||||
ops: List[LambdaOp[F]]
|
||||
): Either[(Token[F], String), List[LambdaModel]] =
|
||||
ops match {
|
||||
case Nil => Right(Nil)
|
||||
case (i @ IntoArray(_)) :: tail =>
|
||||
rootT match {
|
||||
case ArrayType(intern) => resolveOps(intern, ops.tail).map[Type](ArrayType)
|
||||
case _ => Left(i -> s"Expected $rootT to be an array")
|
||||
case ArrayType(intern) =>
|
||||
resolveOps(intern, tail).map(IntoArrayModel(ArrayType(intern)) :: _)
|
||||
case StreamType(intern) =>
|
||||
resolveOps(intern, tail).map(IntoArrayModel(ArrayType(intern)) :: _)
|
||||
case _ => Left(i -> s"Expected $rootT to be an array or a stream")
|
||||
}
|
||||
case i @ IntoField(name) =>
|
||||
case (i @ IntoField(_)) :: tail =>
|
||||
rootT match {
|
||||
case pt @ ProductType(_, fields) =>
|
||||
fields(i.value)
|
||||
.toRight(i -> s"Field `${i.value}` not found in type `${pt.name}``")
|
||||
.flatMap(resolveOps(_, ops.tail))
|
||||
.flatMap(t => resolveOps(t, tail).map(IntoFieldModel(i.value, t) :: _))
|
||||
case _ => Left(i -> s"Expected product to resolve a field, got $rootT")
|
||||
}
|
||||
|
||||
case (i @ IntoIndex(_)) :: tail =>
|
||||
rootT match {
|
||||
case ArrayType(intern) =>
|
||||
resolveOps(intern, tail).map(IntoIndexModel(i.value, intern) :: _)
|
||||
case StreamType(intern) =>
|
||||
resolveOps(intern, tail).map(IntoIndexModel(i.value, intern) :: _)
|
||||
case _ => Left(i -> s"Expected $rootT to be an array")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user