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