From 634b1c17b629b6f899bfe5ff17a9bdc81673acba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 30 Oct 2023 08:46:50 +0000 Subject: [PATCH 1/2] fix(deps): update dependency @fluencelabs/js-client to v0.4.1 (#945) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- integration-tests/package.json | 2 +- pnpm-lock.yaml | 60 +++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/integration-tests/package.json b/integration-tests/package.json index 97d997f5..e198e30c 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -44,7 +44,7 @@ }, "dependencies": { "@fluencelabs/fluence-network-environment": "1.1.2", - "@fluencelabs/js-client": "0.3.0", + "@fluencelabs/js-client": "0.4.1", "deep-equal": "2.2.1", "loglevel": "1.8.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da954b9d..680a0b38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: 1.1.2 version: 1.1.2 '@fluencelabs/js-client': - specifier: 0.3.0 - version: 0.3.0 + specifier: 0.4.1 + version: 0.4.1 deep-equal: specifier: 2.2.1 version: 2.2.1 @@ -520,15 +520,28 @@ packages: resolution: {integrity: sha512-WJ7o51jaBSzUsYENxCEJpv91KiodH1nQ6uKdAn5chWsOQzDu57d3pa6IW1Lu/wh4jtefnNen+jF1esENQCc0BA==} engines: {node: '>=10', pnpm: '>=3'} - /@fluencelabs/js-client@0.3.0: - resolution: {integrity: sha512-mRlEeoDEAsHK4GK3vIlNBkXgfJ01maQ4WVefob4QNEqpshipf6XQpU6R8dpUsjyhx53nus3ui6BSUV6gi5jg8A==} + /@fluencelabs/js-client-isomorphic@0.2.0: + resolution: {integrity: sha512-i2ju1bCrd+vtOX+wsQush8l/TNrk4Zd7zm66Mw7kzQpDzmPyNxXfmFw8DgJz5bxY0DA1ph5+qQm9NuCvy5tafA==} + dependencies: + '@fluencelabs/avm': 0.52.0 + '@fluencelabs/marine-js': 0.7.2 + '@fluencelabs/marine-worker': 0.4.1 + '@fluencelabs/threads': 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@fluencelabs/js-client@0.4.1: + resolution: {integrity: sha512-kHKMprUkk6e8vXm2+bBH/W0zAMc7t9bgBQs0L0NudPm4UXjTyG3kmS6R2vaCRe+IxAcHC/rFubKmBuRuxSj43Q==} engines: {node: '>=10', pnpm: '>=8'} dependencies: '@chainsafe/libp2p-noise': 13.0.0 '@chainsafe/libp2p-yamux': 5.0.0 '@fluencelabs/avm': 0.52.0 '@fluencelabs/interfaces': 0.8.2 - '@fluencelabs/marine-worker': 0.4.0 + '@fluencelabs/js-client-isomorphic': 0.2.0 + '@fluencelabs/marine-worker': 0.4.1 + '@fluencelabs/threads': 2.0.0 '@libp2p/crypto': 2.0.3 '@libp2p/interface': 0.1.2 '@libp2p/peer-id': 3.0.2 @@ -547,7 +560,6 @@ packages: libp2p: 0.46.6 multiformats: 11.0.1 rxjs: 7.5.5 - threads: github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd ts-pattern: 3.3.3 uint8arrays: 4.0.3 uuid: 8.3.2 @@ -566,12 +578,25 @@ packages: default-import: 1.1.5 dev: false - /@fluencelabs/marine-worker@0.4.0: - resolution: {integrity: sha512-nWri+j8Ey4UXoB32NPKsmVYzUKj6mwD7vh/5MjzCxrnVthnWnFdnkETF2BnZwjZWc701xeVhF3L5ZSjiQzKywQ==} + /@fluencelabs/marine-worker@0.4.1: + resolution: {integrity: sha512-BnCOaAnzi3koFFHGy3955uYllI3TmQN++eI/0s5mou4pMZdF2H6qc40mXzgQb8dADpuE9cqRwQ2/0Ecwn5B3dg==} dependencies: '@fluencelabs/marine-js': 0.7.2 + '@fluencelabs/threads': 2.0.0 observable-fns: 0.6.1 - threads: github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd + transitivePeerDependencies: + - supports-color + dev: false + + /@fluencelabs/threads@2.0.0: + resolution: {integrity: sha512-dgYpZg55OcEmop1U3G2bFKEJXg2avjXWYfWsdPlkSbHOHguaRifvr5bgwIYTg1wxoPGcn0jegcjKKwrY0qrV+g==} + dependencies: + callsites: 3.1.0 + debug: 4.3.4 + is-observable: 2.1.0 + observable-fns: 0.6.1 + optionalDependencies: + tiny-worker: 2.3.0 transitivePeerDependencies: - supports-color dev: false @@ -4141,20 +4166,3 @@ packages: /zod@3.22.4: resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false - - github.com/fluencelabs/threads.js/b00a5342380b0278d3ae56dcfb170effb3cad7cd: - resolution: {tarball: https://codeload.github.com/fluencelabs/threads.js/tar.gz/b00a5342380b0278d3ae56dcfb170effb3cad7cd} - name: threads - version: 1.7.0 - prepare: true - requiresBuild: true - dependencies: - callsites: 3.1.0 - debug: 4.3.4 - is-observable: 2.1.0 - observable-fns: 0.6.1 - optionalDependencies: - tiny-worker: 2.3.0 - transitivePeerDependencies: - - supports-color - dev: false From 78ee753c7b3e956faf5c92f4992e51c1af4ac76a Mon Sep 17 00:00:00 2001 From: InversionSpaces Date: Mon, 30 Oct 2023 10:58:51 +0100 Subject: [PATCH 2/2] feat(compiler): Always generate `last` argument of `fold` [LNG-265] (#947) * Always generate last in fold * Fix unit tests * Add methods --- .../src/main/scala/aqua/backend/air/Air.scala | 4 +- .../main/scala/aqua/backend/air/AirGen.scala | 11 +- .../aqua/compiler/AquaCompilerSpec.scala | 54 ++--- .../scala/aqua/model/inline/TagInliner.scala | 8 +- .../model/inline/raw/StreamGateInliner.scala | 2 +- .../aqua/model/inline/ArrowInlinerSpec.scala | 26 ++- .../src/main/scala/aqua/raw/ops/RawTag.scala | 13 +- .../res/src/main/scala/aqua/res/MakeRes.scala | 8 +- .../src/main/scala/aqua/res/ResolvedOp.scala | 18 +- .../src/test/scala/aqua/res/ResBuilder.scala | 2 +- model/src/main/scala/aqua/model/OpModel.scala | 17 +- .../model/transform/pre/ArgsProvider.scala | 12 +- .../model/transform/topology/Topology.scala | 6 +- .../aqua/model/transform/ModelBuilder.scala | 5 +- .../topology/OpModelTreeCursorSpec.scala | 4 +- .../transform/topology/TopologySpec.scala | 211 ++++++++++-------- .../aqua/semantics/expr/func/ForSem.scala | 10 +- .../aqua/semantics/expr/func/ParSeqSem.scala | 18 +- .../scala/aqua/semantics/SemanticsSpec.scala | 2 +- 19 files changed, 254 insertions(+), 177 deletions(-) diff --git a/backend/air/src/main/scala/aqua/backend/air/Air.scala b/backend/air/src/main/scala/aqua/backend/air/Air.scala index 0333711f..56a7bf22 100644 --- a/backend/air/src/main/scala/aqua/backend/air/Air.scala +++ b/backend/air/src/main/scala/aqua/backend/air/Air.scala @@ -93,7 +93,7 @@ object Air { iterable: DataView, label: String, instruction: Air, - lastNextInstruction: Option[Air] + lastNextInstruction: Air ) extends Air(Keyword.Fold) case class Match(left: DataView, right: DataView, instruction: Air) extends Air(Keyword.Match) @@ -137,7 +137,7 @@ object Air { case Air.Next(label) ⇒ s" $label" case Air.New(item, inst) ⇒ s" ${item.show}\n${showNext(inst)}$space" case Air.Fold(iter, label, inst, lastInst) ⇒ - val l = lastInst.map(a => show(depth + 1, a)).getOrElse("") + val l = show(depth + 1, lastInst) s" ${iter.show} $label\n${showNext(inst)}$l$space" case Air.Match(left, right, inst) ⇒ s" ${left.show} ${right.show}\n${showNext(inst)}$space" diff --git a/backend/air/src/main/scala/aqua/backend/air/AirGen.scala b/backend/air/src/main/scala/aqua/backend/air/AirGen.scala index 40b93695..e3351848 100644 --- a/backend/air/src/main/scala/aqua/backend/air/AirGen.scala +++ b/backend/air/src/main/scala/aqua/backend/air/AirGen.scala @@ -94,9 +94,9 @@ object AirGen extends Logging { ) case FoldRes(item, iterable, mode) => - val m = mode.map { - case ForModel.Mode.Null => NullGen - case ForModel.Mode.Never => NeverGen + val m = mode match { + case FoldRes.Mode.Null => NullGen + case FoldRes.Mode.Never => NeverGen } Eval later ForGen(valueToData(iterable), item, opsToSingle(ops), m) case RestrictionRes(item, itemType) => @@ -202,9 +202,8 @@ case class MatchMismatchGen( else Air.Mismatch(left, right, body.generate) } -case class ForGen(iterable: DataView, item: String, body: AirGen, mode: Option[AirGen]) - extends AirGen { - override def generate: Air = Air.Fold(iterable, item, body.generate, mode.map(_.generate)) +case class ForGen(iterable: DataView, item: String, body: AirGen, mode: AirGen) extends AirGen { + override def generate: Air = Air.Fold(iterable, item, body.generate, mode.generate) } case class NewGen(name: String, body: AirGen) extends AirGen { diff --git a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala index fa753df1..0f68680e 100644 --- a/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala +++ b/compiler/src/test/scala/aqua/compiler/AquaCompilerSpec.scala @@ -169,34 +169,36 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside { RestrictionRes(results.name, resultsType).wrap( SeqRes.wrap( ParRes.wrap( - FoldRes(peer.name, peers, ForModel.Mode.Never.some).wrap( - ParRes.wrap( - XorRes.wrap( - // better if first relay will be outside `for` - SeqRes.wrap( - through(ValueModel.fromRaw(relay)), - CallServiceRes( - LiteralModel.fromRaw(LiteralRaw.quote("op")), - "identity", - CallRes( - LiteralModel.fromRaw(LiteralRaw.quote("hahahahah")) :: Nil, - Some(CallModel.Export(retVar.name, retVar.`type`)) - ), - peer - ).leaf, - ApRes(retVar, CallModel.Export(results.name, results.`type`)).leaf, - through(ValueModel.fromRaw(relay)), - through(initPeer) + FoldRes + .lastNever(peer.name, peers) + .wrap( + ParRes.wrap( + XorRes.wrap( + // better if first relay will be outside `for` + SeqRes.wrap( + through(ValueModel.fromRaw(relay)), + CallServiceRes( + LiteralModel.fromRaw(LiteralRaw.quote("op")), + "identity", + CallRes( + LiteralModel.fromRaw(LiteralRaw.quote("hahahahah")) :: Nil, + Some(CallModel.Export(retVar.name, retVar.`type`)) + ), + peer + ).leaf, + ApRes(retVar, CallModel.Export(results.name, results.`type`)).leaf, + through(ValueModel.fromRaw(relay)), + through(initPeer) + ), + SeqRes.wrap( + through(ValueModel.fromRaw(relay)), + through(initPeer), + failErrorRes + ) ), - SeqRes.wrap( - through(ValueModel.fromRaw(relay)), - through(initPeer), - failErrorRes - ) - ), - NextRes(peer.name).leaf + NextRes(peer.name).leaf + ) ) - ) ), join(results, LiteralModel.number(3)), // Compiler optimized addition CanonRes( 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 945c2db8..daa7a0ff 100644 --- a/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/TagInliner.scala @@ -227,12 +227,12 @@ object TagInliner extends Logging { ) } _ <- Exports[S].resolved(item, VarModel(n, elementType)) - m = mode.map { - case ForTag.Mode.Wait => ForModel.Mode.Never - case ForTag.Mode.Pass => ForModel.Mode.Null + modeModel = mode match { + case ForTag.Mode.Blocking => ForModel.Mode.Never + case ForTag.Mode.NonBlocking => ForModel.Mode.Null } } yield TagInlined.Single( - model = ForModel(n, v, m), + model = ForModel(n, v, modeModel), prefix = p ) 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 3c55e15a..fac02fd0 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 @@ -56,7 +56,7 @@ object StreamGateInliner extends Logging { val resultCanon = VarModel(canonName, CanonStreamType(streamType.element)) RestrictionModel(varSTest.name, streamType).wrap( - ForModel(iter.name, VarModel(streamName, streamType), ForModel.Mode.Never.some).wrap( + ForModel(iter.name, VarModel(streamName, streamType), ForModel.Mode.Never).wrap( PushToStreamModel( iter, CallModel.Export(varSTest.name, varSTest.`type`) diff --git a/model/inline/src/test/scala/aqua/model/inline/ArrowInlinerSpec.scala b/model/inline/src/test/scala/aqua/model/inline/ArrowInlinerSpec.scala index 870140f6..5fae85b3 100644 --- a/model/inline/src/test/scala/aqua/model/inline/ArrowInlinerSpec.scala +++ b/model/inline/src/test/scala/aqua/model/inline/ArrowInlinerSpec.scala @@ -2064,8 +2064,12 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside { .leaf ) - val foldOp = - ForTag(iVar.name, array, ForTag.Mode.Wait.some).wrap(inFold, NextTag(iVar.name).leaf) + val foldOp = ForTag + .blocking(iVar.name, array) + .wrap( + inFold, + NextTag(iVar.name).leaf + ) val model: OpModel.Tree = ArrowInliner .callArrow[InliningState]( @@ -2091,14 +2095,16 @@ class ArrowInlinerSpec extends AnyFlatSpec with Matchers with Inside { ._2 model.equalsOrShowDiff( - ForModel(iVar0.name, ValueModel.fromRaw(array), ForModel.Mode.Never.some).wrap( - CallServiceModel( - LiteralModel.fromRaw(serviceId), - fnName, - CallModel(LiteralModel.number(1) :: Nil, Nil) - ).leaf, - NextModel(iVar0.name).leaf - ) + ForModel + .neverMode(iVar0.name, ValueModel.fromRaw(array)) + .wrap( + CallServiceModel( + LiteralModel.fromRaw(serviceId), + fnName, + CallModel(LiteralModel.number(1) :: Nil, Nil) + ).leaf, + NextModel(iVar0.name).leaf + ) ) should be(true) } diff --git a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala index a035ccdc..079a4c9e 100644 --- a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala +++ b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala @@ -168,8 +168,7 @@ case class RestrictionTag(name: String, `type`: DataType) extends SeqGroupTag { copy(name = map.getOrElse(name, name)) } -case class ForTag(item: String, iterable: ValueRaw, mode: Option[ForTag.Mode] = None) - extends SeqGroupTag { +case class ForTag(item: String, iterable: ValueRaw, mode: ForTag.Mode) extends SeqGroupTag { override def restrictsVarNames: Set[String] = Set(item) @@ -185,9 +184,15 @@ case class ForTag(item: String, iterable: ValueRaw, mode: Option[ForTag.Mode] = object ForTag { enum Mode { - case Wait - case Pass + case Blocking + case NonBlocking } + + def blocking(item: String, iterable: ValueRaw): ForTag = + ForTag(item, iterable, Mode.Blocking) + + def nonBlocking(item: String, iterable: ValueRaw): ForTag = + ForTag(item, iterable, Mode.NonBlocking) } case class CallArrowRawTag( diff --git a/model/res/src/main/scala/aqua/res/MakeRes.scala b/model/res/src/main/scala/aqua/res/MakeRes.scala index 4e978cc4..55721f6d 100644 --- a/model/res/src/main/scala/aqua/res/MakeRes.scala +++ b/model/res/src/main/scala/aqua/res/MakeRes.scala @@ -46,7 +46,13 @@ object MakeRes { case SeqModel | _: OnModel | _: ApplyTopologyModel => SeqRes.leaf case MatchMismatchModel(a, b, s) => MatchMismatchRes(a, b, s).leaf - case ForModel(item, iter, mode) if !isNillLiteral(iter) => FoldRes(item, iter, mode).leaf + case ForModel(item, iter, mode) if !isNillLiteral(iter) => + val modeRes = mode match { + case ForModel.Mode.Null => FoldRes.Mode.Null + case ForModel.Mode.Never => FoldRes.Mode.Never + } + + FoldRes(item, iter, modeRes).leaf case RestrictionModel(item, itemType) => RestrictionRes(item, itemType).leaf case DetachModel => ParRes.leaf case ParModel => ParRes.leaf diff --git a/model/res/src/main/scala/aqua/res/ResolvedOp.scala b/model/res/src/main/scala/aqua/res/ResolvedOp.scala index d66632b7..52bbf15d 100644 --- a/model/res/src/main/scala/aqua/res/ResolvedOp.scala +++ b/model/res/src/main/scala/aqua/res/ResolvedOp.scala @@ -32,9 +32,18 @@ case class MatchMismatchRes(left: ValueModel, right: ValueModel, shouldMatch: Bo override def toString: String = s"(${if (shouldMatch) "match" else "mismatch"} $left $right)" } -case class FoldRes(item: String, iterable: ValueModel, mode: Option[ForModel.Mode] = None) - extends ResolvedOp { - override def toString: String = s"(fold $iterable $item ${mode.map(_.toString).getOrElse("")}" +case class FoldRes(item: String, iterable: ValueModel, mode: FoldRes.Mode) extends ResolvedOp { + override def toString: String = s"(fold $iterable $item ${mode.toString.toLowerCase()}" +} + +object FoldRes { + enum Mode { case Null, Never } + + def lastNull(item: String, iterable: ValueModel): FoldRes = + FoldRes(item, iterable, Mode.Null) + + def lastNever(item: String, iterable: ValueModel): FoldRes = + FoldRes(item, iterable, Mode.Never) } case class RestrictionRes(item: String, `type`: DataType) extends ResolvedOp { @@ -50,7 +59,8 @@ case class CallServiceRes( override def toString: String = s"(call $peerId ($serviceId $funcName) $call)" } -case class ApStreamMapRes(key: ValueModel, value: ValueModel, exportTo: CallModel.Export) extends ResolvedOp { +case class ApStreamMapRes(key: ValueModel, value: ValueModel, exportTo: CallModel.Export) + extends ResolvedOp { override def toString: String = s"(ap ($key $value) $exportTo)" } diff --git a/model/res/src/test/scala/aqua/res/ResBuilder.scala b/model/res/src/test/scala/aqua/res/ResBuilder.scala index 6d5a4a9b..0b173345 100644 --- a/model/res/src/test/scala/aqua/res/ResBuilder.scala +++ b/model/res/src/test/scala/aqua/res/ResBuilder.scala @@ -18,7 +18,7 @@ object ResBuilder { val arrayRes = VarModel(stream.name + "_gate", ArrayType(ScalarType.string)) RestrictionRes(testVM.name, testStreamType).wrap( - FoldRes(iter.name, stream, ForModel.Mode.Never.some).wrap( + FoldRes(iter.name, stream, FoldRes.Mode.Never).wrap( ApRes(iter, CallModel.Export(testVM.name, testVM.`type`)).leaf, CanonRes(testVM, peer, CallModel.Export(canon.name, canon.`type`)).leaf, XorRes.wrap( diff --git a/model/src/main/scala/aqua/model/OpModel.scala b/model/src/main/scala/aqua/model/OpModel.scala index 3874ffd8..ab8a3c15 100644 --- a/model/src/main/scala/aqua/model/OpModel.scala +++ b/model/src/main/scala/aqua/model/OpModel.scala @@ -147,11 +147,11 @@ case class MatchMismatchModel(left: ValueModel, right: ValueModel, shouldMatch: case class ForModel( item: String, iterable: ValueModel, - mode: Option[ForModel.Mode] = Some(ForModel.Mode.Null) + mode: ForModel.Mode = ForModel.Mode.Null ) extends SeqGroupModel { override def toString: String = - s"for $item <- $iterable${mode.map(m => " " + m.toString).getOrElse("")}" + s"for $item <- $iterable${mode.toString}" override def restrictsVarNames: Set[String] = Set(item) @@ -165,6 +165,12 @@ object ForModel { case Null case Never } + + def neverMode(item: String, iterable: ValueModel): ForModel = + ForModel(item, iterable, Mode.Never) + + def nullMode(item: String, iterable: ValueModel): ForModel = + ForModel(item, iterable, Mode.Null) } // TODO how is it used? remove, if it's not @@ -175,7 +181,12 @@ case class DeclareStreamModel(value: ValueModel) extends NoExecModel { } // key must be only string or number -case class InsertKeyValueModel(key: ValueModel, value: ValueModel, assignTo: String, assignToType: StreamMapType) extends OpModel { +case class InsertKeyValueModel( + key: ValueModel, + value: ValueModel, + assignTo: String, + assignToType: StreamMapType +) extends OpModel { override def usesVarNames: Set[String] = value.usesVarNames override def exportsVarNames: Set[String] = Set(assignTo) diff --git a/model/transform/src/main/scala/aqua/model/transform/pre/ArgsProvider.scala b/model/transform/src/main/scala/aqua/model/transform/pre/ArgsProvider.scala index 6d378e66..92162a05 100644 --- a/model/transform/src/main/scala/aqua/model/transform/pre/ArgsProvider.scala +++ b/model/transform/src/main/scala/aqua/model/transform/pre/ArgsProvider.scala @@ -35,12 +35,14 @@ case class ArgsFromService(dataServiceId: ValueRaw) extends ArgsProvider { Call(Nil, Call.Export(iter, ArrayType(t.element)) :: Nil) ) .leaf, - ForTag(item, VarRaw(iter, ArrayType(t.element))).wrap( - SeqTag.wrap( - PushToStreamTag(VarRaw(item, t.element), Call.Export(varName, t)).leaf, - NextTag(item).leaf + ForTag + .nonBlocking(item, VarRaw(iter, ArrayType(t.element))) + .wrap( + SeqTag.wrap( + PushToStreamTag(VarRaw(item, t.element), Call.Export(varName, t)).leaf, + NextTag(item).leaf + ) ) - ) ) } diff --git a/model/transform/src/main/scala/aqua/model/transform/topology/Topology.scala b/model/transform/src/main/scala/aqua/model/transform/topology/Topology.scala index 0361b270..aa721e72 100644 --- a/model/transform/src/main/scala/aqua/model/transform/topology/Topology.scala +++ b/model/transform/src/main/scala/aqua/model/transform/topology/Topology.scala @@ -377,7 +377,11 @@ object Topology extends Logging { NextRes(itemName).leaf ) - FoldRes(itemName, v).wrap(if (reversed) steps.reverse else steps) + FoldRes + .lastNull(itemName, v) + .wrap( + if (reversed) steps.reverse else steps + ) case _ => MakeRes.hop(v) } diff --git a/model/transform/src/test/scala/aqua/model/transform/ModelBuilder.scala b/model/transform/src/test/scala/aqua/model/transform/ModelBuilder.scala index 30bbed51..885d49bf 100644 --- a/model/transform/src/test/scala/aqua/model/transform/ModelBuilder.scala +++ b/model/transform/src/test/scala/aqua/model/transform/ModelBuilder.scala @@ -124,7 +124,7 @@ object ModelBuilder { failErrorModel ) - def fold(item: String, iter: ValueRaw, mode: Option[ForModel.Mode], body: OpModel.Tree*) = { + def fold(item: String, iter: ValueRaw, mode: ForModel.Mode, body: OpModel.Tree*) = { val ops = SeqModel.wrap(body: _*) ForModel(item, ValueModel.fromRaw(iter), mode).wrap(ops, NextModel(item).leaf) } @@ -132,7 +132,8 @@ object ModelBuilder { def foldPar(item: String, iter: ValueRaw, body: OpModel.Tree*) = { val ops = SeqModel.wrap(body: _*) DetachModel.wrap( - ForModel(item, ValueModel.fromRaw(iter), ForModel.Mode.Never.some) + ForModel + .neverMode(item, ValueModel.fromRaw(iter)) .wrap(ParModel.wrap(ops, NextModel(item).leaf)) ) } diff --git a/model/transform/src/test/scala/aqua/model/transform/topology/OpModelTreeCursorSpec.scala b/model/transform/src/test/scala/aqua/model/transform/topology/OpModelTreeCursorSpec.scala index a1425652..162bb2a8 100644 --- a/model/transform/src/test/scala/aqua/model/transform/topology/OpModelTreeCursorSpec.scala +++ b/model/transform/src/test/scala/aqua/model/transform/topology/OpModelTreeCursorSpec.scala @@ -1,7 +1,7 @@ package aqua.model.transform.topology import aqua.model.transform.ModelBuilder -import aqua.model.{CallModel, OnModel, SeqModel} +import aqua.model.{CallModel, ForModel, OnModel, SeqModel} import aqua.model.transform.cursor.ChainZipper import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw} import aqua.raw.ops.{Call, FuncOp, OnTag} @@ -137,7 +137,7 @@ class OpModelTreeCursorSpec extends AnyFlatSpec with Matchers { fold( "item", VarRaw("iterable", ArrayType(ScalarType.string)), - None, + ForModel.Mode.Null, OnModel( VarRaw("-in-fold-", ScalarType.string), Chain.one(VarRaw("-fold-relay-", ScalarType.string)) diff --git a/model/transform/src/test/scala/aqua/model/transform/topology/TopologySpec.scala b/model/transform/src/test/scala/aqua/model/transform/topology/TopologySpec.scala index ef6a2ddb..7e2b5b51 100644 --- a/model/transform/src/test/scala/aqua/model/transform/topology/TopologySpec.scala +++ b/model/transform/src/test/scala/aqua/model/transform/topology/TopologySpec.scala @@ -463,7 +463,8 @@ class TopologySpec extends AnyFlatSpec with Matchers { through(relay), callRes(0, otherPeer), ParRes.wrap( - FoldRes("i", valueArray, ForModel.Mode.Never.some) + FoldRes + .lastNever("i", valueArray) .wrap(ParRes.wrap(callRes(2, otherPeer2), NextRes("i").leaf)) ), through(relay), @@ -509,26 +510,28 @@ class TopologySpec extends AnyFlatSpec with Matchers { val proc = Topology.resolve(init).value val foldRes = ParRes.wrap( - FoldRes("i", valueArray, ForModel.Mode.Never.some).wrap( - ParRes.wrap( - // better if first relay will be outside `for` - SeqRes.wrap( - through(relay), - XorRes.wrap( - SeqRes.wrap( - callRes(2, iRelay, Some(CallModel.Export(streamRaw.name, streamRaw.`type`))), - through(relay), - through(initPeer) - ), - SeqRes.wrap( - through(relay), - callRes(4, initPeer) + FoldRes + .lastNever("i", valueArray) + .wrap( + ParRes.wrap( + // better if first relay will be outside `for` + SeqRes.wrap( + through(relay), + XorRes.wrap( + SeqRes.wrap( + callRes(2, iRelay, Some(CallModel.Export(streamRaw.name, streamRaw.`type`))), + through(relay), + through(initPeer) + ), + SeqRes.wrap( + through(relay), + callRes(4, initPeer) + ) ) - ) - ), - NextRes("i").leaf + ), + NextRes("i").leaf + ) ) - ) ) val expected = SeqRes.wrap( Chain( @@ -579,28 +582,30 @@ class TopologySpec extends AnyFlatSpec with Matchers { val proc = Topology.resolve(init).value val fold = ParRes.wrap( - FoldRes("i", valueArray, ForModel.Mode.Never.some).wrap( - ParRes.wrap( - // better if first relay will be outside `for` - SeqRes.wrap( - through(relay), - XorRes.wrap( + FoldRes + .lastNever("i", valueArray) + .wrap( + ParRes.wrap( + // better if first relay will be outside `for` + SeqRes.wrap( + through(relay), XorRes.wrap( + XorRes.wrap( + SeqRes.wrap( + callRes(2, iRelay, Some(CallModel.Export(streamRaw.name, streamRaw.`type`))), + through(relay), + through(initPeer) + ) + ), SeqRes.wrap( - callRes(2, iRelay, Some(CallModel.Export(streamRaw.name, streamRaw.`type`))), through(relay), - through(initPeer) + callRes(4, initPeer) ) - ), - SeqRes.wrap( - through(relay), - callRes(4, initPeer) ) - ) - ), - NextRes("i").leaf + ), + NextRes("i").leaf + ) ) - ) ) val expected = SeqRes.wrap( Chain( @@ -626,7 +631,7 @@ class TopologySpec extends AnyFlatSpec with Matchers { fold( "i", valueArray, - None, + ForModel.Mode.Null, OnModel(otherPeer2, Chain.one(otherRelay2)).wrap( callModel(2) ) @@ -643,10 +648,12 @@ class TopologySpec extends AnyFlatSpec with Matchers { through(relay), callRes(1, otherPeer), through(otherRelay2), - FoldRes("i", valueArray).wrap( - callRes(2, otherPeer2), - NextRes("i").leaf - ), + FoldRes + .lastNull("i", valueArray) + .wrap( + callRes(2, otherPeer2), + NextRes("i").leaf + ), through(otherRelay2), through(relay), callRes(3, initPeer) @@ -662,7 +669,7 @@ class TopologySpec extends AnyFlatSpec with Matchers { fold( "i", valueArray, - None, + ForModel.Mode.Null, OnModel(i, Chain.one(otherRelay)).wrap( callModel(1) ) @@ -674,16 +681,18 @@ class TopologySpec extends AnyFlatSpec with Matchers { val expected = SeqRes.wrap( through(relay), - FoldRes("i", valueArray).wrap( - SeqRes.wrap( - through(otherRelay), - callRes(1, i) - ), - SeqRes.wrap( - through(otherRelay), - NextRes("i").leaf + FoldRes + .lastNull("i", valueArray) + .wrap( + SeqRes.wrap( + through(otherRelay), + callRes(1, i) + ), + SeqRes.wrap( + through(otherRelay), + NextRes("i").leaf + ) ) - ) ) proc.equalsOrShowDiff(expected) should be(true) @@ -766,22 +775,24 @@ class TopologySpec extends AnyFlatSpec with Matchers { val expected = SeqRes.wrap( callRes(1, otherPeer), ParRes.wrap( - FoldRes("i", valueArray, ForModel.Mode.Never.some).wrap( - ParRes.wrap( - SeqRes.wrap( - // TODO: should be outside of fold - through(relayV), - callRes( - 2, - LiteralRaw("i", ScalarType.string), - Some(CallModel.Export("used", StreamType(ScalarType.string))) + FoldRes + .lastNever("i", valueArray) + .wrap( + ParRes.wrap( + SeqRes.wrap( + // TODO: should be outside of fold + through(relayV), + callRes( + 2, + LiteralRaw("i", ScalarType.string), + Some(CallModel.Export("used", StreamType(ScalarType.string))) + ), + // after call `i` topology should send to `otherPeer2` if it's not fire-and-forget – to trigger execution + through(otherPeer2) ), - // after call `i` topology should send to `otherPeer2` if it's not fire-and-forget – to trigger execution - through(otherPeer2) - ), - NextRes("i").leaf + NextRes("i").leaf + ) ) - ) ), callRes(3, otherPeer2, None, VarModel("used", StreamType(ScalarType.string)) :: Nil) ) @@ -843,21 +854,23 @@ class TopologySpec extends AnyFlatSpec with Matchers { val expected = SeqRes.wrap( ParRes.wrap( - FoldRes("i", ValueModel.fromRaw(valueArray), ForModel.Mode.Never.some).wrap( - ParRes.wrap( - SeqRes.wrap( - through(relay), - callRes( - 1, - ValueModel.fromRaw(i), - Some(CallModel.Export(used.name, used.`type`)) + FoldRes + .lastNever("i", ValueModel.fromRaw(valueArray)) + .wrap( + ParRes.wrap( + SeqRes.wrap( + through(relay), + callRes( + 1, + ValueModel.fromRaw(i), + Some(CallModel.Export(used.name, used.`type`)) + ), + through(relay), + through(initPeer) ), - through(relay), - through(initPeer) - ), - NextRes("i").leaf + NextRes("i").leaf + ) ) - ) ) +: joinRes :+ callRes(3, initPeer, None, ValueModel.fromRaw(used) :: Nil) @@ -892,25 +905,27 @@ class TopologySpec extends AnyFlatSpec with Matchers { val proc = Topology.resolve(init).value val foldRes = ParRes.wrap( - FoldRes("i", ValueModel.fromRaw(valueArray), ForModel.Mode.Never.some).wrap( - ParRes.wrap( - SeqRes.wrap( - through(relay), - XorRes.wrap( - SeqRes.wrap( - callRes( - 1, - ValueModel.fromRaw(i), - Some(CallModel.Export(used.name, used.`type`)) - ), - through(relay), - through(initPeer) + FoldRes + .lastNever("i", ValueModel.fromRaw(valueArray)) + .wrap( + ParRes.wrap( + SeqRes.wrap( + through(relay), + XorRes.wrap( + SeqRes.wrap( + callRes( + 1, + ValueModel.fromRaw(i), + Some(CallModel.Export(used.name, used.`type`)) + ), + through(relay), + through(initPeer) + ) ) - ) - ), - NextRes("i").leaf + ), + NextRes("i").leaf + ) ) - ) ) val expected = SeqRes.wrap( foldRes +: @@ -1036,9 +1051,11 @@ class TopologySpec extends AnyFlatSpec with Matchers { CallModel.Export(array.name, array.`type`) ).leaf ), - FoldRes(iterName, array, ForModel.Mode.Null.some).wrap( - NextRes(iterName).leaf - ) + FoldRes + .lastNull(iterName, array) + .wrap( + NextRes(iterName).leaf + ) ) proc.equalsOrShowDiff(expected) shouldEqual true diff --git a/semantics/src/main/scala/aqua/semantics/expr/func/ForSem.scala b/semantics/src/main/scala/aqua/semantics/expr/func/ForSem.scala index 427125ea..2ea4db30 100644 --- a/semantics/src/main/scala/aqua/semantics/expr/func/ForSem.scala +++ b/semantics/src/main/scala/aqua/semantics/expr/func/ForSem.scala @@ -21,6 +21,7 @@ import cats.syntax.apply.* import cats.syntax.flatMap.* import cats.syntax.functor.* import cats.syntax.option.* +import aqua.parser.expr.func.ForExpr.Mode class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal { @@ -44,7 +45,14 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal { case ForExpr.Mode.TryMode => TryTag } - val mode = expr.mode.collect { case ForExpr.Mode.ParMode => ForTag.Mode.Wait } + /** + * `for ... par` => blocking (`never` as `last` in `fold`) + * `for` and `for ... try` => non blocking (`null` as `last` in `fold`) + */ + val mode = expr.mode.fold(ForTag.Mode.NonBlocking) { + case ForExpr.Mode.ParMode => ForTag.Mode.Blocking + case Mode.TryMode => ForTag.Mode.NonBlocking + } val forTag = ForTag(expr.item.value, vm, mode).wrap( innerTag.wrap( diff --git a/semantics/src/main/scala/aqua/semantics/expr/func/ParSeqSem.scala b/semantics/src/main/scala/aqua/semantics/expr/func/ParSeqSem.scala index e17871f2..71a255d1 100644 --- a/semantics/src/main/scala/aqua/semantics/expr/func/ParSeqSem.scala +++ b/semantics/src/main/scala/aqua/semantics/expr/func/ParSeqSem.scala @@ -22,7 +22,7 @@ import cats.syntax.functor.* class ParSeqSem[S[_]](val expr: ParSeqExpr[S]) extends AnyVal { - def program[F[_]: Monad](implicit + def program[F[_]: Monad](using V: ValuesAlgebra[S, F], N: NamesAlgebra[S, F], T: TypesAlgebra[S, F], @@ -63,12 +63,18 @@ class ParSeqSem[S[_]](val expr: ParSeqExpr[S]) extends AnyVal { via = Chain.fromSeq(viaVM), strategy = OnTag.ReturnStrategy.Relay.some ) - tag = ForTag(expr.item.value, vm).wrap( - ParTag.wrap( - onTag.wrap(restricted), - NextTag(expr.item.value).leaf + /** + * `parseq` => blocking (`never` as `last` in `fold`) + * So that peer initiating `parseq` would not continue execution past it + */ + tag = ForTag + .blocking(expr.item.value, vm) + .wrap( + ParTag.wrap( + onTag.wrap(restricted), + NextTag(expr.item.value).leaf + ) ) - ) } yield tag.toFuncOp case (None, _, _) => Raw.error("ParSeqSem: could not resolve `peerId`").pure case (_, None, _) => Raw.error("ParSeqSem: could not resolve `iterable`").pure diff --git a/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala b/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala index 04147a4b..915c9b42 100644 --- a/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala +++ b/semantics/src/test/scala/aqua/semantics/SemanticsSpec.scala @@ -581,7 +581,7 @@ class SemanticsSpec extends AnyFlatSpec with Matchers with Inside { |""".stripMargin insideBody(script) { body => - matchSubtree(body) { case (ForTag("p", _, None), forTag) => + matchSubtree(body) { case (ForTag("p", _, ForTag.Mode.Blocking), forTag) => matchChildren(forTag) { case (ParTag, parTag) => matchChildren(parTag)( { case (OnTag(_, _, strat), _) =>