diff --git a/api/api/.js/src/main/scala/api/AquaAPI.scala b/api/api/.js/src/main/scala/api/AquaAPI.scala index cea82a62..cc99f9b6 100644 --- a/api/api/.js/src/main/scala/api/AquaAPI.scala +++ b/api/api/.js/src/main/scala/api/AquaAPI.scala @@ -17,7 +17,6 @@ import aqua.io.* import aqua.js.{FunctionDefJs, ServiceDefJs, VarJson} import aqua.logging.{LogFormatter, LogLevels} import aqua.model.AquaContext -import aqua.model.transform.{Transform, TransformConfig} import aqua.parser.lexer.{LiteralToken, Token} import aqua.parser.{ArrowReturnError, BlockIndentError, LexerError, ParserError} import aqua.raw.ops.Call diff --git a/api/api/.js/src/main/scala/api/types/InputTypes.scala b/api/api/.js/src/main/scala/api/types/InputTypes.scala index aca5e9ba..cf05d10c 100644 --- a/api/api/.js/src/main/scala/api/types/InputTypes.scala +++ b/api/api/.js/src/main/scala/api/types/InputTypes.scala @@ -3,7 +3,6 @@ package api.types import aqua.api.AquaAPIConfig import aqua.api.TargetType.* import aqua.js.{FunctionDefJs, ServiceDefJs} -import aqua.model.transform.TransformConfig import cats.data.Validated.{invalidNec, validNec} import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec} diff --git a/api/api/.jvm/src/main/scala/aqua/api/Test.scala b/api/api/.jvm/src/main/scala/aqua/api/Test.scala index d81c0041..295480d7 100644 --- a/api/api/.jvm/src/main/scala/aqua/api/Test.scala +++ b/api/api/.jvm/src/main/scala/aqua/api/Test.scala @@ -18,9 +18,10 @@ object Test extends IOApp.Simple { .compilePath( "./aqua-src/antithesis.aqua", Imports.fromMap(Map("/" -> Map("" -> List("./aqua")))), - AquaAPIConfig(targetType = TypeScriptType), + AquaAPIConfig(targetType = TypeScriptType, noXor = true), TypeScriptBackend(false, "IFluenceClient$$") - ).timed + ) + .timed .flatMap { case (duration, res) => println("Compilation time: " + duration.toMillis) val (warnings, result) = res.value.run diff --git a/api/api/src/main/scala/aqua/api/APICompilation.scala b/api/api/src/main/scala/aqua/api/APICompilation.scala index 0191e065..ce947a1e 100644 --- a/api/api/src/main/scala/aqua/api/APICompilation.scala +++ b/api/api/src/main/scala/aqua/api/APICompilation.scala @@ -55,14 +55,16 @@ object APICompilation { LogLevels.levelFromString(aquaConfig.logLevel), Constants.parse(aquaConfig.constants) ).tupled.toResult.flatTraverse { case (level, constants) => - val transformConfig = aquaConfig.getTransformConfig.copy(constants = constants) + val transformConfig = aquaConfig.getTransformConfig + val config = aquaConfig.getCompilerConfig.copy(constants = constants) LogFormatter.initLogger(Some(level)) new FuncCompiler[IO]( Some(RelativePath(Path(pathStr))), imports.toIO, - transformConfig + transformConfig, + config ).compile().map { contextV => for { context <- contextV.toResult @@ -140,7 +142,7 @@ object APICompilation { LogFormatter.initLogger(Some(level)) val transformConfig = aquaConfig.getTransformConfig - val config = AquaCompilerConf(constants ++ transformConfig.constantsList) + val config = aquaConfig.getCompilerConfig.copy(constants = constants) CompilerAPI .compile[IO, AquaFileError, FileModuleId, FileSpan.F]( diff --git a/api/api/src/main/scala/aqua/api/AquaAPIConfig.scala b/api/api/src/main/scala/aqua/api/AquaAPIConfig.scala index 860d5e60..ba4527eb 100644 --- a/api/api/src/main/scala/aqua/api/AquaAPIConfig.scala +++ b/api/api/src/main/scala/aqua/api/AquaAPIConfig.scala @@ -1,4 +1,6 @@ package aqua.api + +import aqua.compiler.AquaCompilerConf import aqua.model.transform.TransformConfig enum TargetType: @@ -8,7 +10,7 @@ case class AquaAPIConfig( targetType: TargetType = TargetType.AirType, logLevel: String = "info", constants: List[String] = Nil, - noXor: Boolean = false, // TODO: Remove + noXor: Boolean = false, noRelay: Boolean = false, tracing: Boolean = false, noEmptyResponse: Boolean = true @@ -17,10 +19,18 @@ case class AquaAPIConfig( def getTransformConfig: TransformConfig = { val config = TransformConfig( tracing = Option.when(tracing)(TransformConfig.TracingConfig.default), - noEmptyResponse = noEmptyResponse + noEmptyResponse = noEmptyResponse, + noXor = noXor ) if (noRelay) config.copy(relayVarName = None) else config } + + def getCompilerConfig: AquaCompilerConf = { + val config = AquaCompilerConf() + + if (noRelay) config.copy(relayVarName = None) + else config + } } diff --git a/aqua-run/src/main/scala/aqua/run/FuncCompiler.scala b/aqua-run/src/main/scala/aqua/run/FuncCompiler.scala index ec4347f7..cc02acb4 100644 --- a/aqua-run/src/main/scala/aqua/run/FuncCompiler.scala +++ b/aqua-run/src/main/scala/aqua/run/FuncCompiler.scala @@ -22,14 +22,14 @@ import scribe.Logging class FuncCompiler[F[_]: Files: AquaIO: Async]( input: Option[AquaPath], imports: Imports, - transformConfig: TransformConfig + transformConfig: TransformConfig, + config: AquaCompilerConf ) extends Logging { type Result = [A] =>> CompileResult[FileModuleId, AquaFileError, FileSpan.F][A] private def compileToContext( - path: Path, - config: AquaCompilerConf = AquaCompilerConf(transformConfig.constantsList) + path: Path ): F[Result[Chain[AquaContext]]] = { val sources = new AquaFileSources[F](path, imports) CompilerAPI.compileToContext[F, AquaFileError, FileModuleId, FileSpan.F]( diff --git a/aqua-src/antithesis.aqua b/aqua-src/antithesis.aqua index 7d07de39..c8615422 100644 --- a/aqua-src/antithesis.aqua +++ b/aqua-src/antithesis.aqua @@ -1,48 +1,15 @@ aqua Main -export bugLNG346 +export main -ability Promise: - yield() -> string +service Srv("srv"): + call(x: i32) -> i32 -func done_nil() -> string: - <- "" +func main(a: i32, b: i32) -> i32: + res: *i32 + if a > b: + on "peer" via "relay": + res <- Srv.call(a) -func done() -> Promise: - <- Promise(yield = done_nil) + <- res! -ability Compute: - yield() -> string - -alias WorkerYield: -> string -alias Yield: WorkerYield -> Promise - -func wait_for() -> Yield: - wait = func (cb: -> string) -> Promise: - yield = func () -> string: - e <- cb() - <- e - <- Promise(yield = yield) - <- wait - -ability Function: - run(dealId: string) -> string - -func simple{Compute}(yield: Yield) -> Function: - deal_run = func () -> string: - c_yield = func () -> string: - <- Compute.yield() - yieeld <- yield(c_yield) - res <- yieeld.yield() - <- res - <- Function(run = deal_run) - -func bugLNG346() -> string: - res: *string - yieeld = func () -> string: - res <<- "hello" - <- "" - c = Compute(yield = yieeld) - fn = simple{c}(wait_for()) - r <- fn.run("") - <- res! \ No newline at end of file diff --git a/compiler/src/main/scala/aqua/compiler/AquaCompilerConf.scala b/compiler/src/main/scala/aqua/compiler/AquaCompilerConf.scala index 6df280e8..ae60bff1 100644 --- a/compiler/src/main/scala/aqua/compiler/AquaCompilerConf.scala +++ b/compiler/src/main/scala/aqua/compiler/AquaCompilerConf.scala @@ -6,5 +6,9 @@ import aqua.raw.ConstantRaw * What should compiler care about during compilation – before generator backend takes its role * * @param constantsList List of known constants + * @param relayVarName Name of the relay variable */ -case class AquaCompilerConf(constantsList: List[ConstantRaw]) +case class AquaCompilerConf( + constants: List[ConstantRaw] = Nil, + relayVarName: Option[String] = Some("-relay-") +) diff --git a/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala b/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala index 764b2aaf..67d4036e 100644 --- a/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala +++ b/compiler/src/main/scala/aqua/compiler/CompilerAPI.scala @@ -4,7 +4,7 @@ import aqua.backend.Backend import aqua.compiler.AquaError.* import aqua.model.AquaContext import aqua.parser.{Ast, ParserError} -import aqua.raw.RawContext +import aqua.raw.{ConstantRaw, RawContext} import aqua.semantics.header.{HeaderHandler, HeaderSem} import aqua.semantics.rules.locations.{DummyLocationsInterpreter, LocationsAlgebra} import aqua.semantics.{FileId, RawSemantics} @@ -48,7 +48,7 @@ object CompilerAPI extends Logging { .implicits( RawContext.blank.copy( parts = Chain - .fromSeq(config.constantsList) + .fromSeq(config.constants ++ ConstantRaw.defaultConstants(config.relayVarName)) .map(const => RawContext.blank -> const) ) ) diff --git a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala index b3727b7a..73ab79b2 100644 --- a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala +++ b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala @@ -883,4 +883,94 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { } } } + + it should "not generate error propagation in `if` with `noXor = true`" in { + val src = Map( + "index.aqua" -> + """aqua Test + | + |export main + | + |service Srv("srv"): + | call() + | + |func main(a: i32): + | if a > 0: + | Srv.call() + |""".stripMargin + ) + + val transformCfg = TransformConfig(noEmptyResponse = true, relayVarName = None, noXor = true) + + insideRes(src, transformCfg = transformCfg)("main") { case main :: Nil => + val aArg = VarModel("-a-arg-", ScalarType.i32) + val gt = CallModel.Export("gt", ScalarType.bool) + val expected = XorRes.wrap( + SeqRes.wrap( + getDataSrv("a", aArg.name, aArg.baseType), + CallServiceRes( + LiteralModel.quote("cmp"), + "gt", + CallRes(aArg :: LiteralModel.number(0) :: Nil, Some(gt)), + initPeer + ).leaf, + XorRes.wrap( + MatchMismatchRes(gt.asVar, LiteralModel.bool(true), true).wrap( + CallServiceRes( + LiteralModel.quote("srv"), + "call", + CallRes(Nil, None), + initPeer + ).leaf + ) + ) + ), + errorCall(transformCfg, 0, initPeer) + ) + + main.body.equalsOrShowDiff(expected) should be(true) + } + } + + it should "not generate error propagation in `on` with `noXor = true`" in { + val src = Map( + "index.aqua" -> + """aqua Test + | + |export main + | + |service Srv("srv"): + | call() + | + |func main(): + | on "peer" via "relay": + | Srv.call() + | Srv.call() + |""".stripMargin + ) + + val transformCfg = TransformConfig(noEmptyResponse = true, relayVarName = None, noXor = true) + + insideRes(src, transformCfg = transformCfg)("main") { case main :: Nil => + def call(peer: ValueModel) = + CallServiceRes( + LiteralModel.quote("srv"), + "call", + CallRes(Nil, None), + peer + ).leaf + + val expected = XorRes.wrap( + SeqRes.wrap( + through(LiteralModel.quote("relay")), + call(LiteralModel.quote("peer")), + through(LiteralModel.quote("relay")), + call(initPeer) + ), + errorCall(transformCfg, 0, initPeer) + ) + + main.body.equalsOrShowDiff(expected) should be(true) + } + } } diff --git a/language-server/language-server-api/src/main/scala/aqua/lsp/LSPCompiler.scala b/language-server/language-server-api/src/main/scala/aqua/lsp/LSPCompiler.scala index 0dfc5c72..aa6d87c5 100644 --- a/language-server/language-server-api/src/main/scala/aqua/lsp/LSPCompiler.scala +++ b/language-server/language-server-api/src/main/scala/aqua/lsp/LSPCompiler.scala @@ -2,10 +2,11 @@ package aqua.lsp import aqua.compiler.{AquaCompiler, AquaCompilerConf, AquaError, AquaSources} import aqua.parser.{Ast, ParserError} -import aqua.raw.RawContext +import aqua.raw.{ConstantRaw, RawContext} +import aqua.semantics.FileId import aqua.semantics.header.{HeaderHandler, HeaderSem} import aqua.semantics.rules.locations.LocationsAlgebra -import aqua.semantics.FileId + import cats.data.Validated.validNec import cats.data.{Chain, State, Validated, ValidatedNec} import cats.syntax.either.* @@ -24,7 +25,7 @@ object LSPCompiler { LspContext.blank.copy(raw = RawContext.blank.copy( parts = Chain - .fromSeq(config.constantsList) + .fromSeq(config.constants ++ ConstantRaw.defaultConstants(config.relayVarName)) .map(const => RawContext.blank -> const) ) ) diff --git a/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala b/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala index be3ebd27..31bcce5d 100644 --- a/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/ArrowInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline import aqua.errors.Errors.internalError import aqua.model import aqua.model.* -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.ops.RawTag import aqua.raw.value.{ValueRaw, VarRaw} import aqua.types.* @@ -27,7 +27,7 @@ import scribe.Logging */ object ArrowInliner extends Logging { - def callArrow[S: Exports: Arrows: Mangler]( + def callArrow[S: Exports: Arrows: Mangler: Config]( arrow: FuncArrow, call: CallModel ): State[S, OpModel.Tree] = @@ -43,7 +43,7 @@ object ArrowInliner extends Logging { ) // push results to streams if they are exported to streams - private def pushStreamResults[S: Mangler: Exports: Arrows]( + private def pushStreamResults[S: Mangler: Exports: Arrows: Config]( outsideStreamNames: Set[String], exportTo: List[CallModel.Export], results: List[ValueRaw] @@ -140,7 +140,7 @@ object ArrowInliner extends Logging { } // Apply a callable function, get its fully resolved body & optional value, if any - private def inline[S: Mangler: Arrows: Exports]( + private def inline[S: Mangler: Arrows: Exports: Config]( fn: FuncArrow, call: CallModel, outsideDeclaredStreams: Set[String] @@ -542,7 +542,7 @@ object ArrowInliner extends Logging { _ <- Exports[S].resolved(exportsResolved) } yield (fn.copy(body = treeWithCanons, ret = ret), SeqModel.wrap(canons)) - private[inline] def callArrowRet[S: Exports: Arrows: Mangler]( + private[inline] def callArrowRet[S: Exports: Arrows: Mangler: Config]( arrow: FuncArrow, call: CallModel ): State[S, (OpModel.Tree, List[ValueModel])] = for { diff --git a/model/inline/src/main/scala/aqua/model/inline/MakeStructRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/MakeStructRawInliner.scala index d8fdc133..baa59d2d 100644 --- a/model/inline/src/main/scala/aqua/model/inline/MakeStructRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/MakeStructRawInliner.scala @@ -1,15 +1,15 @@ package aqua.model.inline +import aqua.model.* import aqua.model.inline.RawValueInliner.unfold import aqua.model.inline.raw.RawInliner -import aqua.model.inline.state.{Arrows, Exports, Mangler} -import aqua.model.* +import aqua.model.inline.state.* import aqua.raw.value.MakeStructRaw import aqua.types.{StreamMapType, StructType} import cats.data.{Chain, NonEmptyMap, State} -import cats.syntax.foldable.* import cats.syntax.bifunctor.* +import cats.syntax.foldable.* import cats.syntax.functor.* object MakeStructRawInliner extends RawInliner[MakeStructRaw] { @@ -58,7 +58,7 @@ object MakeStructRawInliner extends RawInliner[MakeStructRaw] { constructThroughMap(mapName, mapType, CallModel.Export(resultName, resultType), fields) } - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: MakeStructRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/RawValueInliner.scala b/model/inline/src/main/scala/aqua/model/inline/RawValueInliner.scala index d0482fd8..63d4549c 100644 --- a/model/inline/src/main/scala/aqua/model/inline/RawValueInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/RawValueInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline import aqua.model.* import aqua.model.inline.Inline.MergeMode.* import aqua.model.inline.raw.* -import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.ops.* import aqua.raw.value.* import aqua.types.{ArrayType, LiteralType, OptionType, StreamType} @@ -23,7 +23,7 @@ object RawValueInliner extends Logging { import aqua.model.inline.Inline.* - private[inline] def unfold[S: Mangler: Exports: Arrows]( + private[inline] def unfold[S: Mangler: Exports: Arrows: Config]( raw: ValueRaw, propertiesAllowed: Boolean = true ): State[S, (ValueModel, Inline)] = for { @@ -69,7 +69,7 @@ object RawValueInliner extends Logging { } } yield result - private[inline] def inlineToTree[S: Mangler: Exports: Arrows]( + private[inline] def inlineToTree[S: Mangler: Exports: Arrows: Config]( inline: Inline ): State[S, List[OpModel.Tree]] = (inline.mergeMode match { @@ -77,7 +77,7 @@ object RawValueInliner extends Logging { case ParMode => inline.predo.toList }).pure - private[inline] def toModel[S: Mangler: Exports: Arrows]( + private[inline] def toModel[S: Mangler: Exports: Arrows: Config]( unfoldF: State[S, (ValueModel, Inline)] ): State[S, (ValueModel, Option[OpModel.Tree])] = for { @@ -92,7 +92,7 @@ object RawValueInliner extends Logging { _ = logger.trace("map was: " + map) } yield vm -> parDesugarPrefix(ops.filterNot(_ == EmptyModel.leaf)) - def valueToModel[S: Mangler: Exports: Arrows]( + def valueToModel[S: Mangler: Exports: Arrows: Config]( value: ValueRaw, propertiesAllowed: Boolean = true ): State[S, (ValueModel, Option[OpModel.Tree])] = for { @@ -100,7 +100,7 @@ object RawValueInliner extends Logging { model <- toModel(unfold(value, propertiesAllowed)) } yield model - def valueListToModel[S: Mangler: Exports: Arrows]( + def valueListToModel[S: Mangler: Exports: Arrows: Config]( values: List[ValueRaw] ): State[S, List[(ValueModel, Option[OpModel.Tree])]] = values.traverse(valueToModel(_)) @@ -109,7 +109,7 @@ object RawValueInliner extends Logging { * Unfold all arguments and make CallModel * @param flatStreamArguments canonicalize and flatten all stream arguments if true */ - def callToModel[S: Mangler: Exports: Arrows]( + def callToModel[S: Mangler: Exports: Arrows: Config]( call: Call, flatStreamArguments: Boolean ): State[S, (CallModel, Option[OpModel.Tree])] = { @@ -122,7 +122,7 @@ object RawValueInliner extends Logging { State.pure(args) } exportTo <- call.exportTo.traverse { - case c@Call.Export(_, _, isExistingStream) if isExistingStream => + case c @ Call.Export(_, _, isExistingStream) if isExistingStream => // process streams, because they can be stored in Exports outside function/closure with different name valueToModel(c.toRaw) case ce => diff --git a/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala b/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala index efaade71..78bba18d 100644 --- a/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala @@ -3,8 +3,8 @@ package aqua.model.inline import aqua.errors.Errors.internalError import aqua.model.* import aqua.model.inline.raw.{CallArrowRawInliner, CallServiceRawInliner} -import aqua.model.inline.state.{Arrows, Exports, Mangler} -import aqua.model.inline.tag.IfTagInliner +import aqua.model.inline.state.* +import aqua.model.inline.tag.* import aqua.raw.ops.* import aqua.raw.value.* import aqua.types.{CanonStreamType, CollectionType, StreamType} @@ -193,35 +193,16 @@ object TagInliner extends Logging { * @tparam S Current state * @return Model (if any), and prefix (if any) */ - def tagToModel[S: Mangler: Arrows: Exports]( + def tagToModel[S: Mangler: Arrows: Exports: Config]( tag: RawTag ): State[S, TagInlined[S]] = tag match { case OnTag(peerId, via, strategy) => - for { - peerIdDe <- valueToModel(peerId) - viaDe <- valueListToModel(via.toList) - viaDeFlattened <- viaDe.traverse { case (vm, tree) => - flat(vm, tree) - } - (pid, pif) = peerIdDe - (viaD, viaF) = viaDeFlattened.unzip - .bimap(Chain.fromSeq, _.flatten) - strat = strategy.map { case OnTag.ReturnStrategy.Relay => - OnModel.ReturnStrategy.Relay - } - toModel = (children: Chain[OpModel.Tree]) => - XorModel.wrap( - OnModel(pid, viaD, strat).wrap( - children - ), - // This will return to previous topology - // and propagate error up - FailModel(ValueModel.error).leaf - ) - } yield TagInlined.Mapping( - toModel = toModel, - prefix = parDesugarPrefix(viaF.prependedAll(pif)) + OnTagInliner(peerId, via, strategy).inlined.map(inlined => + TagInlined.Mapping( + toModel = inlined.toModel, + prefix = inlined.prefix + ) ) case IfTag(valueRaw) => @@ -471,7 +452,7 @@ object TagInliner extends Logging { inlined <- headInlined.build(children) } yield inlined - def handleTree[S: Exports: Mangler: Arrows]( + def handleTree[S: Exports: Mangler: Arrows: Config]( tree: RawTag.Tree ): State[S, OpModel.Tree] = traverseS(tree, tagToModel(_)) diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBinaryOpRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBinaryOpRawInliner.scala index 48c06cad..b52ceb0f 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBinaryOpRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBinaryOpRawInliner.scala @@ -2,32 +2,32 @@ package aqua.model.inline.raw import aqua.errors.Errors.internalError import aqua.model.* -import aqua.model.inline.raw.RawInliner -import aqua.model.inline.TagInliner -import aqua.model.inline.state.{Arrows, Exports, Mangler} -import aqua.raw.value.{AbilityRaw, LiteralRaw, MakeStructRaw} -import cats.data.{NonEmptyList, NonEmptyMap, State} import aqua.model.inline.Inline +import aqua.model.inline.Inline.MergeMode import aqua.model.inline.RawValueInliner.{unfold, valueToModel} -import aqua.types.{ArrowType, ScalarType, Type} +import aqua.model.inline.TagInliner +import aqua.model.inline.raw.RawInliner +import aqua.model.inline.state.* import aqua.raw.value.ApplyBinaryOpRaw import aqua.raw.value.ApplyBinaryOpRaw.Op import aqua.raw.value.ApplyBinaryOpRaw.Op.* -import aqua.model.inline.Inline.MergeMode +import aqua.raw.value.{AbilityRaw, LiteralRaw, MakeStructRaw} +import aqua.types.LiteralType +import aqua.types.{ArrowType, ScalarType, Type} import cats.data.Chain -import cats.syntax.traverse.* -import cats.syntax.monoid.* -import cats.syntax.functor.* -import cats.syntax.flatMap.* -import cats.syntax.apply.* -import cats.syntax.foldable.* +import cats.data.{NonEmptyList, NonEmptyMap, State} import cats.syntax.applicative.* -import aqua.types.LiteralType +import cats.syntax.apply.* +import cats.syntax.flatMap.* +import cats.syntax.foldable.* +import cats.syntax.functor.* +import cats.syntax.monoid.* +import cats.syntax.traverse.* object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: ApplyBinaryOpRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = for { @@ -83,7 +83,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { } } yield result - private def inlineEqOp[S: Mangler: Exports: Arrows]( + private def inlineEqOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, @@ -106,7 +106,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { case _ => fullInlineEqOp(lmodel, rmodel, linline, rinline, op, resType) } - private def fullInlineEqOp[S: Mangler: Exports: Arrows]( + private def fullInlineEqOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, @@ -152,7 +152,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { result(name, resType, predo) } - private def inlineBoolOp[S: Mangler: Exports: Arrows]( + private def inlineBoolOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, @@ -178,7 +178,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { case _ => fullInlineBoolOp(lmodel, rmodel, linline, rinline, op, resType) } - private def fullInlineBoolOp[S: Mangler: Exports: Arrows]( + private def fullInlineBoolOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, @@ -230,7 +230,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { result(name, resType, predo) } - private def inlineCmpOp[S: Mangler: Exports: Arrows]( + private def inlineCmpOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, @@ -276,7 +276,7 @@ object ApplyBinaryOpRawInliner extends RawInliner[ApplyBinaryOpRaw] { result(fn, resType, predo) } - private def inlineMathOp[S: Mangler: Exports: Arrows]( + private def inlineMathOp[S: Mangler: Exports: Arrows: Config]( lmodel: ValueModel, rmodel: ValueModel, linline: Inline, diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyFunctorRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyFunctorRawInliner.scala index eb297e17..d4ad9e1d 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyFunctorRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyFunctorRawInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline.raw import aqua.model.inline.Inline import aqua.model.inline.Inline.MergeMode.* import aqua.model.inline.RawValueInliner.unfold -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.model.{ CallModel, CanonicalizeModel, @@ -24,7 +24,7 @@ import scribe.Logging object ApplyFunctorRawInliner extends Logging { - def apply[S: Mangler: Exports: Arrows]( + def apply[S: Mangler: Exports: Arrows: Config]( value: ValueModel, functor: FunctorRaw ): State[S, (VarModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala index a4dabc1d..144e5ae2 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala @@ -4,10 +4,11 @@ import aqua.errors.Errors.internalError import aqua.model.* import aqua.model.inline.Inline.MergeMode.* import aqua.model.inline.RawValueInliner.unfold -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.model.inline.{Inline, MakeStructRawInliner} import aqua.raw.value.IntoCopyRaw import aqua.types.{StreamMapType, StructType} + import cats.data.{Chain, NonEmptyMap, State} import cats.syntax.foldable.* import cats.syntax.functor.* @@ -40,10 +41,16 @@ object ApplyIntoCopyRawInliner extends Logging { } MakeStructRawInliner - .constructThroughMap(mapName, mapType, CallModel.Export(resultName, resultType), fields, nonCopiedValues) + .constructThroughMap( + mapName, + mapType, + CallModel.Export(resultName, resultType), + fields, + nonCopiedValues + ) } - def apply[S: Mangler: Exports: Arrows]( + def apply[S: Mangler: Exports: Arrows: Config]( value: VarModel, intoCopy: IntoCopyRaw ): State[S, (VarModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyPropertiesRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyPropertiesRawInliner.scala index 7327efc8..5498148f 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyPropertiesRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyPropertiesRawInliner.scala @@ -6,7 +6,7 @@ import aqua.model.ValueModel.Ability import aqua.model.inline.Inline import aqua.model.inline.Inline.MergeMode.* import aqua.model.inline.RawValueInliner.unfold -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.value.* import aqua.types.* @@ -24,7 +24,7 @@ import scribe.Logging object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Logging { // in perspective literals can have properties and functors (like `nil` with length) - def flatLiteralWithProperties[S: Mangler: Exports: Arrows]( + def flatLiteralWithProperties[S: Mangler: Exports: Arrows: Config]( literal: LiteralModel, inl: Inline, properties: Chain[PropertyModel] @@ -45,7 +45,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi } } - private def unfoldAbilityProperty[S: Mangler: Exports: Arrows]( + private def unfoldAbilityProperty[S: Mangler: Exports: Arrows: Config]( varModel: VarModel, abilityType: NamedType, p: PropertyRaw @@ -112,7 +112,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi ) } - private[inline] def unfoldProperty[S: Mangler: Exports: Arrows]( + private[inline] def unfoldProperty[S: Mangler: Exports: Arrows: Config]( varModel: VarModel, p: PropertyRaw ): State[S, (VarModel, Inline)] = @@ -172,7 +172,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi private case class PropertyRawWithModel(raw: PropertyRaw, model: Option[PropertyModel]) // Unfold properties that we can process in parallel - private def optimizeProperties[S: Mangler: Exports: Arrows]( + private def optimizeProperties[S: Mangler: Exports: Arrows: Config]( properties: Chain[PropertyRaw] ): State[S, (Chain[PropertyRawWithModel], Inline)] = { properties.map { @@ -211,7 +211,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi }.sequence.map(_.toList.unzip.bimap(Chain.fromSeq, _.combineAll)) } - private def unfoldProperties[S: Mangler: Exports: Arrows]( + private def unfoldProperties[S: Mangler: Exports: Arrows: Config]( prevInline: Inline, vm: VarModel, properties: Chain[PropertyRaw], @@ -263,7 +263,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi /** * Unfold `stream[idx]` */ - private def unfoldStreamGate[S: Mangler: Exports: Arrows]( + private def unfoldStreamGate[S: Mangler: Exports: Arrows: Config]( streamName: String, streamType: StreamType, idx: ValueRaw @@ -325,7 +325,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi mergeMode = SeqMode ) - private def unfoldRawWithProperties[S: Mangler: Exports: Arrows]( + private def unfoldRawWithProperties[S: Mangler: Exports: Arrows: Config]( raw: ValueRaw, properties: Chain[PropertyRaw], propertiesAllowed: Boolean @@ -389,7 +389,7 @@ object ApplyPropertiesRawInliner extends RawInliner[ApplyPropertyRaw] with Loggi flatten = VarModel(nn, varModel.`type`) } yield flatten -> Inline.tree(FlattenModel(varModel, flatten.name).leaf) - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( apr: ApplyPropertyRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyUnaryOpRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyUnaryOpRawInliner.scala index 8d77845b..2b128c88 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyUnaryOpRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyUnaryOpRawInliner.scala @@ -1,28 +1,28 @@ package aqua.model.inline.raw import aqua.model.* -import aqua.model.inline.raw.RawInliner -import aqua.model.inline.state.{Arrows, Exports, Mangler} -import aqua.raw.value.{AbilityRaw, LiteralRaw, MakeStructRaw} -import cats.data.{NonEmptyList, NonEmptyMap, State} import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.{unfold, valueToModel} -import aqua.types.{ArrowType, ScalarType} +import aqua.model.inline.raw.RawInliner +import aqua.model.inline.state.* import aqua.raw.value.ApplyUnaryOpRaw import aqua.raw.value.ApplyUnaryOpRaw.Op.* +import aqua.raw.value.{AbilityRaw, LiteralRaw, MakeStructRaw} +import aqua.types.{ArrowType, ScalarType} import cats.data.Chain -import cats.syntax.traverse.* -import cats.syntax.monoid.* -import cats.syntax.functor.* -import cats.syntax.flatMap.* -import cats.syntax.apply.* -import cats.syntax.foldable.* +import cats.data.{NonEmptyList, NonEmptyMap, State} import cats.syntax.applicative.* +import cats.syntax.apply.* +import cats.syntax.flatMap.* +import cats.syntax.foldable.* +import cats.syntax.functor.* +import cats.syntax.monoid.* +import cats.syntax.traverse.* object ApplyUnaryOpRawInliner extends RawInliner[ApplyUnaryOpRaw] { - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: ApplyUnaryOpRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = for { @@ -40,7 +40,7 @@ object ApplyUnaryOpRawInliner extends RawInliner[ApplyUnaryOpRaw] { } } yield result - private def fullInline[S: Mangler: Exports: Arrows]( + private def fullInline[S: Mangler: Exports: Arrows: Config]( vm: ValueModel, vinline: Inline, op: ApplyUnaryOpRaw.Op diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala index 3aa8227e..d88e1759 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline.raw import aqua.errors.Errors.internalError import aqua.model.* import aqua.model.inline.RawValueInliner.callToModel -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.model.inline.{ArrowInliner, Inline, RawValueInliner} import aqua.raw.ops.Call import aqua.raw.value.CallArrowRaw @@ -14,7 +14,7 @@ import scribe.Logging object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { - private[inline] def unfold[S: Mangler: Exports: Arrows]( + private[inline] def unfold[S: Mangler: Exports: Arrows: Config]( value: CallArrowRaw, exportTo: List[Call.Export] ): State[S, (List[ValueModel], Inline)] = { @@ -31,7 +31,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { resolveArrow(funcName, call) } - private def resolveFuncArrow[S: Mangler: Exports: Arrows]( + private def resolveFuncArrow[S: Mangler: Exports: Arrows: Config]( fn: FuncArrow, call: Call ): State[S, (List[ValueModel], Inline)] = { @@ -52,7 +52,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { } } - private def resolveArrow[S: Mangler: Exports: Arrows]( + private def resolveArrow[S: Mangler: Exports: Arrows: Config]( funcName: String, call: Call ): State[S, (List[ValueModel], Inline)] = for { @@ -76,7 +76,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { }) } yield result - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: CallArrowRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CallServiceRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CallServiceRawInliner.scala index 9c8e000c..e723a442 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CallServiceRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CallServiceRawInliner.scala @@ -3,22 +3,22 @@ package aqua.model.inline.raw import aqua.model.* import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.{callToModel, valueToModel} -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.ops.Call import aqua.raw.value.CallServiceRaw + import cats.data.{Chain, State} import scribe.Logging object CallServiceRawInliner extends RawInliner[CallServiceRaw] with Logging { - private[inline] def unfold[S: Mangler: Exports: Arrows]( + private[inline] def unfold[S: Mangler: Exports: Arrows: Config]( value: CallServiceRaw, exportTo: List[Call.Export] ): State[S, (List[ValueModel], Inline)] = Exports[S].exports.flatMap { exports => logger.trace(s"${exportTo.mkString(" ")} $value") logger.trace(Console.BLUE + s"call service id ${value.serviceId}" + Console.RESET) - val call = Call(value.arguments, exportTo) for { @@ -40,7 +40,7 @@ object CallServiceRawInliner extends RawInliner[CallServiceRaw] with Logging { } yield values.values.toList -> inline } - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: CallServiceRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala index 3344b380..59a7881c 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CollectionRawInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline.raw import aqua.model.* import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.valueToModel -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.value.CollectionRaw import aqua.types.StreamMapType import aqua.types.{ArrayType, CanonStreamType, OptionType, StreamType} @@ -12,7 +12,7 @@ import cats.data.{Chain, State} object CollectionRawInliner extends RawInliner[CollectionRaw] { - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: CollectionRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala index 6f9deab0..ea8ba244 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/MakeAbilityRawInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline.raw import aqua.model.ValueModel.Ability import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.unfold -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.model.{SeqModel, ValueModel, VarModel} import aqua.raw.value.AbilityRaw import aqua.types.AbilityType @@ -15,7 +15,7 @@ import cats.syntax.functor.* object MakeAbilityRawInliner extends RawInliner[AbilityRaw] { - private def updateFields[S: Mangler: Exports: Arrows]( + private def updateFields[S: Mangler: Exports: Arrows: Config]( name: String, fields: NonEmptyMap[String, (ValueModel, Inline)] ): State[S, Unit] = @@ -27,7 +27,7 @@ object MakeAbilityRawInliner extends RawInliner[AbilityRaw] { Exports[S].resolveAbilityField(name, n, vm) }.as(()) - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: AbilityRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/RawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/RawInliner.scala index aee39da2..ffeb10ad 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/RawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/RawInliner.scala @@ -2,13 +2,14 @@ package aqua.model.inline.raw import aqua.model.ValueModel import aqua.model.inline.Inline -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.value.ValueRaw + import cats.data.State trait RawInliner[T <: ValueRaw] { - def apply[S: Mangler: Exports: Arrows]( + def apply[S: Mangler: Exports: Arrows: Config]( raw: T, propertiesAllowed: Boolean = true ): State[S, (ValueModel, Inline)] diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/StreamGateInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/StreamGateInliner.scala index fac02fd0..b074a9b2 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/StreamGateInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/StreamGateInliner.scala @@ -3,17 +3,17 @@ package aqua.model.inline.raw import aqua.errors.Errors.internalError import aqua.model.* import aqua.model.inline.Inline -import aqua.model.inline.state.{Arrows, Exports, Mangler} import aqua.model.inline.RawValueInliner.unfold +import aqua.model.inline.state.* import aqua.types.{ArrayType, CanonStreamType, ScalarType, StreamType} -import cats.data.State import cats.data.Chain +import cats.data.State +import cats.instances.stream +import cats.syntax.applicative.* import cats.syntax.monoid.* import cats.syntax.option.* -import cats.syntax.applicative.* import scribe.Logging -import cats.instances.stream object StreamGateInliner extends Logging { @@ -88,7 +88,7 @@ object StreamGateInliner extends Logging { ) } - def apply[S: Mangler: Exports: Arrows]( + def apply[S: Mangler: Exports: Arrows: Config]( streamName: String, streamType: StreamType, sizeModel: ValueModel diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/StreamRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/StreamRawInliner.scala index adc7e1be..50fb8470 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/StreamRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/StreamRawInliner.scala @@ -3,7 +3,7 @@ package aqua.model.inline.raw import aqua.model.* import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.valueToModel -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.inline.state.* import aqua.raw.value.StreamRaw import cats.data.{Chain, State} @@ -11,7 +11,7 @@ import cats.syntax.traverse.* object StreamRawInliner extends RawInliner[StreamRaw] { - override def apply[S: Mangler: Exports: Arrows]( + override def apply[S: Mangler: Exports: Arrows: Config]( raw: StreamRaw, propertiesAllowed: Boolean ): State[S, (ValueModel, Inline)] = { diff --git a/model/inline/src/main/scala/aqua/model/inline/state/Config.scala b/model/inline/src/main/scala/aqua/model/inline/state/Config.scala new file mode 100644 index 00000000..7fc5dd23 --- /dev/null +++ b/model/inline/src/main/scala/aqua/model/inline/state/Config.scala @@ -0,0 +1,41 @@ +package aqua.model.inline.state + +import cats.data.{Reader, State} + +/** + * Representation that `S` contains configuration for inlining + */ +trait Config[S] { + self => + + /** + * Flag that disables error propagation mechanics in inlined code + */ + def noErrorPropagation: Reader[S, Boolean] + + final def transform[R](f: R => S): Config[R] = new Config[R] { + + override def noErrorPropagation: Reader[R, Boolean] = + self.noErrorPropagation.local(f) + } +} + +object Config { + case class Values(noErrorPropagation: Boolean = false) + + object Values { + lazy val default: Values = Values() + } + + given Config[Values] = new Config[Values] { + + override def noErrorPropagation: Reader[Values, Boolean] = + Reader(_.noErrorPropagation) + } + + def apply[S: Config]: Config[S] = + implicitly[Config[S]] + + def noErrorPropagation[S: Config]: Reader[S, Boolean] = + Config[S].noErrorPropagation +} diff --git a/model/inline/src/main/scala/aqua/model/inline/state/InliningState.scala b/model/inline/src/main/scala/aqua/model/inline/state/InliningState.scala index e931cd0a..9218c374 100644 --- a/model/inline/src/main/scala/aqua/model/inline/state/InliningState.scala +++ b/model/inline/src/main/scala/aqua/model/inline/state/InliningState.scala @@ -1,11 +1,12 @@ package aqua.model.inline.state import aqua.mangler.ManglerState -import aqua.model.{FuncArrow, ValueModel} import aqua.model.inline.state.{Arrows, Counter, Exports, Mangler} +import aqua.model.{FuncArrow, ValueModel} import aqua.raw.arrow.FuncRaw import aqua.raw.value.{ValueRaw, VarRaw} import aqua.types.ArrowType + import cats.data.{Chain, State} import cats.instances.list.* import cats.syntax.traverse.* @@ -27,7 +28,8 @@ case class InliningState( noNames: ManglerState = ManglerState(), resolvedExports: Map[String, ValueModel] = Map.empty, resolvedArrows: Map[String, FuncArrow] = Map.empty, - instructionCounter: Int = 0 + instructionCounter: Int = 0, + config: Config.Values = Config.Values.default ) object InliningState { @@ -44,4 +46,6 @@ object InliningState { given Exports[InliningState] = Exports.Simple.transformS(_.resolvedExports, (acc, ex) => acc.copy(resolvedExports = ex)) + given Config[InliningState] = + Config[Config.Values].transform(_.config) } diff --git a/model/inline/src/main/scala/aqua/model/inline/tag/IfTagInliner.scala b/model/inline/src/main/scala/aqua/model/inline/tag/IfTagInliner.scala index cedc8202..3e8f5c0b 100644 --- a/model/inline/src/main/scala/aqua/model/inline/tag/IfTagInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/tag/IfTagInliner.scala @@ -1,25 +1,28 @@ package aqua.model.inline.tag -import aqua.raw.value.{ApplyBinaryOpRaw, ValueRaw} -import aqua.raw.value.ApplyBinaryOpRaw.Op as BinOp -import aqua.model.ValueModel +import aqua.helpers.syntax.reader.* import aqua.model.* -import aqua.model.inline.state.{Arrows, Exports, Mangler} +import aqua.model.ValueModel +import aqua.model.inline.Inline.parDesugarPrefixOpt import aqua.model.inline.RawValueInliner.valueToModel import aqua.model.inline.TagInliner.canonicalizeIfStream -import aqua.model.inline.Inline.parDesugarPrefixOpt -import cats.data.{Chain, State} -import cats.syntax.flatMap.* -import cats.syntax.apply.* +import aqua.model.inline.state.* +import aqua.raw.value.ApplyBinaryOpRaw.Op as BinOp +import aqua.raw.value.{ApplyBinaryOpRaw, ValueRaw} + import cats.Eval +import cats.data.Reader +import cats.data.{Chain, State} +import cats.syntax.apply.* +import cats.syntax.flatMap.* final case class IfTagInliner( valueRaw: ValueRaw ) { import IfTagInliner.* - def inlined[S: Mangler: Exports: Arrows]: State[S, IfTagInlined] = - (valueRaw match { + def inlined[S: Mangler: Exports: Arrows: Config]: State[S, IfTagInlined] = for { + cond <- (valueRaw match { // Optimize in case last operation is equality check case ApplyBinaryOpRaw(op @ (BinOp.Eq | BinOp.Neq), left, right, _) => ( @@ -41,12 +44,36 @@ final case class IfTagInliner( (prefix, valueModel, compareModel, shouldMatch) } - }).map { case (prefix, leftValue, rightValue, shouldMatch) => - IfTagInlined( - prefix, - toModel(leftValue, rightValue, shouldMatch) - ) - } + }) + (prefix, leftValue, rightValue, shouldMatch) = cond + noProp <- Config[S].noErrorPropagation.toState + model = if (noProp) toModelNoProp else toModel + } yield IfTagInlined( + prefix, + model(leftValue, rightValue, shouldMatch) + ) + + private def toModelNoProp( + leftValue: ValueModel, + rightValue: ValueModel, + shouldMatch: Boolean + )(children: Chain[OpModel.Tree]): OpModel.Tree = + children + .filterNot(_.head == EmptyModel) + .uncons + .map { case (ifBody, elseBody) => + XorModel.wrap( + MatchMismatchModel( + leftValue, + rightValue, + shouldMatch + ).wrap(ifBody), + SeqModel.wrap( + elseBody + ) + ) + } + .getOrElse(EmptyModel.leaf) private def toModel( leftValue: ValueModel, diff --git a/model/inline/src/main/scala/aqua/model/inline/tag/OnTagInliner.scala b/model/inline/src/main/scala/aqua/model/inline/tag/OnTagInliner.scala new file mode 100644 index 00000000..ec09edae --- /dev/null +++ b/model/inline/src/main/scala/aqua/model/inline/tag/OnTagInliner.scala @@ -0,0 +1,68 @@ +package aqua.model.inline.tag + +import aqua.helpers.syntax.reader.* +import aqua.model.* +import aqua.model.inline.Inline.parDesugarPrefix +import aqua.model.inline.RawValueInliner.{valueListToModel, valueToModel} +import aqua.model.inline.TagInliner.flat +import aqua.model.inline.state.* +import aqua.raw.ops.OnTag +import aqua.raw.value.ValueRaw + +import cats.data.{Chain, State} +import cats.syntax.bifunctor.* +import cats.syntax.traverse.* + +final case class OnTagInliner( + peerId: ValueRaw, + via: Chain[ValueRaw], + strategy: Option[OnTag.ReturnStrategy] +) { + import OnTagInliner.* + + def inlined[S: Mangler: Exports: Arrows: Config]: State[S, OnTagInlined] = + for { + peerIdDe <- valueToModel(peerId) + viaDe <- valueListToModel(via.toList) + viaDeFlattened <- viaDe.traverse(flat.tupled) + (pid, pif) = peerIdDe + (viaD, viaF) = viaDeFlattened.unzip.bimap(Chain.fromSeq, _.flatten) + strat = strategy.map { case OnTag.ReturnStrategy.Relay => + OnModel.ReturnStrategy.Relay + } + noProp <- Config[S].noErrorPropagation.toState + model = if (noProp) toModelNoProp else toModel + } yield OnTagInlined( + prefix = parDesugarPrefix(viaF.prependedAll(pif)), + toModel = model(pid, viaD, strat) + ) + + private def toModelNoProp( + pid: ValueModel, + via: Chain[ValueModel], + strat: Option[OnModel.ReturnStrategy] + )(children: Chain[OpModel.Tree]): OpModel.Tree = + OnModel(pid, via, strat).wrap(children) + + private def toModel( + pid: ValueModel, + via: Chain[ValueModel], + strat: Option[OnModel.ReturnStrategy] + )(children: Chain[OpModel.Tree]): OpModel.Tree = + XorModel.wrap( + OnModel(pid, via, strat).wrap( + children + ), + // This will return to previous topology + // and propagate error up + FailModel(ValueModel.error).leaf + ) +} + +object OnTagInliner { + + final case class OnTagInlined( + prefix: Option[OpModel.Tree], + toModel: Chain[OpModel.Tree] => OpModel.Tree + ) +} diff --git a/model/raw/src/main/scala/aqua/raw/ConstantRaw.scala b/model/raw/src/main/scala/aqua/raw/ConstantRaw.scala index f8481c2c..af4c243d 100644 --- a/model/raw/src/main/scala/aqua/raw/ConstantRaw.scala +++ b/model/raw/src/main/scala/aqua/raw/ConstantRaw.scala @@ -51,7 +51,7 @@ object ConstantRaw { def hostPeerId(relayVarName: Option[String]): ConstantRaw = ConstantRaw( "HOST_PEER_ID", - relayVarName.fold[ValueRaw](ValueRaw.InitPeerId)(r => VarRaw(r, ScalarType.string)), + relayVarName.fold(ValueRaw.InitPeerId)(r => VarRaw(r, ScalarType.string)), false ) diff --git a/model/res/src/main/scala/aqua/res/MakeRes.scala b/model/res/src/main/scala/aqua/res/MakeRes.scala index 55721f6d..59bba966 100644 --- a/model/res/src/main/scala/aqua/res/MakeRes.scala +++ b/model/res/src/main/scala/aqua/res/MakeRes.scala @@ -1,12 +1,13 @@ package aqua.res +import aqua.model.* +import aqua.raw.value.{LiteralRaw, ValueRaw} +import aqua.types.* import aqua.types.{ArrayType, CanonStreamType, StreamType} + import cats.Eval import cats.data.{Chain, NonEmptyList} import cats.free.Cofree -import aqua.raw.value.{LiteralRaw, ValueRaw} -import aqua.model.* -import aqua.types.* /** * Helpers for translating [[OpModel]] to [[ResolvedOp]] @@ -22,8 +23,8 @@ object MakeRes { def hop(onPeer: ValueModel): ResolvedOp.Tree = { // Those names can't be produced from compilation // so they are safe to use - val streamName = "-ephemeral-stream-" - val canonName = "-ephemeral-canon-" + val streamName = "-hop-" + val canonName = "-hopc-" val elementType = BottomType val streamType = StreamType(elementType) val canonType = CanonStreamType(elementType) diff --git a/model/transform/src/main/scala/aqua/model/transform/Transform.scala b/model/transform/src/main/scala/aqua/model/transform/Transform.scala index 760be8cc..875fdfb0 100644 --- a/model/transform/src/main/scala/aqua/model/transform/Transform.scala +++ b/model/transform/src/main/scala/aqua/model/transform/Transform.scala @@ -2,7 +2,7 @@ package aqua.model.transform import aqua.model.* import aqua.model.inline.ArrowInliner -import aqua.model.inline.state.InliningState +import aqua.model.inline.state.{Config, InliningState} import aqua.model.transform.TransformConfig.TracingConfig import aqua.model.transform.funcop.* import aqua.model.transform.pre.* @@ -48,6 +48,7 @@ object Transform extends Logging { private def funcToModelTree( func: FuncArrow, preTransformer: FuncPreTransformer, + conf: TransformConfig, funcArgName: String = "_func" ): Eval[OpModel.Tree] = { @@ -66,7 +67,10 @@ object Transform extends Logging { val call = CallModel(funcArg :: Nil, Nil) // resolves to func - val initState = InliningState(resolvedArrows = Map(funcArgName -> func)) + val initState = InliningState( + resolvedArrows = Map(funcArgName -> func), + config = Config.Values(noErrorPropagation = conf.noXor) + ) // Inlining `funcAround()` ArrowInliner @@ -118,7 +122,7 @@ object Transform extends Logging { for { // Pre transform and inline the function - model <- funcToModelTree(func, preTransformer) + model <- funcToModelTree(func, preTransformer, conf) // Post transform the function. // We should wrap `model` with `onInitPeer` here // so that TagInliner would not wrap it with `xor`. diff --git a/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala b/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala index 313cdc94..09c1b086 100644 --- a/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala +++ b/model/transform/src/main/scala/aqua/model/transform/TransformConfig.scala @@ -20,6 +20,7 @@ import cats.kernel.Monoid * @param relayVarName - name of the relay variable * @param tracing - tracing configuration * @param constants - list of constants + * @param noXor - if true, do not generate generate `xor`s for error propagation */ case class TransformConfig( getDataService: String = "getDataSrv", @@ -30,16 +31,12 @@ case class TransformConfig( noEmptyResponse: Boolean = false, relayVarName: Option[String] = Some("-relay-"), tracing: Option[TransformConfig.TracingConfig] = None, - constants: List[ConstantRaw] = Nil + noXor: Boolean = false ) { - val errorId: ValueRaw = LiteralRaw.quote(errorFuncName) val errorHandlingSrvId: ValueRaw = LiteralRaw.quote(errorHandlingService) val callbackSrvId: ValueRaw = LiteralRaw.quote(callbackService) val dataSrvId: ValueRaw = LiteralRaw.quote(getDataService) - - val constantsList: List[ConstantRaw] = - ConstantRaw.defaultConstants(relayVarName) ::: constants } object TransformConfig { diff --git a/model/transform/src/main/scala/aqua/model/transform/funcop/OpTransform.scala b/model/transform/src/main/scala/aqua/model/transform/funcop/OpTransform.scala index 0e108db5..2c913005 100644 --- a/model/transform/src/main/scala/aqua/model/transform/funcop/OpTransform.scala +++ b/model/transform/src/main/scala/aqua/model/transform/funcop/OpTransform.scala @@ -2,9 +2,9 @@ package aqua.model.transform.funcop import aqua.model.OpModel +import cats.Eval import cats.data.Chain import cats.free.Cofree -import cats.Eval /** * Base type for [[OpModel.Tree]] -> [[OpModel.Tree]] transformation @@ -23,7 +23,7 @@ trait OpTransform { .lift(op, children) .getOrElse( Eval.now( - op.wrap(children.toList: _*) + op.wrap(children.toList*) ) ) ) diff --git a/utils/helpers/src/main/scala/aqua/helpers/syntax/reader.scala b/utils/helpers/src/main/scala/aqua/helpers/syntax/reader.scala new file mode 100644 index 00000000..9fac6b23 --- /dev/null +++ b/utils/helpers/src/main/scala/aqua/helpers/syntax/reader.scala @@ -0,0 +1,10 @@ +package aqua.helpers.syntax + +import cats.data.{Reader, State} + +object reader { + + extension [S, A](r: Reader[S, A]) { + def toState: State[S, A] = State.inspect(r.run) + } +}