mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 14:40:17 +00:00
feat(tracing): Introduce function calls tracing [fixes LNG-169] (#732)
* Introduced MetaModel.CallArrowModel * Fixed ArrowInlinerSpec * Implemented trace calls injection * Propagate TracingConfig * Add tracing flag to js api * Use detach instead of xor * Write tests * ScalarType -> LiteralType * Add tests * Fix after rebase * Fixed tests * Add tests * Remove debug prints * Clean up and add comments * Fix issues * Add tracing flag to js api * Rename liftString -> quote * Change literal type * Use CallServiceModel constructor * Fix js args * Fixed tests * Add tracing option to cli
This commit is contained in:
parent
e2f67b3c0f
commit
e9c004452e
17
api/aqua-api-npm/aqua-api.d.ts
vendored
17
api/aqua-api-npm/aqua-api.d.ts
vendored
@ -1,14 +1,21 @@
|
||||
import type {FunctionCallDef, ServiceDef} from "@fluencelabs/fluence/dist/internal/compilerSupport/v3impl/interface"
|
||||
import type { FunctionCallDef, ServiceDef } from "@fluencelabs/fluence/dist/internal/compilerSupport/v3impl/interface"
|
||||
|
||||
export class AquaConfig {
|
||||
constructor(logLevel: string, constants: string[], noXor: boolean, noRelay: boolean);
|
||||
constructor(logLevel: string, constants: string[], noXor: boolean, noRelay: boolean, targetType: string);
|
||||
constructor(
|
||||
logLevel?: string,
|
||||
constants?: string[],
|
||||
noXor?: boolean,
|
||||
noRelay?: boolean,
|
||||
targetType?: string,
|
||||
tracing?: boolean
|
||||
);
|
||||
|
||||
logLevel?: string
|
||||
constants?: string[]
|
||||
noXor?: boolean
|
||||
noRelay?: boolean
|
||||
targetType?: string
|
||||
tracing?: boolean
|
||||
}
|
||||
|
||||
export class AquaFunction {
|
||||
@ -45,8 +52,8 @@ export class Path {
|
||||
|
||||
export class Call {
|
||||
constructor(functionCall: string,
|
||||
arguments: any,
|
||||
input: Input | Path);
|
||||
arguments: any,
|
||||
input: Input | Path);
|
||||
|
||||
functionCall: string
|
||||
arguments: any
|
||||
|
@ -4,7 +4,7 @@ import aqua.api.AquaAPIConfig
|
||||
import aqua.api.TargetType.*
|
||||
import aqua.js.{FunctionDefJs, ServiceDefJs}
|
||||
import aqua.model.transform.TransformConfig
|
||||
import cats.data.Validated.{Invalid, Valid, invalidNec, validNec}
|
||||
import cats.data.Validated.{invalidNec, validNec}
|
||||
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
||||
|
||||
import scala.scalajs.js
|
||||
@ -45,7 +45,9 @@ class AquaConfig(
|
||||
@JSExport
|
||||
val noRelay: js.UndefOr[Boolean],
|
||||
@JSExport
|
||||
val targetType: js.UndefOr[String]
|
||||
val targetType: js.UndefOr[String],
|
||||
@JSExport
|
||||
val tracing: js.UndefOr[Boolean]
|
||||
)
|
||||
|
||||
object AquaConfig {
|
||||
@ -62,11 +64,12 @@ object AquaConfig {
|
||||
.getOrElse(validNec(AirType))
|
||||
.map { target =>
|
||||
AquaAPIConfig(
|
||||
target,
|
||||
cjs.logLevel.getOrElse("info"),
|
||||
cjs.constants.map(_.toList).getOrElse(Nil),
|
||||
cjs.noXor.getOrElse(false),
|
||||
cjs.noRelay.getOrElse(false)
|
||||
targetType = target,
|
||||
logLevel = cjs.logLevel.getOrElse("info"),
|
||||
constants = cjs.constants.map(_.toList).getOrElse(Nil),
|
||||
noXor = cjs.noXor.getOrElse(false),
|
||||
noRelay = cjs.noRelay.getOrElse(false),
|
||||
tracing = cjs.tracing.getOrElse(false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,17 @@ case class AquaAPIConfig(
|
||||
logLevel: String = "info",
|
||||
constants: List[String] = Nil,
|
||||
noXor: Boolean = false,
|
||||
noRelay: Boolean = false
|
||||
noRelay: Boolean = false,
|
||||
tracing: Boolean = false
|
||||
) {
|
||||
|
||||
def getTransformConfig: TransformConfig =
|
||||
if (noRelay) TransformConfig(relayVarName = None, wrapWithXor = !noXor)
|
||||
else TransformConfig(wrapWithXor = !noXor)
|
||||
def getTransformConfig: TransformConfig = {
|
||||
val config = TransformConfig(
|
||||
wrapWithXor = !noXor,
|
||||
tracing = Option.when(tracing)(TransformConfig.TracingConfig.default)
|
||||
)
|
||||
|
||||
if (noRelay) config.copy(relayVarName = None)
|
||||
else config
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import aqua.model.transform.{Transform, TransformConfig}
|
||||
import aqua.model.{FuncArrow, ValueModel, VarModel}
|
||||
import aqua.parser.lexer.CallArrowToken
|
||||
import aqua.parser.lift.Span
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, FuncOp, SeqTag}
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, SeqTag}
|
||||
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
|
||||
import aqua.types.*
|
||||
import cats.data.Validated.{invalid, invalidNec, invalidNel, validNec, validNel}
|
||||
@ -18,7 +18,7 @@ import cats.syntax.flatMap.*
|
||||
import cats.syntax.partialOrder.*
|
||||
import cats.syntax.show.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Id, ~>}
|
||||
import cats.{~>, Id}
|
||||
|
||||
import scala.collection.immutable.SortedMap
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
@ -7,7 +7,7 @@ import aqua.model.transform.{Transform, TransformConfig}
|
||||
import aqua.model.{FuncArrow, ValueModel, VarModel}
|
||||
import aqua.parser.lexer.CallArrowToken
|
||||
import aqua.parser.lift.Span
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, FuncOp, SeqTag}
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, SeqTag}
|
||||
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
|
||||
import aqua.types.*
|
||||
import cats.data.Validated.{invalid, invalidNec, invalidNel, validNec, validNel}
|
||||
@ -101,9 +101,10 @@ class RunPreparer(
|
||||
val returnCodomain = ProductType(results.map(_.`type`))
|
||||
|
||||
// arguments is only variables, without literals
|
||||
val argumentsType = ProductType.labelled(func.args.zip(funcCallable.arrowType.domain.labelledData).collect {
|
||||
case (VarRaw(name, _), (_, t)) => (name, t)
|
||||
})
|
||||
val argumentsType =
|
||||
ProductType.labelled(func.args.zip(funcCallable.arrowType.domain.labelledData).collect {
|
||||
case (VarRaw(name, _), (_, t)) => (name, t)
|
||||
})
|
||||
|
||||
FuncArrow(
|
||||
func.name + "Run",
|
||||
|
@ -144,6 +144,12 @@ object AppOpts {
|
||||
.map(_ => true)
|
||||
.withDefault(false)
|
||||
|
||||
val tracing: Opts[Boolean] =
|
||||
Opts
|
||||
.flag("trace", "Generate tace events calls")
|
||||
.map(_ => true)
|
||||
.withDefault(false)
|
||||
|
||||
val isOldFluenceJs: Opts[Boolean] =
|
||||
Opts
|
||||
.flagOption[String](
|
||||
@ -172,7 +178,7 @@ object AppOpts {
|
||||
Opts
|
||||
.flag(
|
||||
"scheduled",
|
||||
"Generate air code for script storage. Without error handling wrappers and hops on relay. Will ignore other options"
|
||||
"Generate air code for script storage. Without error handling wrappers, hops on relay and tracing. Will ignore other options"
|
||||
)
|
||||
.map(_ => true)
|
||||
.withDefault(false)
|
||||
|
@ -17,7 +17,7 @@ import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Functor, Id, Monad, ~>}
|
||||
import cats.{~>, Functor, Id, Monad}
|
||||
import com.monovore.decline
|
||||
import com.monovore.decline.effect.CommandIOApp
|
||||
import com.monovore.decline.effect.CommandIOApp.printHelp
|
||||
@ -95,6 +95,7 @@ object AquaCli extends IOApp with Logging {
|
||||
compileToJs,
|
||||
noRelay,
|
||||
noXorWrapper,
|
||||
tracing,
|
||||
isOldFluenceJs,
|
||||
wrapWithOption(helpOpt),
|
||||
wrapWithOption(versionOpt),
|
||||
@ -112,6 +113,7 @@ object AquaCli extends IOApp with Logging {
|
||||
toJs,
|
||||
noRelayOp,
|
||||
noXorOp,
|
||||
tracingOp,
|
||||
isOldFluenceJsOp,
|
||||
h,
|
||||
v,
|
||||
@ -124,6 +126,7 @@ object AquaCli extends IOApp with Logging {
|
||||
val toAir = toAirOp || isScheduled
|
||||
val noXor = noXorOp || isScheduled
|
||||
val noRelay = noRelayOp || isScheduled
|
||||
val tracingEnabled = tracingOp && !isScheduled
|
||||
|
||||
// if there is `--help` or `--version` flag - show help and version
|
||||
// otherwise continue program execution
|
||||
@ -133,7 +136,11 @@ object AquaCli extends IOApp with Logging {
|
||||
else if (toJs) JavaScriptTarget
|
||||
else TypescriptTarget
|
||||
val bc = {
|
||||
val bc = TransformConfig(wrapWithXor = !noXor, constants = constants)
|
||||
val bc = TransformConfig(
|
||||
wrapWithXor = !noXor,
|
||||
constants = constants,
|
||||
tracing = Option.when(tracingEnabled)(TransformConfig.TracingConfig.default)
|
||||
)
|
||||
bc.copy(relayVarName = bc.relayVarName.filterNot(_ => noRelay))
|
||||
}
|
||||
LogFormatter.initLogger(Some(logLevel.compiler))
|
||||
@ -205,8 +212,8 @@ object AquaCli extends IOApp with Logging {
|
||||
ExitCode.Error
|
||||
}
|
||||
}
|
||||
.getOrElse{
|
||||
ConsoleEff[IO].print(h).map{_ =>
|
||||
.getOrElse {
|
||||
ConsoleEff[IO].print(h).map { _ =>
|
||||
// hack to show last string in `help`
|
||||
println()
|
||||
ExitCode.Success
|
||||
|
@ -2,7 +2,13 @@ package aqua.model.inline
|
||||
|
||||
import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler}
|
||||
import aqua.model.*
|
||||
import aqua.model.inline.raw.{ApplyFunctorRawInliner, ApplyGateRawInliner, ApplyPropertiesRawInliner, CallArrowRawInliner, CollectionRawInliner}
|
||||
import aqua.model.inline.raw.{
|
||||
ApplyFunctorRawInliner,
|
||||
ApplyGateRawInliner,
|
||||
ApplyPropertiesRawInliner,
|
||||
CallArrowRawInliner,
|
||||
CollectionRawInliner
|
||||
}
|
||||
import aqua.raw.ops.*
|
||||
import aqua.raw.value.*
|
||||
import aqua.types.{ArrayType, OptionType, StreamType}
|
||||
@ -86,10 +92,10 @@ object RawValueInliner extends Logging {
|
||||
case (vv, _) =>
|
||||
FlattenModel(vv, name).leaf
|
||||
}
|
||||
}.map{ predo =>
|
||||
}.map { predo =>
|
||||
inline.mergeMode match
|
||||
case SeqMode =>
|
||||
SeqModel.wrap((inline.predo.toList ++ predo):_*) :: Nil
|
||||
SeqModel.wrap((inline.predo.toList ++ predo): _*) :: Nil
|
||||
case ParMode => inline.predo.toList ::: predo
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,11 @@ import aqua.raw.value.*
|
||||
import aqua.types.{ArrayType, ArrowType, BoxType, CanonStreamType, StreamType}
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.option.*
|
||||
import cats.instances.list.*
|
||||
import cats.data.{Chain, State, StateT}
|
||||
import cats.syntax.show.*
|
||||
import scribe.{log, Logging}
|
||||
|
||||
/**
|
||||
@ -218,10 +221,10 @@ object TagInliner extends Logging {
|
||||
collectionToModel(c, Some(assignTo))
|
||||
case v =>
|
||||
valueToModel(v, false)
|
||||
}).flatMap { cd =>
|
||||
for {
|
||||
_ <- Exports[S].resolved(assignTo, cd._1)
|
||||
} yield None -> cd._2
|
||||
}).flatMap { case (model, prefix) =>
|
||||
Exports[S]
|
||||
.resolved(assignTo, model)
|
||||
.as(None -> prefix)
|
||||
}
|
||||
|
||||
case ClosureTag(arrow, detach) =>
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.model.inline.raw
|
||||
|
||||
import aqua.model.inline.Inline.parDesugarPrefixOpt
|
||||
import aqua.model.{CallServiceModel, FuncArrow, SeqModel, ValueModel, VarModel}
|
||||
import aqua.model.{CallServiceModel, FuncArrow, MetaModel, SeqModel, ValueModel, VarModel}
|
||||
import aqua.model.inline.{ArrowInliner, Inline, TagInliner}
|
||||
import aqua.model.inline.RawValueInliner.{callToModel, valueToModel}
|
||||
import aqua.model.inline.state.{Arrows, Exports, Mangler}
|
||||
@ -48,7 +48,10 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
}
|
||||
}
|
||||
|
||||
private def resolveFuncArrow[S: Mangler: Exports: Arrows](fn: FuncArrow, call: Call) = {
|
||||
private def resolveFuncArrow[S: Mangler: Exports: Arrows](
|
||||
fn: FuncArrow,
|
||||
call: Call
|
||||
): State[S, (List[ValueModel], Inline)] = {
|
||||
logger.trace(Console.YELLOW + s"Call arrow ${fn.funcName}" + Console.RESET)
|
||||
callToModel(call, false).flatMap { case (cm, p) =>
|
||||
ArrowInliner
|
||||
@ -56,13 +59,23 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging {
|
||||
.map { case (body, vars) =>
|
||||
vars -> Inline(
|
||||
ListMap.empty,
|
||||
Chain.one(SeqModel.wrap(p.toList :+ body: _*))
|
||||
Chain.one(
|
||||
// Leave meta information in tree after inlining
|
||||
MetaModel
|
||||
.CallArrowModel(fn.funcName)
|
||||
.wrap(
|
||||
SeqModel.wrap(p.toList :+ body: _*)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def resolveArrow[S: Mangler: Exports: Arrows](funcName: String, call: Call) =
|
||||
private def resolveArrow[S: Mangler: Exports: Arrows](
|
||||
funcName: String,
|
||||
call: Call
|
||||
): State[S, (List[ValueModel], Inline)] =
|
||||
Arrows[S].arrows.flatMap(arrows =>
|
||||
arrows.get(funcName) match {
|
||||
case Some(fn) =>
|
||||
|
@ -9,6 +9,8 @@ import cats.syntax.show.*
|
||||
import cats.data.{Chain, NonEmptyList, NonEmptyMap}
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.raw.value.{CallArrowRaw, ValueRaw}
|
||||
import aqua.raw.arrow.{ArrowRaw, FuncRaw}
|
||||
|
||||
class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
@ -33,7 +35,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
model.equalsOrShowDiff(
|
||||
CallServiceModel(
|
||||
LiteralModel("\"dumb_srv_id\"", LiteralType.string),
|
||||
LiteralModel.quote("dumb_srv_id"),
|
||||
"dumb",
|
||||
CallModel(Nil, Nil)
|
||||
).leaf
|
||||
@ -113,14 +115,21 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
model.equalsOrShowDiff(
|
||||
RestrictionModel(streamVar.name, true).wrap(
|
||||
SeqModel.wrap(
|
||||
CanonicalizeModel(streamModel, CallModel.Export(canonModel.name, canonModel.`type`)).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel("\"test-service\"", LiteralType.string),
|
||||
"some-call",
|
||||
CallModel(canonModel :: Nil, Nil)
|
||||
).leaf
|
||||
)
|
||||
MetaModel
|
||||
.CallArrowModel("cb")
|
||||
.wrap(
|
||||
SeqModel.wrap(
|
||||
CanonicalizeModel(
|
||||
streamModel,
|
||||
CallModel.Export(canonModel.name, canonModel.`type`)
|
||||
).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel.quote("test-service"),
|
||||
"some-call",
|
||||
CallModel(canonModel :: Nil, Nil)
|
||||
).leaf
|
||||
)
|
||||
)
|
||||
)
|
||||
) should be(true)
|
||||
|
||||
@ -130,7 +139,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
func stream-callback(cb: string -> ()):
|
||||
records: *string
|
||||
cb(records!)
|
||||
*/
|
||||
*/
|
||||
ignore /*"arrow inliner"*/ should "pass stream with gate to callback properly" in {
|
||||
val streamType = StreamType(ScalarType.string)
|
||||
val streamVar = VarRaw("records", streamType)
|
||||
@ -210,7 +219,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
model.equalsOrShowDiff(
|
||||
RestrictionModel(streamVar.name, true).wrap(
|
||||
CallServiceModel(
|
||||
LiteralModel("\"test-service\"", LiteralType.string),
|
||||
LiteralModel.quote("test-service"),
|
||||
"some-call",
|
||||
CallModel(streamModel :: Nil, Nil)
|
||||
).leaf
|
||||
@ -291,15 +300,19 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
model.equalsOrShowDiff(
|
||||
SeqModel.wrap(
|
||||
CallServiceModel(
|
||||
LiteralModel("\"test-service\"", LiteralType.string),
|
||||
"get_records",
|
||||
CallModel(Nil, CallModel.Export(recordsModel.name, recordsModel.`type`) :: Nil)
|
||||
).leaf,
|
||||
MetaModel
|
||||
.CallArrowModel(innerName)
|
||||
.wrap(
|
||||
CallServiceModel(
|
||||
LiteralModel.quote("test-service"),
|
||||
"get_records",
|
||||
CallModel(Nil, CallModel.Export(recordsModel.name, recordsModel.`type`) :: Nil)
|
||||
).leaf
|
||||
),
|
||||
SeqModel.wrap(
|
||||
CanonicalizeModel(recordsModel, CallModel.Export(canonModel.name, canonType)).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel("\"callbackSrv\"", LiteralType.string),
|
||||
LiteralModel.quote("callbackSrv"),
|
||||
"response",
|
||||
CallModel(canonModel :: Nil, Nil)
|
||||
).leaf
|
||||
@ -309,6 +322,642 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* service Test("test-service"):
|
||||
* get_number() -> u16
|
||||
*
|
||||
* func inner() -> u16:
|
||||
* res <- Test.get_number()
|
||||
* <- res
|
||||
*
|
||||
* func outer() -> u16
|
||||
* res1 <- inner() -- Meta should be left here
|
||||
* res2 <- Test.get_number()
|
||||
* res3 <- inner() -- Meta should be left here
|
||||
* retval = res1 + res2 + res3
|
||||
* <- retval
|
||||
*/
|
||||
"arrow inliner" should "leave meta after function inlining" in {
|
||||
val innerName = "inner"
|
||||
val innerRes = VarRaw("res", ScalarType.u16)
|
||||
|
||||
val serviceName = "test-service"
|
||||
val serviceMethod = "get_number"
|
||||
|
||||
val serviceCall = (res: VarRaw) =>
|
||||
CallArrowRawTag
|
||||
.service(
|
||||
LiteralRaw.quote(serviceName),
|
||||
serviceMethod,
|
||||
Call(Nil, Call.Export(res.name, ScalarType.u16) :: Nil)
|
||||
)
|
||||
.leaf
|
||||
|
||||
val innerBody = SeqTag.wrap(
|
||||
serviceCall(innerRes),
|
||||
ReturnTag(
|
||||
NonEmptyList.one(
|
||||
innerRes
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val inner = FuncArrow(
|
||||
funcName = innerName,
|
||||
body = innerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(innerRes),
|
||||
capturedArrows = Map.empty,
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val outterRes1 = VarRaw("res1", ScalarType.u16)
|
||||
val outterRes2 = VarRaw("res2", ScalarType.u16)
|
||||
val outterRes3 = VarRaw("res3", ScalarType.u16)
|
||||
val outterRetVal = VarRaw("retval", ScalarType.u16)
|
||||
|
||||
val innerCall = (res: VarRaw) =>
|
||||
CallArrowRawTag
|
||||
.func(
|
||||
innerName,
|
||||
Call(Nil, Call.Export(res.name, ScalarType.u16) :: Nil)
|
||||
)
|
||||
.leaf
|
||||
|
||||
val outerBody = SeqTag.wrap(
|
||||
innerCall(outterRes1),
|
||||
serviceCall(outterRes2),
|
||||
innerCall(outterRes3),
|
||||
AssignmentTag(
|
||||
RawBuilder.add(
|
||||
outterRes1,
|
||||
RawBuilder.add(
|
||||
outterRes2,
|
||||
outterRes3
|
||||
)
|
||||
),
|
||||
outterRetVal.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList
|
||||
.one(
|
||||
outterRetVal
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val outer = FuncArrow(
|
||||
funcName = "outer",
|
||||
body = outerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(outterRetVal),
|
||||
capturedArrows = Map(innerName -> inner),
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val model = ArrowInliner
|
||||
.callArrow[InliningState](
|
||||
outer,
|
||||
CallModel(Nil, Nil)
|
||||
)
|
||||
.runA(InliningState())
|
||||
.value
|
||||
|
||||
val serviceCallModel = (res: VarModel) =>
|
||||
CallServiceModel(
|
||||
LiteralModel.quote(serviceName),
|
||||
serviceMethod,
|
||||
CallModel(Nil, CallModel.Export(res.name, res.`type`) :: Nil)
|
||||
).leaf
|
||||
|
||||
/* WARNING: This naming is unstable */
|
||||
val res1 = VarModel("res", ScalarType.u16)
|
||||
val res2 = VarModel("res2", ScalarType.u16)
|
||||
val res3 = VarModel("res-0", ScalarType.u16)
|
||||
val tempAdd = VarModel("add-0", ScalarType.u16)
|
||||
|
||||
val expected = SeqModel.wrap(
|
||||
MetaModel
|
||||
.CallArrowModel(innerName)
|
||||
.wrap(
|
||||
serviceCallModel(res1)
|
||||
),
|
||||
serviceCallModel(res2),
|
||||
MetaModel
|
||||
.CallArrowModel(innerName)
|
||||
.wrap(
|
||||
serviceCallModel(res3)
|
||||
),
|
||||
SeqModel.wrap(
|
||||
ModelBuilder.add(res2, res3)(tempAdd).leaf,
|
||||
ModelBuilder.add(res1, tempAdd)(VarModel("add", ScalarType.u16)).leaf
|
||||
)
|
||||
)
|
||||
|
||||
model.equalsOrShowDiff(expected) shouldEqual true
|
||||
}
|
||||
|
||||
/**
|
||||
* func inner() -> u16:
|
||||
* res = 42
|
||||
* <- res
|
||||
*
|
||||
* func outer() -> u16:
|
||||
* retval = inner() + inner() + 37
|
||||
* <- retval
|
||||
*/
|
||||
"arrow inliner" should "omit meta if arrow was completely erased" in {
|
||||
val innerName = "inner"
|
||||
val innerRes = VarRaw("res", ScalarType.u16)
|
||||
val innerRet = "42"
|
||||
|
||||
val innerBody = SeqTag.wrap(
|
||||
AssignmentTag(
|
||||
LiteralRaw(innerRet, ScalarType.u16),
|
||||
innerRes.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList.one(
|
||||
innerRes
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val inner = FuncArrow(
|
||||
funcName = innerName,
|
||||
body = innerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(innerRes),
|
||||
capturedArrows = Map.empty,
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val innerCall = CallArrowRaw(
|
||||
ability = None,
|
||||
name = innerName,
|
||||
arguments = Nil,
|
||||
baseType = ArrowType(
|
||||
domain = NilType,
|
||||
codomain = ProductType(List(ScalarType.u16))
|
||||
),
|
||||
serviceId = None
|
||||
)
|
||||
|
||||
val outerAdd = "37"
|
||||
val outterRetVal = VarRaw("retval", ScalarType.u16)
|
||||
|
||||
val outerBody = SeqTag.wrap(
|
||||
AssignmentTag(
|
||||
RawBuilder.add(
|
||||
innerCall,
|
||||
RawBuilder.add(
|
||||
innerCall,
|
||||
LiteralRaw(outerAdd, ScalarType.u16)
|
||||
)
|
||||
),
|
||||
outterRetVal.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList
|
||||
.one(
|
||||
outterRetVal
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val outer = FuncArrow(
|
||||
funcName = "outer",
|
||||
body = outerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(outterRetVal),
|
||||
capturedArrows = Map(innerName -> inner),
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val model = ArrowInliner
|
||||
.callArrow[InliningState](
|
||||
outer,
|
||||
CallModel(Nil, Nil)
|
||||
)
|
||||
.runA(InliningState())
|
||||
.value
|
||||
|
||||
/* WARNING: This naming is unstable */
|
||||
val tempAdd0 = VarModel("add-0", ScalarType.u16)
|
||||
val tempAdd = VarModel("add", ScalarType.u16)
|
||||
|
||||
val expected = SeqModel.wrap(
|
||||
ModelBuilder
|
||||
.add(
|
||||
LiteralModel(innerRet, ScalarType.u16),
|
||||
LiteralModel(outerAdd, ScalarType.u16)
|
||||
)(tempAdd0)
|
||||
.leaf,
|
||||
ModelBuilder
|
||||
.add(
|
||||
LiteralModel(innerRet, ScalarType.u16),
|
||||
tempAdd0
|
||||
)(tempAdd)
|
||||
.leaf
|
||||
)
|
||||
|
||||
model.equalsOrShowDiff(expected) shouldEqual true
|
||||
}
|
||||
|
||||
/**
|
||||
* func inner(arg: u16) -> u16 -> u16:
|
||||
* closure = (x: u16) -> u16:
|
||||
* retval = x + arg
|
||||
* <- retval
|
||||
* <- closure
|
||||
*
|
||||
* func outer() -> u16:
|
||||
* c <- inner(42)
|
||||
* retval = 37 + c(1) + c(2)
|
||||
* <- retval
|
||||
*/
|
||||
"arrow inliner" should "leave meta after returned closure inlining" in {
|
||||
val innerName = "inner"
|
||||
val closureName = "closure"
|
||||
|
||||
val closureArg = VarRaw(
|
||||
"x",
|
||||
ScalarType.u16
|
||||
)
|
||||
val innerArg = VarRaw(
|
||||
"arg",
|
||||
ScalarType.u16
|
||||
)
|
||||
|
||||
val closureRes = VarRaw(
|
||||
"retval",
|
||||
ScalarType.u16
|
||||
)
|
||||
val closureType = ArrowType(
|
||||
domain = ProductType(List(closureArg.`type`)),
|
||||
codomain = ProductType(List(ScalarType.u16))
|
||||
)
|
||||
val closureTypeLablled = closureType.copy(
|
||||
domain = ProductType.labelled(List(closureArg.name -> closureArg.`type`))
|
||||
)
|
||||
|
||||
val innerRes = VarRaw(
|
||||
closureName,
|
||||
closureTypeLablled
|
||||
)
|
||||
val innerType = ArrowType(
|
||||
domain = ProductType.labelled(List(innerArg.name -> innerArg.`type`)),
|
||||
codomain = ProductType(List(closureType))
|
||||
)
|
||||
|
||||
val closureBody = SeqTag.wrap(
|
||||
AssignmentTag(
|
||||
RawBuilder.add(
|
||||
closureArg,
|
||||
innerArg
|
||||
),
|
||||
closureRes.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList.one(closureRes)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val closureFunc = FuncRaw(
|
||||
name = closureName,
|
||||
arrow = ArrowRaw(
|
||||
`type` = closureTypeLablled,
|
||||
ret = List(closureRes),
|
||||
body = closureBody
|
||||
)
|
||||
)
|
||||
|
||||
val innerBody = SeqTag.wrap(
|
||||
ClosureTag(
|
||||
func = closureFunc,
|
||||
detach = false
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList.one(innerRes)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val inner = FuncArrow(
|
||||
funcName = innerName,
|
||||
body = innerBody,
|
||||
arrowType = innerType,
|
||||
ret = List(innerRes),
|
||||
capturedArrows = Map.empty,
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val outterClosure = VarRaw(
|
||||
"c",
|
||||
closureType
|
||||
)
|
||||
val outterRes = VarRaw(
|
||||
"retval",
|
||||
ScalarType.u16
|
||||
)
|
||||
|
||||
val innerCall =
|
||||
CallArrowRawTag(
|
||||
List(Call.Export(outterClosure.name, outterClosure.`type`)),
|
||||
CallArrowRaw(
|
||||
ability = None,
|
||||
name = innerName,
|
||||
arguments = List(LiteralRaw("42", LiteralType.number)),
|
||||
baseType = innerType,
|
||||
serviceId = None
|
||||
)
|
||||
).leaf
|
||||
|
||||
val closureCall = (i: String) =>
|
||||
CallArrowRaw(
|
||||
ability = None,
|
||||
name = outterClosure.name,
|
||||
arguments = List(LiteralRaw(i, LiteralType.number)),
|
||||
baseType = closureType,
|
||||
serviceId = None
|
||||
)
|
||||
|
||||
val outerBody = SeqTag.wrap(
|
||||
innerCall,
|
||||
AssignmentTag(
|
||||
RawBuilder.add(
|
||||
RawBuilder.add(
|
||||
LiteralRaw("37", LiteralType.number),
|
||||
closureCall("1")
|
||||
),
|
||||
closureCall("2")
|
||||
),
|
||||
outterRes.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList
|
||||
.one(
|
||||
outterRes
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val outer = FuncArrow(
|
||||
funcName = "outer",
|
||||
body = outerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(outterRes),
|
||||
capturedArrows = Map(innerName -> inner),
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val model = ArrowInliner
|
||||
.callArrow[InliningState](
|
||||
outer,
|
||||
CallModel(Nil, Nil)
|
||||
)
|
||||
.runA(InliningState())
|
||||
.value
|
||||
|
||||
val closureCallModel = (x: String, o: VarModel) =>
|
||||
MetaModel
|
||||
.CallArrowModel(closureName)
|
||||
.wrap(
|
||||
ApplyTopologyModel(closureName)
|
||||
.wrap(
|
||||
ModelBuilder
|
||||
.add(
|
||||
LiteralModel(x, LiteralType.number),
|
||||
LiteralModel("42", LiteralType.number)
|
||||
)(o)
|
||||
.leaf
|
||||
)
|
||||
)
|
||||
|
||||
/* WARNING: This naming is unstable */
|
||||
val tempAdd0 = VarModel("add-0", ScalarType.u16)
|
||||
val tempAdd1 = VarModel("add-1", ScalarType.u16)
|
||||
val tempAdd2 = VarModel("add-2", ScalarType.u16)
|
||||
val tempAdd = VarModel("add", ScalarType.u16)
|
||||
|
||||
val expected = SeqModel.wrap(
|
||||
MetaModel
|
||||
.CallArrowModel(innerName)
|
||||
.wrap(
|
||||
CaptureTopologyModel(closureName).leaf
|
||||
),
|
||||
SeqModel.wrap(
|
||||
ParModel.wrap(
|
||||
SeqModel.wrap(
|
||||
closureCallModel("1", tempAdd1),
|
||||
ModelBuilder
|
||||
.add(
|
||||
LiteralModel("37", LiteralType.number),
|
||||
tempAdd1
|
||||
)(tempAdd0)
|
||||
.leaf
|
||||
),
|
||||
closureCallModel("2", tempAdd2)
|
||||
),
|
||||
ModelBuilder
|
||||
.add(
|
||||
tempAdd0,
|
||||
tempAdd2
|
||||
)(tempAdd)
|
||||
.leaf
|
||||
)
|
||||
)
|
||||
|
||||
model.equalsOrShowDiff(expected) shouldEqual true
|
||||
}
|
||||
|
||||
/**
|
||||
* func inner() -> () -> u16:
|
||||
* closure = func () -> u16:
|
||||
* <- 42
|
||||
* <- closure
|
||||
*
|
||||
* func outer() -> u16:
|
||||
* c <- inner()
|
||||
* retval = 37 + c() + c()
|
||||
* <- retval
|
||||
*/
|
||||
"arrow inliner" should "omit meta if returned closure was completely erased" in {
|
||||
val innerName = "inner"
|
||||
val closureName = "closure"
|
||||
|
||||
val closureRes = LiteralRaw(
|
||||
"42",
|
||||
LiteralType.number
|
||||
)
|
||||
val closureType = ArrowType(
|
||||
domain = NilType,
|
||||
codomain = ProductType(List(ScalarType.u16))
|
||||
)
|
||||
|
||||
val innerRes = VarRaw(
|
||||
closureName,
|
||||
closureType
|
||||
)
|
||||
val innerType = ArrowType(
|
||||
domain = NilType,
|
||||
codomain = ProductType(List(closureType))
|
||||
)
|
||||
|
||||
val closureBody = SeqTag.wrap(
|
||||
ReturnTag(
|
||||
NonEmptyList.one(closureRes)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val closureFunc = FuncRaw(
|
||||
name = closureName,
|
||||
arrow = ArrowRaw(
|
||||
`type` = closureType,
|
||||
ret = List(closureRes),
|
||||
body = closureBody
|
||||
)
|
||||
)
|
||||
|
||||
val innerBody = SeqTag.wrap(
|
||||
ClosureTag(
|
||||
func = closureFunc,
|
||||
detach = true
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList.one(innerRes)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val inner = FuncArrow(
|
||||
funcName = innerName,
|
||||
body = innerBody,
|
||||
arrowType = innerType,
|
||||
ret = List(innerRes),
|
||||
capturedArrows = Map.empty,
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val outterClosure = VarRaw(
|
||||
"c",
|
||||
closureType
|
||||
)
|
||||
val outterRes = VarRaw(
|
||||
"retval",
|
||||
ScalarType.u16
|
||||
)
|
||||
|
||||
val innerCall =
|
||||
CallArrowRawTag(
|
||||
List(Call.Export(outterClosure.name, outterClosure.`type`)),
|
||||
CallArrowRaw(
|
||||
ability = None,
|
||||
name = innerName,
|
||||
arguments = Nil,
|
||||
baseType = innerType,
|
||||
serviceId = None
|
||||
)
|
||||
).leaf
|
||||
|
||||
val closureCall =
|
||||
CallArrowRaw(
|
||||
ability = None,
|
||||
name = outterClosure.name,
|
||||
arguments = Nil,
|
||||
baseType = closureType,
|
||||
serviceId = None
|
||||
)
|
||||
|
||||
val outerBody = SeqTag.wrap(
|
||||
innerCall,
|
||||
AssignmentTag(
|
||||
RawBuilder.add(
|
||||
RawBuilder.add(
|
||||
LiteralRaw("37", LiteralType.number),
|
||||
closureCall
|
||||
),
|
||||
closureCall
|
||||
),
|
||||
outterRes.name
|
||||
).leaf,
|
||||
ReturnTag(
|
||||
NonEmptyList
|
||||
.one(
|
||||
outterRes
|
||||
)
|
||||
).leaf
|
||||
)
|
||||
|
||||
val outer = FuncArrow(
|
||||
funcName = "outer",
|
||||
body = outerBody,
|
||||
arrowType = ArrowType(
|
||||
ProductType(Nil),
|
||||
ProductType(List(ScalarType.u16))
|
||||
),
|
||||
ret = List(outterRes),
|
||||
capturedArrows = Map(innerName -> inner),
|
||||
capturedValues = Map.empty,
|
||||
capturedTopology = None
|
||||
)
|
||||
|
||||
val model = ArrowInliner
|
||||
.callArrow[InliningState](
|
||||
outer,
|
||||
CallModel(Nil, Nil)
|
||||
)
|
||||
.runA(InliningState())
|
||||
.value
|
||||
|
||||
/* WARNING: This naming is unstable */
|
||||
val tempAdd0 = VarModel("add-0", ScalarType.u16)
|
||||
val tempAdd = VarModel("add", ScalarType.u16)
|
||||
|
||||
val number = (v: String) =>
|
||||
LiteralModel(
|
||||
v,
|
||||
LiteralType.number
|
||||
)
|
||||
|
||||
val expected = SeqModel.wrap(
|
||||
ModelBuilder
|
||||
.add(
|
||||
number("37"),
|
||||
number("42")
|
||||
)(tempAdd0)
|
||||
.leaf,
|
||||
ModelBuilder
|
||||
.add(
|
||||
tempAdd0,
|
||||
number("42")
|
||||
)(tempAdd)
|
||||
.leaf
|
||||
)
|
||||
|
||||
model.equalsOrShowDiff(expected) shouldEqual true
|
||||
}
|
||||
|
||||
/*
|
||||
data Prod:
|
||||
value: string
|
||||
@ -322,6 +971,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
OpHa.identity(v)
|
||||
*/
|
||||
"arrow inliner" should "hold lambda" in {
|
||||
val innerName = "inner"
|
||||
|
||||
// lambda that will be assigned to another variable
|
||||
val objectVarLambda =
|
||||
@ -348,7 +998,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
// function where we assign object lambda to value and call service
|
||||
val inner =
|
||||
FuncArrow(
|
||||
"inner",
|
||||
innerName,
|
||||
SeqTag.wrap(
|
||||
AssignmentTag(
|
||||
objectVarLambda,
|
||||
@ -399,18 +1049,22 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
model.equalsOrShowDiff(
|
||||
SeqModel.wrap(
|
||||
CallServiceModel(
|
||||
LiteralModel("\"getSrv\"", LiteralType.string),
|
||||
LiteralModel.quote("getSrv"),
|
||||
"getObj",
|
||||
CallModel(Nil, CallModel.Export(objectVar.name, objectVar.`type`) :: Nil)
|
||||
).leaf,
|
||||
SeqModel.wrap(
|
||||
FlattenModel(ValueModel.fromRaw(objectVarLambda), flattenObject.name).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel("\"callbackSrv\"", LiteralType.string),
|
||||
"response",
|
||||
CallModel(ValueModel.fromRaw(flattenObject) :: Nil, Nil)
|
||||
).leaf
|
||||
)
|
||||
MetaModel
|
||||
.CallArrowModel(innerName)
|
||||
.wrap(
|
||||
SeqModel.wrap(
|
||||
FlattenModel(ValueModel.fromRaw(objectVarLambda), flattenObject.name).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel.quote("callbackSrv"),
|
||||
"response",
|
||||
CallModel(ValueModel.fromRaw(flattenObject) :: Nil, Nil)
|
||||
).leaf
|
||||
)
|
||||
)
|
||||
)
|
||||
) should be(true)
|
||||
|
||||
@ -421,6 +1075,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
join nodes[idx]
|
||||
*/
|
||||
"arrow inliner" should "not rename value in index array lambda" in {
|
||||
val innerName = "inner"
|
||||
|
||||
// lambda that will be assigned to another variable
|
||||
val argArray = VarRaw(
|
||||
@ -453,7 +1108,7 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
// function where we assign object lambda to value and call service
|
||||
val inner =
|
||||
FuncArrow(
|
||||
"inner",
|
||||
innerName,
|
||||
JoinTag(NonEmptyList.one(arrIdx)).leaf,
|
||||
ArrowType(
|
||||
ProductType.labelled(
|
||||
@ -495,12 +1150,12 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
model.equalsOrShowDiff(
|
||||
SeqModel.wrap(
|
||||
CallServiceModel(
|
||||
LiteralModel("\"getSrv\"", LiteralType.string),
|
||||
LiteralModel.quote("getSrv"),
|
||||
"getArr",
|
||||
CallModel(Nil, CallModel.Export(argArray.name, argArray.`type`) :: Nil)
|
||||
).leaf,
|
||||
CallServiceModel(
|
||||
LiteralModel("\"getSrv\"", LiteralType.string),
|
||||
LiteralModel.quote("getSrv"),
|
||||
"getIdx",
|
||||
CallModel(Nil, CallModel.Export(idxVar.name, idxVar.`type`) :: Nil)
|
||||
).leaf
|
||||
|
@ -24,7 +24,13 @@ class CopyInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
val length = FunctorRaw("length", ScalarType.u32)
|
||||
val lengthValue = VarRaw("l", arrType).withProperty(length)
|
||||
|
||||
val getField = CallArrowRaw(None, "get_field", Nil, ArrowType(NilType, UnlabeledConsType(ScalarType.string, NilType)), Option(LiteralRaw("\"serv\"", ScalarType.string)))
|
||||
val getField = CallArrowRaw(
|
||||
None,
|
||||
"get_field",
|
||||
Nil,
|
||||
ArrowType(NilType, UnlabeledConsType(ScalarType.string, NilType)),
|
||||
Option(LiteralRaw.quote("serv"))
|
||||
)
|
||||
|
||||
val copyRaw =
|
||||
IntoCopyRaw(structType, NonEmptyMap.of("field1" -> lengthValue, "field2" -> getField))
|
||||
@ -44,7 +50,7 @@ class CopyInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
ParModel.wrap(
|
||||
SeqModel.wrap(
|
||||
FlattenModel(VarModel("l", arrType), "l_to_functor").leaf,
|
||||
FlattenModel(VarModel("l_to_functor", arrType, Chain.one(lengthModel)), "l_length").leaf,
|
||||
FlattenModel(VarModel("l_to_functor", arrType, Chain.one(lengthModel)), "l_length").leaf
|
||||
),
|
||||
CallServiceModel(
|
||||
"serv",
|
||||
|
@ -29,7 +29,7 @@ class MakeStructInlinerSpec extends AnyFlatSpec with Matchers {
|
||||
"get_field",
|
||||
Nil,
|
||||
ArrowType(NilType, UnlabeledConsType(ScalarType.string, NilType)),
|
||||
Option(LiteralRaw("\"serv\"", ScalarType.string))
|
||||
Option(LiteralRaw.quote("serv"))
|
||||
)
|
||||
|
||||
val makeStruct =
|
||||
|
@ -0,0 +1,14 @@
|
||||
package aqua.model.inline
|
||||
|
||||
import aqua.model.{CallModel, CallServiceModel, LiteralModel, ValueModel, VarModel}
|
||||
|
||||
object ModelBuilder {
|
||||
|
||||
def add(l: ValueModel, r: ValueModel)(o: VarModel): CallServiceModel =
|
||||
CallServiceModel(
|
||||
serviceId = "math",
|
||||
funcName = "add",
|
||||
args = List(l, r),
|
||||
result = o
|
||||
)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package aqua.model.inline
|
||||
|
||||
import aqua.raw.value.{CallArrowRaw, LiteralRaw, ValueRaw}
|
||||
import aqua.types.{ArrowType, ProductType, ScalarType}
|
||||
|
||||
object RawBuilder {
|
||||
|
||||
def add(l: ValueRaw, r: ValueRaw): ValueRaw =
|
||||
CallArrowRaw(
|
||||
ability = Some("math"),
|
||||
name = "add",
|
||||
arguments = List(l, r),
|
||||
baseType = ArrowType(
|
||||
ProductType(List(ScalarType.i64, ScalarType.i64)),
|
||||
ProductType(
|
||||
List(l.`type` `∪` r.`type`)
|
||||
)
|
||||
),
|
||||
serviceId = Some(LiteralRaw.quote("math"))
|
||||
)
|
||||
}
|
@ -172,7 +172,8 @@ case class CollectionRaw(values: NonEmptyList[ValueRaw], boxType: BoxType) exten
|
||||
copy(values = values.map(_.renameVars(map)))
|
||||
}
|
||||
|
||||
case class MakeStructRaw(fields: NonEmptyMap[String, ValueRaw], structType: StructType) extends ValueRaw {
|
||||
case class MakeStructRaw(fields: NonEmptyMap[String, ValueRaw], structType: StructType)
|
||||
extends ValueRaw {
|
||||
|
||||
override def baseType: Type = structType
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.raw.arrow.FuncRaw
|
||||
import aqua.raw.ops.{CallArrowRawTag, FuncOp}
|
||||
import aqua.raw.ops.CallArrowRawTag
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.raw.value.CallArrowRaw
|
||||
import aqua.raw.{ConstantRaw, RawContext, RawPart, ServiceRaw, TypeRaw}
|
||||
|
@ -2,7 +2,7 @@ package aqua.model
|
||||
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.arrow.FuncRaw
|
||||
import aqua.raw.ops.{FuncOp, RawTag}
|
||||
import aqua.raw.ops.RawTag
|
||||
import aqua.raw.value.ValueRaw
|
||||
import aqua.types.{ArrowType, Type}
|
||||
|
||||
|
@ -39,6 +39,26 @@ object OpModel extends TreeNodeCompanion[OpModel] {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Meta information embedded in a tree
|
||||
*/
|
||||
enum MetaModel extends OpModel {
|
||||
|
||||
/**
|
||||
* Wraps subtree that was produced after inlining arrow
|
||||
*
|
||||
* @param name Name of arrow inlined
|
||||
*/
|
||||
case CallArrowModel(name: String)
|
||||
|
||||
override def wrap(children: Tree*): Tree =
|
||||
// NOTE: Consider leaving some meta info if call is completely erased?
|
||||
children.filter(_.head != EmptyModel) match {
|
||||
case Nil => EmptyModel.leaf
|
||||
case filtered => super.wrap(filtered: _*)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait NoExecModel extends OpModel
|
||||
|
||||
sealed trait ForceExecModel extends OpModel
|
||||
@ -95,9 +115,14 @@ case class MatchMismatchModel(left: ValueModel, right: ValueModel, shouldMatch:
|
||||
left.usesVarNames ++ right.usesVarNames
|
||||
}
|
||||
|
||||
case class ForModel(item: String, iterable: ValueModel, mode: Option[ForModel.Mode] = Some(ForModel.NullMode)) extends SeqGroupModel {
|
||||
case class ForModel(
|
||||
item: String,
|
||||
iterable: ValueModel,
|
||||
mode: Option[ForModel.Mode] = Some(ForModel.NullMode)
|
||||
) extends SeqGroupModel {
|
||||
|
||||
override def toString: String = s"for $item <- $iterable${mode.map(m => " " + m.toString).getOrElse("")}"
|
||||
override def toString: String =
|
||||
s"for $item <- $iterable${mode.map(m => " " + m.toString).getOrElse("")}"
|
||||
|
||||
override def restrictsVarNames: Set[String] = Set(item)
|
||||
|
||||
@ -142,9 +167,15 @@ case class CallServiceModel(serviceId: ValueModel, funcName: String, call: CallM
|
||||
}
|
||||
|
||||
object CallServiceModel {
|
||||
def apply(serviceId: String, funcName: String, args: List[ValueModel], result: VarModel): CallServiceModel =
|
||||
|
||||
def apply(
|
||||
serviceId: String,
|
||||
funcName: String,
|
||||
args: List[ValueModel],
|
||||
result: VarModel
|
||||
): CallServiceModel =
|
||||
CallServiceModel(
|
||||
LiteralModel(s"\"$serviceId\"", ScalarType.string),
|
||||
LiteralModel.quote(serviceId),
|
||||
funcName,
|
||||
CallModel(
|
||||
args,
|
||||
|
@ -47,6 +47,8 @@ case class LiteralModel(value: String, `type`: Type) extends ValueModel {
|
||||
|
||||
object LiteralModel {
|
||||
def fromRaw(raw: LiteralRaw): LiteralModel = LiteralModel(raw.value, raw.baseType)
|
||||
|
||||
def quote(str: String): LiteralModel = LiteralModel(s"\"$str\"", LiteralType.string)
|
||||
}
|
||||
|
||||
sealed trait PropertyModel {
|
||||
|
@ -16,7 +16,9 @@ import aqua.types.ScalarType
|
||||
import cats.Eval
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
import cats.syntax.option.*
|
||||
import scribe.Logging
|
||||
import aqua.model.transform.TransformConfig.TracingConfig
|
||||
|
||||
// API for transforming RawTag to Res
|
||||
object Transform extends Logging {
|
||||
@ -87,6 +89,11 @@ object Transform extends Logging {
|
||||
callable = initCallable
|
||||
)
|
||||
|
||||
val tracing = Tracing(
|
||||
enabledConfig = conf.tracing,
|
||||
initCallable = initCallable
|
||||
)
|
||||
|
||||
val argsProvider: ArgsProvider = ArgsFromService(
|
||||
dataServiceId = conf.dataSrvId,
|
||||
names = relayVar.toList ::: func.arrowType.domain.labelledData
|
||||
@ -110,9 +117,10 @@ object Transform extends Logging {
|
||||
// Pre transform and inline the function
|
||||
model <- funcToModelTree(func, preTransformer)
|
||||
// Post transform the function
|
||||
postModel = errorsCatcher.transform(model)
|
||||
errorsModel = errorsCatcher.transform(model)
|
||||
tracingModel <- tracing(errorsModel)
|
||||
// Resolve topology
|
||||
resolved <- Topology.resolve(postModel)
|
||||
resolved <- Topology.resolve(tracingModel)
|
||||
// Clear the tree
|
||||
result = clear(resolved)
|
||||
} yield FuncRes(
|
||||
|
@ -16,6 +16,7 @@ case class TransformConfig(
|
||||
respFuncName: String = "response",
|
||||
relayVarName: Option[String] = Some("-relay-"),
|
||||
wrapWithXor: Boolean = true,
|
||||
tracing: Option[TransformConfig.TracingConfig] = None,
|
||||
constants: List[ConstantRaw] = Nil
|
||||
) {
|
||||
|
||||
@ -29,3 +30,15 @@ case class TransformConfig(
|
||||
val constantsList: List[ConstantRaw] =
|
||||
ConstantRaw.defaultConstants(relayVarName) ::: constants
|
||||
}
|
||||
|
||||
object TransformConfig {
|
||||
|
||||
final case class TracingConfig(
|
||||
serviceId: String = "tracingSrv",
|
||||
serviceFuncName: String = "tracingEvent"
|
||||
)
|
||||
|
||||
object TracingConfig {
|
||||
lazy val default = TracingConfig()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,34 @@
|
||||
package aqua.model.transform.funcop
|
||||
|
||||
import aqua.model.OpModel
|
||||
|
||||
import cats.data.Chain
|
||||
import cats.free.Cofree
|
||||
import cats.Eval
|
||||
|
||||
/**
|
||||
* Base type for [[OpModel.Tree]] -> [[OpModel.Tree]] transformation
|
||||
*/
|
||||
trait OpTransform {
|
||||
|
||||
/**
|
||||
* Transformation step
|
||||
* (node, child results) => node result
|
||||
*/
|
||||
def folder: OpTransform.OpFolder
|
||||
|
||||
def apply(tree: OpModel.Tree): Eval[OpModel.Tree] =
|
||||
Cofree.cata[Chain, OpModel, OpModel.Tree](tree)((op, children) =>
|
||||
folder
|
||||
.lift(op, children)
|
||||
.getOrElse(
|
||||
Eval.now(
|
||||
op.wrap(children.toList: _*)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object OpTransform {
|
||||
type OpFolder = PartialFunction[(OpModel, Chain[OpModel.Tree]), Eval[OpModel.Tree]]
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package aqua.model.transform.funcop
|
||||
|
||||
import cats.data.Chain
|
||||
|
||||
import cats.Eval
|
||||
|
||||
import aqua.model.{
|
||||
CallModel,
|
||||
CallServiceModel,
|
||||
LiteralModel,
|
||||
MetaModel,
|
||||
OpModel,
|
||||
SeqModel,
|
||||
ValueModel
|
||||
}
|
||||
import aqua.model.transform.pre.InitPeerCallable
|
||||
import aqua.model.ParModel
|
||||
import aqua.model.DetachModel
|
||||
import aqua.model.transform.TransformConfig.TracingConfig
|
||||
|
||||
final case class Tracing(
|
||||
enabledConfig: Option[TracingConfig],
|
||||
initCallable: InitPeerCallable
|
||||
) extends OpTransform {
|
||||
import Tracing.*
|
||||
|
||||
private def getChild(children: Chain[OpModel.Tree]): OpModel.Tree =
|
||||
children.headOption
|
||||
.filter(_ => children.length == 1)
|
||||
.getOrElse(
|
||||
SeqModel.wrap(children.toList: _*)
|
||||
)
|
||||
|
||||
override def folder: OpTransform.OpFolder = {
|
||||
case (MetaModel.CallArrowModel(arrowName), children) =>
|
||||
val child = getChild(children)
|
||||
|
||||
Eval.now(
|
||||
enabledConfig
|
||||
.map(traceCallModel(_, arrowName))
|
||||
.fold(child)(traceCall =>
|
||||
/* seq:
|
||||
detach: call tracing enter
|
||||
<call-arrow-code>
|
||||
detach: call tracing exit */
|
||||
SeqModel.wrap(
|
||||
DetachModel.wrap(
|
||||
initCallable.onInitPeer.wrap(
|
||||
traceCall(Event.Enter)
|
||||
)
|
||||
),
|
||||
child,
|
||||
DetachModel.wrap(
|
||||
initCallable.onInitPeer.wrap(
|
||||
traceCall(Event.Exit)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object Tracing {
|
||||
|
||||
enum Event {
|
||||
case Enter, Exit
|
||||
|
||||
def toArg: ValueModel = LiteralModel.quote(this match {
|
||||
case Enter => "enter"
|
||||
case Exit => "exit"
|
||||
})
|
||||
}
|
||||
|
||||
def traceCallModel(config: TracingConfig, arrowName: String)(
|
||||
event: Event
|
||||
): OpModel.Tree =
|
||||
CallServiceModel(
|
||||
LiteralModel.quote(config.serviceId),
|
||||
config.serviceFuncName,
|
||||
CallModel(
|
||||
args = List(LiteralModel.quote(arrowName), event.toArg),
|
||||
exportTo = Nil
|
||||
)
|
||||
).leaf
|
||||
}
|
@ -2,7 +2,7 @@ package aqua.model.transform.pre
|
||||
|
||||
import aqua.model.FuncArrow
|
||||
import aqua.model.ArgsCall
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, FuncOp, RawTag, SeqTag}
|
||||
import aqua.raw.ops.{Call, CallArrowRawTag, RawTag, SeqTag}
|
||||
import aqua.raw.value.{ValueRaw, VarRaw}
|
||||
import aqua.types.*
|
||||
import cats.syntax.show.*
|
||||
|
@ -16,16 +16,16 @@ trait TreeNodeCompanion[T <: TreeNode[T]] {
|
||||
type Tree = Cofree[Chain, T]
|
||||
|
||||
private def showOffset(what: Tree, offset: Int): String = {
|
||||
val spaces = " " * offset
|
||||
val spaces = "| " * offset
|
||||
spaces + what.head.show + what.tail.map {
|
||||
case ch if ch.nonEmpty =>
|
||||
" :\n" + ch.toList.map(showOffset(_, offset + 1)).mkString("") + "\n"
|
||||
" :\n" + ch.toList.map(showOffset(_, offset + 1)).mkString("")
|
||||
case ch => "\n"
|
||||
}.value
|
||||
}
|
||||
|
||||
private def showDiffOffset(what: (Tree, Tree), offset: Int): String = {
|
||||
val spaces = " " * offset
|
||||
val spaces = "| " * offset
|
||||
val head =
|
||||
if (what._1.head == what._2.head) what._1.head.show
|
||||
else {
|
||||
|
@ -23,6 +23,7 @@ import cats.Reducible
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.kernel.Monoid
|
||||
import cats.syntax.applicative.*
|
||||
import cats.syntax.option.*
|
||||
import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
@ -59,9 +60,7 @@ class RawSemantics[S[_]](implicit p: Picker[RawContext]) extends Semantics[S, Ra
|
||||
.map { case (state, ctx) =>
|
||||
NonEmptyChain
|
||||
.fromChain(state.errors)
|
||||
.fold[ValidatedNec[SemanticError[S], RawContext]](
|
||||
Valid(ctx)
|
||||
)(Invalid(_))
|
||||
.toInvalid(ctx)
|
||||
}
|
||||
// TODO: return as Eval
|
||||
.value
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{AbilityIdTag, FuncOp}
|
||||
import aqua.raw.ops.AbilityIdTag
|
||||
import aqua.parser.expr.func.AbilityIdExpr
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
|
@ -133,13 +133,15 @@ class ArrowSem[S[_]](val expr: ArrowExpr[S]) extends AnyVal {
|
||||
|
||||
(
|
||||
SeqTag.wrap(
|
||||
bodyAcc :: CanonicalizeTag(
|
||||
bodyAcc,
|
||||
CanonicalizeTag(
|
||||
VarRaw(streamName, streamType),
|
||||
Call.Export(canonReturnVar.name, canonReturnVar.`type`)
|
||||
).leaf :: FlattenTag(
|
||||
).leaf,
|
||||
FlattenTag(
|
||||
canonReturnVar,
|
||||
returnVar.name
|
||||
).leaf :: Nil: _*
|
||||
).leaf
|
||||
),
|
||||
returnAcc :+ returnVar,
|
||||
idx + 1
|
||||
|
@ -3,7 +3,7 @@ package aqua.semantics.expr.func
|
||||
import aqua.raw.Raw
|
||||
import aqua.types.ArrowType
|
||||
import aqua.raw.value.CallArrowRaw
|
||||
import aqua.raw.ops.{AssignmentTag, ClosureTag, FuncOp}
|
||||
import aqua.raw.ops.{AssignmentTag, ClosureTag}
|
||||
import aqua.parser.expr.func.AssignmentExpr
|
||||
import aqua.raw.arrow.FuncRaw
|
||||
import aqua.semantics.Prog
|
||||
|
@ -16,34 +16,42 @@ import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.{Monad, Traverse}
|
||||
import aqua.raw.value.CallArrowRaw
|
||||
|
||||
class CallArrowSem[S[_]](val expr: CallArrowExpr[S]) extends AnyVal {
|
||||
|
||||
import expr.*
|
||||
|
||||
private def getExports[Alg[_]: Monad](callArrow: CallArrowRaw)(implicit
|
||||
N: NamesAlgebra[S, Alg],
|
||||
T: TypesAlgebra[S, Alg]
|
||||
): Alg[List[Call.Export]] =
|
||||
(variables zip callArrow.baseType.codomain.toList).traverse { case (v, t) =>
|
||||
N.read(v, mustBeDefined = false).flatMap {
|
||||
case Some(stream @ StreamType(st)) =>
|
||||
T.ensureTypeMatches(v, st, t).as(Call.Export(v.value, stream))
|
||||
case _ =>
|
||||
N.define(v, t).as(Call.Export(v.value, t))
|
||||
}
|
||||
}
|
||||
|
||||
private def toModel[Alg[_]: Monad](implicit
|
||||
N: NamesAlgebra[S, Alg],
|
||||
A: AbilitiesAlgebra[S, Alg],
|
||||
T: TypesAlgebra[S, Alg],
|
||||
V: ValuesAlgebra[S, Alg]
|
||||
): Alg[Option[FuncOp]] = V.callArrowToRaw(callArrow).flatMap {
|
||||
case None => None.pure[Alg]
|
||||
case Some(car) =>
|
||||
): Alg[Option[FuncOp]] = for {
|
||||
callArrowRaw <- V.callArrowToRaw(callArrow)
|
||||
maybeOp <- callArrowRaw.traverse(car =>
|
||||
variables
|
||||
.drop(car.baseType.codomain.length)
|
||||
.headOption
|
||||
.fold(
|
||||
(variables zip car.baseType.codomain.toList).traverse { case (v, t) =>
|
||||
N.read(v, mustBeDefined = false).flatMap {
|
||||
case Some(stream @ StreamType(st)) =>
|
||||
T.ensureTypeMatches(v, st, t).as(Call.Export(v.value, stream))
|
||||
case _ =>
|
||||
N.define(v, t).as(Call.Export(v.value, t))
|
||||
}
|
||||
}
|
||||
)(T.expectNoExport(_).as(Nil))
|
||||
.map(maybeExport => Some(CallArrowRawTag(maybeExport, car).funcOpLeaf))
|
||||
}
|
||||
.fold(getExports(car))(
|
||||
T.expectNoExport(_).as(Nil)
|
||||
)
|
||||
.map(maybeExports => CallArrowRawTag(maybeExports, car).funcOpLeaf)
|
||||
)
|
||||
} yield maybeOp
|
||||
|
||||
def program[Alg[_]: Monad](implicit
|
||||
N: NamesAlgebra[S, Alg],
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{ClosureTag, FuncOp}
|
||||
import aqua.raw.ops.ClosureTag
|
||||
import aqua.raw.arrow.{ArrowRaw, FuncRaw}
|
||||
import aqua.parser.expr.FuncExpr
|
||||
import aqua.parser.expr.func.ClosureExpr
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{DeclareStreamTag, FuncOp}
|
||||
import aqua.raw.ops.DeclareStreamTag
|
||||
import aqua.parser.expr.func.DeclareStreamExpr
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.value.VarRaw
|
||||
|
@ -2,7 +2,7 @@ package aqua.semantics.expr.func
|
||||
|
||||
import aqua.parser.expr.func.JoinExpr
|
||||
import aqua.raw.Raw
|
||||
import aqua.raw.ops.{FuncOp, JoinTag}
|
||||
import aqua.raw.ops.JoinTag
|
||||
import aqua.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{Call, FuncOp, PushToStreamTag}
|
||||
import aqua.raw.ops.{Call, PushToStreamTag}
|
||||
import aqua.parser.expr.func.PushToStreamExpr
|
||||
import aqua.parser.lexer.Token
|
||||
import aqua.raw.Raw
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.semantics.expr.func
|
||||
|
||||
import aqua.raw.ops.{FuncOp, ReturnTag}
|
||||
import aqua.raw.ops.ReturnTag
|
||||
import aqua.parser.expr.func.ReturnExpr
|
||||
import aqua.raw.Raw
|
||||
import aqua.semantics.Prog
|
||||
|
@ -14,6 +14,7 @@ import cats.syntax.apply.*
|
||||
import cats.syntax.flatMap.*
|
||||
import cats.syntax.functor.*
|
||||
import cats.syntax.traverse.*
|
||||
import cats.syntax.option.*
|
||||
import cats.instances.list.*
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
|
||||
@ -209,18 +210,18 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
|
||||
}
|
||||
|
||||
def callArrowToRaw(ca: CallArrowToken[S]): Alg[Option[CallArrowRaw]] =
|
||||
ca.ability
|
||||
def callArrowToRaw(ca: CallArrowToken[S]): Alg[Option[CallArrowRaw]] = for {
|
||||
raw <- ca.ability
|
||||
.fold(
|
||||
N.readArrow(ca.funcName)
|
||||
.map(
|
||||
_.map(
|
||||
_.map(bt =>
|
||||
CallArrowRaw(
|
||||
None,
|
||||
ca.funcName.value,
|
||||
Nil,
|
||||
_,
|
||||
None
|
||||
ability = None,
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = bt,
|
||||
serviceId = None
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -228,49 +229,48 @@ class ValuesAlgebra[S[_], Alg[_]: Monad](implicit
|
||||
(A.getArrow(ab, ca.funcName), A.getServiceId(ab)).mapN {
|
||||
case (Some(at), Right(sid)) =>
|
||||
// Service call, actually
|
||||
Some(
|
||||
CallArrowRaw(
|
||||
Some(ab.value),
|
||||
ca.funcName.value,
|
||||
Nil,
|
||||
at,
|
||||
Some(sid)
|
||||
)
|
||||
)
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = Some(sid)
|
||||
).some
|
||||
case (Some(at), Left(true)) =>
|
||||
// Ability function call, actually
|
||||
Some(
|
||||
CallArrowRaw(
|
||||
Some(ab.value),
|
||||
ca.funcName.value,
|
||||
Nil,
|
||||
at,
|
||||
None
|
||||
)
|
||||
)
|
||||
case _ => None
|
||||
CallArrowRaw(
|
||||
ability = Some(ab.value),
|
||||
name = ca.funcName.value,
|
||||
arguments = Nil,
|
||||
baseType = at,
|
||||
serviceId = None
|
||||
).some
|
||||
case _ => none
|
||||
}
|
||||
)
|
||||
.flatMap {
|
||||
case Some(r) =>
|
||||
val arr = r.baseType
|
||||
T.checkArgumentsNumber(ca.funcName, arr.domain.length, ca.args.length).flatMap {
|
||||
case false => Option.empty[CallArrowRaw].pure[Alg]
|
||||
case true =>
|
||||
(ca.args zip arr.domain.toList).traverse { case (tkn, tp) =>
|
||||
valueToRaw(tkn).flatMap {
|
||||
case Some(v) => T.ensureTypeMatches(tkn, tp, v.`type`).map(Option.when(_)(v))
|
||||
case None => None.pure[Alg]
|
||||
}
|
||||
}.map(_.toList.flatten).map {
|
||||
case args: List[ValueRaw] if args.length == arr.domain.length =>
|
||||
Some(r.copy(arguments = args))
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
case None => Option.empty[CallArrowRaw].pure[Alg]
|
||||
}
|
||||
result <- raw.flatTraverse(r =>
|
||||
val arr = r.baseType
|
||||
for {
|
||||
argsCheck <- T.checkArgumentsNumber(ca.funcName, arr.domain.length, ca.args.length)
|
||||
args <- Option
|
||||
.when(argsCheck)(ca.args zip arr.domain.toList)
|
||||
.traverse(
|
||||
_.flatTraverse { case (tkn, tp) =>
|
||||
for {
|
||||
maybeValueRaw <- valueToRaw(tkn)
|
||||
checked <- maybeValueRaw.flatTraverse(v =>
|
||||
T.ensureTypeMatches(tkn, tp, v.`type`)
|
||||
.map(Option.when(_)(v))
|
||||
)
|
||||
} yield checked.toList
|
||||
}
|
||||
)
|
||||
result = args
|
||||
.filter(_.length == arr.domain.length)
|
||||
.map(args => r.copy(arguments = args))
|
||||
} yield result
|
||||
)
|
||||
} yield result
|
||||
|
||||
def checkArguments(token: Token[S], arr: ArrowType, args: List[ValueToken[S]]): Alg[Boolean] =
|
||||
// TODO: do we really need to check this?
|
||||
|
@ -169,7 +169,7 @@ object ScalarType {
|
||||
}
|
||||
|
||||
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends DataType {
|
||||
override def toString: String = name
|
||||
override def toString: String = s"$name:lt"
|
||||
}
|
||||
|
||||
object LiteralType {
|
||||
|
Loading…
Reference in New Issue
Block a user