Topology refactoring (#100)

* Topology refactoring

* TransformSpec fixed & improved

* Fixes #98

* Better Par handling

* Introduced Cursor class

* Better exit process for par branch

* Force move to target peer when exiting from a par branch
This commit is contained in:
Dmitry Kurinskiy 2021-04-29 14:16:25 +03:00 committed by GitHub
parent 27f2912c5f
commit 1fc5557ba6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 428 additions and 238 deletions

View File

@ -13,6 +13,8 @@ service Test("test"):
getUserList: -> []User getUserList: -> []User
doSomething: -> bool doSomething: -> bool
check: bool -> () check: bool -> ()
log: string -> ()
getString: string -> string
func initAfterJoin(me: User) -> []User: func initAfterJoin(me: User) -> []User:
allUsers <- Test.getUserList() allUsers <- Test.getUserList()
@ -41,4 +43,19 @@ func checkStreams(ch: []string) -> []bool:
on b: on b:
stream <- Peer.is_connected(b) stream <- Peer.is_connected(b)
handleArr(stream) handleArr(stream)
<- stream <- stream
func test(user: string, relay_id: string) -> string:
on relay_id:
Peer.is_connected("on relay_id")
on user:
Peer.is_connected("on user")
par Peer.is_connected("par on init peer")
<- ""
-- should fail, as using str2 in parallel
func topologyTest(friend: string, friendRelay: string) -> string:
on friend via friendRelay:
str2 <- Test.getString("friends string via")
par Test.log(str2)
<- "finish"

View File

@ -14,15 +14,18 @@ case class TypescriptFile(script: ScriptModel) {
object TypescriptFile { object TypescriptFile {
val Header: String = val Header: String =
"""/** s"""/**
| * | *
| * This file is auto-generated. Do not edit manually: changes may be erased. | * This file is auto-generated. Do not edit manually: changes may be erased.
| * Generated by Aqua compiler: https://github.com/fluencelabs/aqua/. | * Generated by Aqua compiler: https://github.com/fluencelabs/aqua/.
| * If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues | * If you find any bugs, please write an issue on GitHub: https://github.com/fluencelabs/aqua/issues
| * | * Aqua version: ${Option(getClass.getPackage.getImplementationVersion)
| */ .filter(_.nonEmpty)
|import { FluenceClient, PeerIdB58 } from '@fluencelabs/fluence'; .getOrElse("Unknown")}
|import { RequestFlowBuilder } from '@fluencelabs/fluence/dist/api.unstable'; | *
|""".stripMargin | */
|import { FluenceClient, PeerIdB58 } from '@fluencelabs/fluence';
|import { RequestFlowBuilder } from '@fluencelabs/fluence/dist/api.unstable';
|""".stripMargin
} }

View File

@ -1,18 +1,18 @@
val dottyVersion = "2.13.5" val dottyVersion = "2.13.5"
//val dottyVersion = "3.0.0-RC3"
scalaVersion := dottyVersion scalaVersion := dottyVersion
//val dottyVersion = "3.0.0-RC2"
val baseAquaVersion = settingKey[String]("base aqua version") val baseAquaVersion = settingKey[String]("base aqua version")
val catsV = "2.5.0" val catsV = "2.6.0"
val catsParseV = "0.3.2" val catsParseV = "0.3.2"
val monocleV = "3.0.0-M4" val monocleV = "3.0.0-M5"
val scalaTestV = "3.2.7" val scalaTestV = "3.2.7" // TODO update version for scala 3-RC3
val fs2V = "3.0.0" val fs2V = "3.0.2"
val catsEffectV = "3.0.2" val catsEffectV = "3.1.0"
val declineV = "2.0.0-RC1" val declineV = "2.0.0-RC1" // Scala3 issue: https://github.com/bkirwi/decline/issues/260
name := "aqua-hll" name := "aqua-hll"

View File

@ -17,6 +17,7 @@ object Model {
case (l: ScriptModel, r: ScriptModel) => case (l: ScriptModel, r: ScriptModel) =>
ScriptModel.SMMonoid.combine(l, r) ScriptModel.SMMonoid.combine(l, r)
case (l: EmptyModel, r: EmptyModel) => EmptyModel(l.log + " |+| " + r.log)
case (_: EmptyModel, r) => r case (_: EmptyModel, r) => r
case (l, _: EmptyModel) => l case (l, _: EmptyModel) => l
@ -24,6 +25,7 @@ object Model {
ScriptModel.toScriptPart(l).fold(r)(ScriptModel.SMMonoid.combine(_, r)) ScriptModel.toScriptPart(l).fold(r)(ScriptModel.SMMonoid.combine(_, r))
case (l: ScriptModel, r) => case (l: ScriptModel, r) =>
ScriptModel.toScriptPart(r).fold(l)(ScriptModel.SMMonoid.combine(l, _)) ScriptModel.toScriptPart(r).fold(l)(ScriptModel.SMMonoid.combine(l, _))
case (l, r) => case (l, r) =>
ScriptModel ScriptModel
.toScriptPart(l) .toScriptPart(l)
@ -31,8 +33,6 @@ object Model {
ScriptModel.toScriptPart(r).fold(l)(rs => ScriptModel.SMMonoid.combine(ls, rs)) ScriptModel.toScriptPart(r).fold(l)(rs => ScriptModel.SMMonoid.combine(ls, rs))
) )
case (l: EmptyModel, r: EmptyModel) => EmptyModel(l.log + " |+| " + r.log)
} }
} }
} }

View File

@ -1,12 +1,20 @@
package aqua.model package aqua.model
import aqua.types.Type import aqua.types.Type
import cats.Eq
import cats.data.Chain import cats.data.Chain
sealed trait ValueModel { sealed trait ValueModel {
def resolveWith(map: Map[String, ValueModel]): ValueModel = this def resolveWith(map: Map[String, ValueModel]): ValueModel = this
} }
object ValueModel {
implicit object ValueModelEq extends Eq[ValueModel] {
override def eqv(x: ValueModel, y: ValueModel): Boolean = x == y
}
}
case class LiteralModel(value: String) extends ValueModel case class LiteralModel(value: String) extends ValueModel
object LiteralModel { object LiteralModel {

View File

@ -27,15 +27,19 @@ sealed trait OpTag {
} }
} }
sealed trait GroupTag extends OpTag
sealed trait SeqGroupTag extends GroupTag
case object SeqTag extends OpTag case object SeqTag extends SeqGroupTag
case object ParTag extends OpTag case object ParTag extends GroupTag
case object XorTag extends OpTag case object XorTag extends GroupTag
case class XorParTag(xor: FuncOp, par: FuncOp) extends OpTag case class XorParTag(xor: FuncOp, par: FuncOp) extends OpTag
case class OnTag(peerId: ValueModel, via: Chain[ValueModel]) extends OpTag case class OnTag(peerId: ValueModel, via: Chain[ValueModel]) extends SeqGroupTag
case class NextTag(item: String) extends OpTag case class NextTag(item: String) extends OpTag
case class MatchMismatchTag(left: ValueModel, right: ValueModel, shouldMatch: Boolean) extends OpTag
case class ForTag(item: String, iterable: ValueModel) extends OpTag case class MatchMismatchTag(left: ValueModel, right: ValueModel, shouldMatch: Boolean)
extends SeqGroupTag
case class ForTag(item: String, iterable: ValueModel) extends SeqGroupTag
case class CallArrowTag( case class CallArrowTag(
funcName: String, funcName: String,

View File

@ -0,0 +1,51 @@
package aqua.model.topology
import cats.data.Chain
import cats.free.Cofree
case class ChainZipper[T](prev: Chain[T], current: T, next: Chain[T]) {
def chain: Chain[T] = (prev :+ current) ++ next
def moveLeft: Option[ChainZipper[T]] =
prev.initLast.map { case (init, last) =>
ChainZipper(init, last, current +: next)
}
def moveRight: Option[ChainZipper[T]] =
next.uncons.map { case (head, tail) =>
ChainZipper(prev :+ current, head, tail)
}
def replaceInjecting(cz: ChainZipper[T]): ChainZipper[T] =
copy(prev ++ cz.prev, cz.current, cz.next ++ next)
}
object ChainZipper {
def one[T](el: T): ChainZipper[T] = ChainZipper(Chain.empty, el, Chain.empty)
def fromChain[T](chain: Chain[T], prev: Chain[T] = Chain.empty): Chain[ChainZipper[T]] =
chain.uncons.fold(Chain.empty[ChainZipper[T]]) { case (t, next) =>
ChainZipper(prev, t, next) +: fromChain(next, prev :+ t)
}
def fromChainMap[T](chain: Chain[T], prev: Chain[T] = Chain.empty)(
f: ChainZipper[T] => Option[T]
): Chain[T] =
chain.uncons.fold(Chain.empty[T]) { case (t, next) =>
f(ChainZipper(prev, t, next)).fold(fromChainMap(next, prev)(f))(r =>
r +: fromChainMap(next, prev :+ r)(f)
)
}
object Matchers {
object `current` {
def unapply[T](cz: ChainZipper[T]): Option[T] = Some(cz.current)
}
object `head` {
def unapply[F[_], T](cz: ChainZipper[Cofree[F, T]]): Option[T] = Some(cz.current.head)
}
}
}

View File

@ -0,0 +1,81 @@
package aqua.model.topology
import Topology.Tree
import aqua.model.func.body.{OnTag, OpTag, ParTag, SeqTag}
import cats.Eval
import cats.data.Chain
import cats.free.Cofree
case class Cursor(point: ChainZipper[Tree], loc: Location) {
def downLoc(tree: Tree): Location =
loc.down(point.copy(current = tree))
def prevOnTags: Chain[OnTag] =
Chain
.fromSeq(
point.prev.lastOption
.orElse(loc.lastLeftSeq.map(_._1.current))
.toList
.flatMap(Cursor.rightBoundary)
.takeWhile {
case ParTag => false
case _ => true
}
)
.collect { case o: OnTag =>
o
}
def nextOnTags: Chain[OnTag] =
Chain
.fromSeq(
loc.lastRightSeq
.map(_._1.current)
.toList
.flatMap(Cursor.leftBoundary)
.takeWhile {
case ParTag => false
case _ => true
}
)
.collect { case o: OnTag =>
o
}
}
object Cursor {
def rightBoundary(root: Tree): LazyList[OpTag] =
root.head #:: LazyList.unfold(root.tail)(_.value.lastOption.map(lo => lo.head -> lo.tail))
def leftBoundary(root: Tree): LazyList[OpTag] =
root.head #:: LazyList.unfold(root.tail)(_.value.headOption.map(lo => lo.head -> lo.tail))
def transform(root: Tree)(f: Cursor => List[Tree]): Option[Tree] = {
def step(cursor: Cursor): Option[Tree] =
f(cursor) match {
case Nil => None
case h :: Nil =>
val np = cursor.downLoc(h)
Some(h.copy(tail = h.tail.map(ChainZipper.fromChainMap(_)(cz => step(Cursor(cz, np))))))
case hs =>
ChainZipper
.fromChain(Chain.fromSeq(hs))
.map(cursor.point.replaceInjecting)
.map { cfh =>
val np = cursor.loc.down(cfh)
cfh.current.copy(tail =
cfh.current.tail.map(ChainZipper.fromChainMap(_)(cz => step(Cursor(cz, np))))
)
}
.uncons
.map {
case (h, t) if t.isEmpty => h
case (h, t) => Cofree(SeqTag, Eval.later(h +: t))
}
}
step(Cursor(ChainZipper.one(root), Location()))
}
}

View File

@ -0,0 +1,63 @@
package aqua.model.topology
import aqua.model.ValueModel
import aqua.model.func.body.{OnTag, SeqGroupTag}
import cats.data.Chain
import cats.free.Cofree
case class Location(path: List[ChainZipper[Topology.Tree]] = Nil) {
def down(h: ChainZipper[Topology.Tree]): Location = copy(h :: path)
def lastOn: Option[OnTag] = path.map(_.current.head).collectFirst { case o: OnTag =>
o
}
def pathOn: List[OnTag] = path.map(_.current.head).collect { case o: OnTag =>
o
}
def pathViaChain: Chain[ValueModel] = Chain.fromSeq(
path
.map(_.current.head)
.collectFirst { case t: OnTag =>
t.via.toList
}
.toList
.flatten
)
def lastLeftSeq: Option[(ChainZipper[Topology.Tree], Location)] =
path match {
case (cz @ ChainZipper(prev, Cofree(_: SeqGroupTag, _), _)) :: tail if prev.nonEmpty =>
cz.moveLeft.map(_ -> Location(tail))
case _ :: tail => Location(tail).lastLeftSeq
case Nil => None
}
def lastRightSeq: Option[(ChainZipper[Topology.Tree], Location)] =
path match {
case (cz @ ChainZipper(_, Cofree(_: SeqGroupTag, _), next)) :: tail if next.nonEmpty =>
cz.moveRight.map(_ -> Location(tail))
case _ :: tail => Location(tail).lastRightSeq
case Nil => None
}
path.collectFirst {
case ChainZipper(prev, Cofree(_: SeqGroupTag, _), _) if prev.nonEmpty => prev.lastOption
}.flatten
}
object Location {
object Matchers {
object /: {
def unapply(loc: Location): Option[(ChainZipper[Topology.Tree], Location)] =
loc.path match {
case h :: tail => Some(h -> Location(tail))
case _ => None
}
}
}
}

View File

@ -0,0 +1,96 @@
package aqua.model.topology
import aqua.model.ValueModel
import aqua.model.func.body._
import cats.Eval
import cats.data.Chain
import cats.free.Cofree
import ChainZipper.Matchers._
import Location.Matchers._
object Topology {
type Tree = Cofree[Chain, OpTag]
// Walks through peer IDs, doing a noop function on each
// If same IDs are found in a row, does noop only once
// if there's a chain like a -> b -> c -> ... -> b -> g, remove everything between b and b
def through(peerIds: Chain[ValueModel]): Chain[Tree] =
peerIds
.foldLeft(Chain.empty[ValueModel]) {
case (acc, p) if acc.lastOption.contains(p) => acc
case (acc, p) if acc.contains(p) => acc.takeWhile(_ != p) :+ p
case (acc, p) => acc :+ p
}
.map(FuncOps.noop)
.map(_.tree)
def mapTag(tag: OpTag, loc: Location): OpTag = tag match {
case c: CallServiceTag if c.peerId.isEmpty =>
c.copy(peerId = loc.lastOn.map(_.peerId))
case t => t
}
def resolve(op: Tree): Tree =
Cofree
.cata[Chain, OpTag, Tree](resolveOnMoves(op)) {
case (SeqTag | _: OnTag, children) =>
Eval.later(
Cofree(
SeqTag,
Eval.now(children.flatMap {
case Cofree(SeqTag, ch) => ch.value
case cf => Chain.one(cf)
})
)
)
case (head, children) => Eval.later(Cofree(head, Eval.now(children)))
}
.value
def resolveOnMoves(op: Tree): Tree =
Cursor
.transform(op) {
case c @ Cursor(
cz @ `current`(cf),
loc @ `head`(parent: GroupTag) /: _
) =>
val cfu = cf.copy(mapTag(cf.head, loc))
val getThere = (cfu.head, loc.pathOn) match {
case (OnTag(pid, _), h :: _) if h.peerId == pid => Chain.empty[ValueModel]
case (OnTag(_, via), h :: _) =>
h.via.reverse ++ via
case (_, _) => Chain.empty[ValueModel]
}
val prevOn = c.prevOnTags
val prevPath = prevOn.map { case OnTag(_, v) =>
v.reverse
}
.flatMap(identity)
val nextOn = parent match {
case ParTag | XorTag => c.nextOnTags
case _ => Chain.empty[OnTag]
}
val nextPath = (if (nextOn.nonEmpty) getThere.reverse else Chain.empty) ++ nextOn.map {
case OnTag(_, v) =>
v.reverse
}
.flatMap(identity) ++ Chain.fromOption(
// Dirty fix for join behaviour
nextOn.lastOption.filter(_ => parent == ParTag).map(_.peerId)
)
if (prevOn.isEmpty && getThere.isEmpty) cfu :: Nil
else
(through(prevPath ++ loc.pathViaChain ++ getThere)
.append(cfu) ++ through(nextPath)).toList
case Cursor(ChainZipper(_, cf, _), loc) =>
cf.copy(mapTag(cf.head, loc)) :: Nil
}
.getOrElse(op)
}

View File

@ -1,106 +0,0 @@
package aqua.model.transform
import aqua.model.ValueModel
import aqua.model.func.body.{CallServiceTag, FuncOps, OnTag, OpTag, ParTag, SeqTag}
import cats.Eval
import cats.data.Chain
import cats.free.Cofree
object Topology {
type Tree = Cofree[Chain, OpTag]
def rightBoundary(root: Tree): List[OpTag] =
root.head :: root.tailForced.lastOption.fold(List.empty[OpTag])(rightBoundary)
// Walks through peer IDs, doing a noop function on each
// If same IDs are found in a row, does noop only once
// TODO: if there's a chain like a -> b -> c -> ... -> b -> g, remove everything between b and b
def through(peerIds: Chain[ValueModel]): Chain[Tree] =
peerIds
.foldLeft(Chain.empty[ValueModel]) {
case (acc, p) if acc.lastOption.contains(p) => acc
case (acc, p) => acc :+ p
}
.map(FuncOps.noop)
.map(_.tree)
// TODO: after topology is resolved, OnTag should be eliminated
def resolve(op: Tree): Tree =
transformWithPath(op) {
case (path, c: CallServiceTag, children) if c.peerId.isEmpty =>
Cofree[Chain, OpTag](
c.copy(peerId = path.collectFirst { case OnTag(peerId, _) =>
peerId
}),
children
)
case (path, tag @ OnTag(pid, via), children) =>
// Drop seq/par/xor from path
val pathOn = path.collect { case ot: OnTag =>
ot
}
pathOn match {
// If we are on the right node, do nothing
case Nil =>
Cofree[Chain, OpTag](tag, children)
case h :: _ if h.peerId == pid =>
Cofree[Chain, OpTag](tag, children)
case h :: _ =>
Cofree[Chain, OpTag](
tag,
// TODO: merge children, if possible
children.map(through(h.via.reverse ++ via) ++ _)
)
}
case (path, SeqTag, children) =>
// TODO if we have OnTag, and then something else, need to get back
// AND keep in mind that we will handle all the children with OnTag processor!
val pathViaChain = Chain.fromSeq(path.collectFirst { case t: OnTag =>
t.via.toList
}.toList.flatten)
def modifyChildrenList(list: List[Tree], prev: Option[Tree]): Chain[Tree] = list match {
case Nil => Chain.empty
case op :: tail =>
// TODO further improve
val prevPath = Chain
.fromSeq(prev.toList.flatMap(rightBoundary).takeWhile {
case ParTag => false
case _ => true
})
.collect { case OnTag(_, v) =>
v.reverse
}
if (prevPath.isEmpty) op +: modifyChildrenList(tail, Some(op))
else
through(prevPath.flatMap(identity) ++ pathViaChain).append(op) ++ modifyChildrenList(
tail,
Some(op)
)
case o :: ops => o +: modifyChildrenList(ops, Some(o))
}
Cofree[Chain, OpTag](
SeqTag,
children.map(_.toList).map(modifyChildrenList(_, None))
)
case (_, t, children) =>
Cofree[Chain, OpTag](t, children)
}
def transformWithPath(cf: Tree, path: List[OpTag] = Nil)(
f: (List[OpTag], OpTag, Eval[Chain[Tree]]) => Tree
): Tree = {
val newCf = f(path, cf.head, cf.tail)
Cofree[Chain, OpTag](
newCf.head,
newCf.tail.map(_.map(transformWithPath(_, newCf.head :: path)(f)))
)
}
}

View File

@ -3,6 +3,7 @@ package aqua.model.transform
import aqua.model.func.body._ import aqua.model.func.body._
import aqua.model.func.FuncCallable import aqua.model.func.FuncCallable
import aqua.model.VarModel import aqua.model.VarModel
import aqua.model.topology.Topology
import aqua.types.ScalarType import aqua.types.ScalarType
import cats.data.Chain import cats.data.Chain
import cats.free.Cofree import cats.free.Cofree

View File

@ -0,0 +1,23 @@
package aqua.model.topology
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import Location.Matchers._
import ChainZipper.Matchers._
import aqua.model.func.body.SeqTag
import cats.Eval
import cats.data.Chain
import cats.free.Cofree
class LocationSpec extends AnyFlatSpec with Matchers {
"matchers" should "unapply correctly" in {
val loc =
Location(ChainZipper.one(Cofree(SeqTag, Eval.later(Chain.empty[Topology.Tree]))) :: Nil)
Option(loc).collect { case `head`(SeqTag) /: _ =>
true
} should be('defined)
}
}

View File

@ -1,4 +1,4 @@
package aqua.model.transform package aqua.model.topology
import aqua.model.Node import aqua.model.Node
import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.flatspec.AnyFlatSpec
@ -20,14 +20,11 @@ class TopologySpec extends AnyFlatSpec with Matchers {
val proc: Node = Topology.resolve(init) val proc: Node = Topology.resolve(init)
val expected = on( val expected =
initPeer,
relay :: Nil,
seq( seq(
call(1, initPeer), call(1, initPeer),
call(2, initPeer) call(2, initPeer)
) )
)
proc should be(expected) proc should be(expected)
@ -50,19 +47,8 @@ class TopologySpec extends AnyFlatSpec with Matchers {
val proc: Node = Topology.resolve(init) val proc: Node = Topology.resolve(init)
val expected = on( val expected =
initPeer, seq(through(relay), call(1, otherPeer), call(2, otherPeer))
relay :: Nil,
on(
otherPeer,
Nil,
through(relay),
seq(
call(1, otherPeer),
call(2, otherPeer)
)
)
)
proc should be(expected) proc should be(expected)
} }
@ -84,20 +70,13 @@ class TopologySpec extends AnyFlatSpec with Matchers {
val proc: Node = Topology.resolve(init) val proc: Node = Topology.resolve(init)
val expected = on( val expected =
initPeer, seq(
relay :: Nil,
on(
otherPeer,
otherRelay :: Nil,
through(relay), through(relay),
through(otherRelay), through(otherRelay),
seq( call(1, otherPeer),
call(1, otherPeer), call(2, otherPeer)
call(2, otherPeer)
)
) )
)
proc should be(expected) proc should be(expected)
} }
@ -119,22 +98,15 @@ class TopologySpec extends AnyFlatSpec with Matchers {
val proc: Node = Topology.resolve(init) val proc: Node = Topology.resolve(init)
val expected = on( val expected =
initPeer,
relay :: Nil,
seq( seq(
on( through(relay),
otherPeer, through(otherRelay),
otherRelay :: Nil, call(1, otherPeer),
through(relay),
through(otherRelay),
call(1, otherPeer)
),
through(otherRelay), through(otherRelay),
through(relay), through(relay),
call(2, initPeer) call(2, initPeer)
) )
)
// println(Console.BLUE + init) // println(Console.BLUE + init)
// println(Console.YELLOW + proc) // println(Console.YELLOW + proc)
@ -175,38 +147,25 @@ class TopologySpec extends AnyFlatSpec with Matchers {
val proc: Node = Topology.resolve(init) val proc: Node = Topology.resolve(init)
val expected = on( val expected =
initPeer,
relay :: Nil,
seq( seq(
on( through(relay),
through(otherRelay),
call(0, otherPeer),
through(otherRelay),
call(1, otherPeer2),
_match(
otherPeer, otherPeer,
otherRelay :: Nil, otherRelay,
through(relay), seq(
through(otherRelay),
call(0, otherPeer),
on(
otherPeer2,
otherRelay :: Nil,
through(otherRelay), through(otherRelay),
call(1, otherPeer2), call(2, otherPeer)
_match(
otherPeer,
otherRelay,
on(
otherPeer,
otherRelay :: Nil,
through(otherRelay),
call(2, otherPeer)
)
)
) )
), ),
through(otherRelay), through(otherRelay),
through(relay), through(relay),
call(3, initPeer) call(3, initPeer)
) )
)
// println(Console.BLUE + init) // println(Console.BLUE + init)
// println(Console.YELLOW + proc) // println(Console.YELLOW + proc)

View File

@ -32,17 +32,17 @@ class TransformSpec extends AnyFlatSpec with Matchers {
val expectedFC = val expectedFC =
xor( xor(
on( seq(
initPeer, dataCall(bc, "relay", initPeer),
relayV :: Nil, through(relayV),
seq( call(1, otherPeer),
dataCall(bc, "relay", initPeer), through(relayV),
on(otherPeer, Nil, through(relayV), call(1, otherPeer)), respCall(bc, ret, initPeer)
through(relayV),
on(initPeer, relayV :: Nil, respCall(bc, ret, initPeer))
)
), ),
on(initPeer, relayV :: Nil, xorErrorCall(bc, initPeer)) seq(
through(relayV),
xorErrorCall(bc, initPeer)
)
) )
procFC.equalsOrPrintDiff(expectedFC) should be(true) procFC.equalsOrPrintDiff(expectedFC) should be(true)
@ -70,20 +70,18 @@ class TransformSpec extends AnyFlatSpec with Matchers {
val expectedFC = val expectedFC =
xor( xor(
on( seq(
initPeer, dataCall(bc, "relay", initPeer),
relayV :: Nil, call(0, initPeer),
seq( through(relayV),
dataCall(bc, "relay", initPeer), call(1, otherPeer),
seq( through(relayV),
call(0, initPeer), respCall(bc, ret, initPeer)
on(otherPeer, Nil, through(relayV), call(1, otherPeer))
),
through(relayV),
on(initPeer, relayV :: Nil, respCall(bc, ret, initPeer))
)
), ),
on(initPeer, relayV :: Nil, xorErrorCall(bc, initPeer)) seq(
through(relayV),
xorErrorCall(bc, initPeer)
)
) )
procFC.equalsOrPrintDiff(expectedFC) should be(true) procFC.equalsOrPrintDiff(expectedFC) should be(true)
@ -137,25 +135,17 @@ class TransformSpec extends AnyFlatSpec with Matchers {
val res = Transform.forClient(f2, bc): Node val res = Transform.forClient(f2, bc): Node
res.equalsOrPrintDiff( res.equalsOrPrintDiff(
on( seq(
initPeer, dataCall(bc, "relay", initPeer),
relayV :: Nil, Node(
seq( CallServiceTag(
dataCall(bc, "relay", initPeer), LiteralModel("\"srv1\""),
Node( "foo",
CallServiceTag( Call(Nil, Some(Call.Export("v", ScalarType.string))),
LiteralModel("\"srv1\""), Some(initPeer)
"foo",
Call(Nil, Some(Call.Export("v", ScalarType.string))),
Some(initPeer)
)
),
on(
initPeer,
relayV :: Nil,
respCall(bc, VarModel("v", ScalarType.string), initPeer)
) )
) ),
respCall(bc, VarModel("v", ScalarType.string), initPeer)
) )
) should be(true) ) should be(true)
} }

View File

@ -1 +1 @@
sbt.version=1.5.0 sbt.version=1.5.1