This commit is contained in:
Dima 2021-07-14 16:09:10 +03:00 committed by GitHub
parent 83d5a7b2a3
commit f455716548
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 149 additions and 210 deletions

View File

@ -1,34 +0,0 @@
service OpH("op"):
puk(s: string) -> string
pek(s: string, -- trgtr
c: string) -> string
pyk: []u32 -> string
pok: []bool -> string
identity: -> ⊥
func a( -- ferkjn
b: string, -- fr
c: string, -- asdf
g: string
) -> string: -- rgtr
try:
f = "world"
OpH "planet"
OpH.pek("TRY THIS", -- gtrg
c)
catch err:
OpH.puk(err.msg)
<- f
-- hello
func z(t: ?string, b: []u32, c: *bool):
OpH.puk(t!)
OpH.pyk(b)
OpH.pok(c)
c <- OpH.identity(true)
c <- OpH.identity("string")
func k():
z(nil, nil, nil)

11
aqua-src/test.aqua Normal file
View File

@ -0,0 +1,11 @@
service OpH("op"):
get_str(s: string) -> string
get_arr() -> []string
identity: -> ⊥
func registerKeyPutValue(node_id: string) -> []string:
nodes <- OpH.get_arr()
for n <- nodes par:
on n:
OpH.get_str(node_id)
<- nodes

View File

@ -1,62 +0,0 @@
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class Test1 extends AnyFlatSpec with Matchers {
"test" should "run" in {
import cats.parse.{Parser0 P0, Parser => P, Numbers}
/*
def getTime(peer: PeerId, reply: i64 -> string) -> string =
on peer:
t <- Peer.timestamp()
reply(t)
Scope(Var("peer"), List(
Fetch(
Var("t"),
AbilityCall(
CustomType("Peer"),
FnName("timestamp"),
Nil
)
)
)),
Unscoped(
FuncCall("reply", List(Var("t"))
)
(seq
(call %init_peer_id% ("load" "peer") [] peer)
(seq
(call peer ("peer" "timestamp") [] t)
(call %init_peer_id% ("callback" "reply") [t]) ;; if used in fetch, then put return value
)
)
;; register peer value
;; register reply callback
code block:
free variables
free functions
new variables
scope?
THEN name, types -- maybe bind free to types
line variants:
func(...)
x <- func(...)
Ability.func(...)
x <- Ability.func(...)
par line
xor line
on peer:
indented lines*
*/
}
}

View File

@ -32,8 +32,8 @@ object PathFinder extends LogSupport {
findPath(
fromOn,
toOn,
Chain.fromOption(from.currentPeerId),
Chain.fromOption(to.currentPeerId)
from.currentPeerId,
to.currentPeerId
)
}
}
@ -49,6 +49,10 @@ object PathFinder extends LogSupport {
case (acc, p) if acc.contains(p) => acc.takeWhile(_ != p) :+ p
case (acc, p) => acc :+ p
}
trace(s"PEER IDS: $optimized")
trace(s"PREFIX: $prefix")
trace(s"SUFFIX: $suffix")
trace(s"OPTIMIZED WITH PREFIX AND SUFFIX: $optimized")
val noPrefix = skipPrefix(optimized, prefix, optimized)
skipSuffix(noPrefix, suffix, noPrefix)
}
@ -56,19 +60,30 @@ object PathFinder extends LogSupport {
def findPath(
fromOn: Chain[OnTag],
toOn: Chain[OnTag],
fromPeer: Chain[ValueModel],
toPeer: Chain[ValueModel]
fromPeer: Option[ValueModel],
toPeer: Option[ValueModel]
): Chain[ValueModel] = {
trace(s"FROM ON: $fromOn")
trace(s"TO ON: $toOn")
val (from, to) = skipCommonPrefix(fromOn, toOn)
val fromFix =
if (from.isEmpty && fromPeer != toPeer) Chain.fromOption(fromOn.lastOption) else from
val toFix = if (to.isEmpty && fromPeer != toPeer) Chain.fromOption(toOn.lastOption) else to
val fromTo = fromFix.reverse.flatMap(_.via.reverse) ++ toFix.flatMap(_.via)
val optimized = optimizePath(fromPeer ++ fromTo ++ toPeer, fromPeer, toPeer)
trace("FIND PATH " + fromFix)
trace(" -> " + toFix)
trace(s"$fromPeer $toPeer")
trace("FIND PATH FROM | " + fromFix)
trace(" TO | " + toFix)
val fromTo = fromFix.reverse.flatMap(_.via.reverse) ++ toFix.flatMap(_.via)
trace(s"FROM TO: $fromTo")
val fromPeerCh = Chain.fromOption(fromPeer)
val toPeerCh = Chain.fromOption(toPeer)
val optimized = optimizePath(fromPeerCh ++ fromTo ++ toPeerCh, fromPeerCh, toPeerCh)
trace(
s"FROM PEER '${fromPeer.map(_.toString).getOrElse("None")}' TO PEER '${toPeer.map(_.toString).getOrElse("None")}'"
)
trace(" Optimized: " + optimized)
optimized
}

View File

@ -127,27 +127,26 @@ case class RawCursor(tree: NonEmptyList[ChainZipper[FuncOp.Tree]])
}
def cata[A](wrap: ChainZipper[Cofree[Chain, A]] => Chain[Cofree[Chain, A]])(
f: RawCursor => OptionT[Eval, ChainZipper[Cofree[Chain, A]]]
folder: RawCursor => OptionT[Eval, ChainZipper[Cofree[Chain, A]]]
): Eval[Chain[Cofree[Chain, A]]] =
f(this).map { case ChainZipper(prev, curr, next) =>
val inner = curr.copy(tail =
Eval
.later(
Chain.fromSeq(
toFirstChild
.map(fc =>
LazyList
.unfold(fc) { _.toNextSibling.map(c => c -> c) }
.prepended(fc)
)
.getOrElse(LazyList.empty)
folder(this).map { case ChainZipper(prev, curr, next) =>
val tail = Eval.later {
Chain.fromSeq(
toFirstChild
.map(folderCursor =>
LazyList
.unfold(folderCursor) { _.toNextSibling.map(cursor => cursor -> cursor) }
.prepended(folderCursor)
)
)
// TODO: this can be parallelized
.flatMap(_.traverse(_.cata(wrap)(f)))
.map(_.flatMap(identity))
.flatMap(addition => curr.tail.map(_ ++ addition))
)
.getOrElse(LazyList.empty)
)
}
// TODO: this can be parallelized
.flatMap(_.traverse(_.cata(wrap)(folder)))
.map(_.flatMap(identity))
.flatMap(addition => curr.tail.map(_ ++ addition))
val inner = curr.copy(tail = tail)
wrap(ChainZipper(prev, inner, next))
}.getOrElse(Chain.empty).memoize

View File

@ -1,6 +1,7 @@
package aqua.model.func.resolved
import aqua.model.func.Call
import aqua.model.topology.Topology.Res
import aqua.model.{LiteralModel, ValueModel}
import cats.Eval
import cats.data.Chain
@ -8,24 +9,24 @@ import cats.free.Cofree
object MakeRes {
val nilTail: Eval[Chain[Cofree[Chain, ResolvedOp]]] = Eval.now(Chain.empty)
type Cof = Cofree[Chain, ResolvedOp]
def leaf(op: ResolvedOp): Cof = Cofree[Chain, ResolvedOp](op, nilTail)
def next(item: String): Cof =
def leaf(op: ResolvedOp): Res = Cofree[Chain, ResolvedOp](op, nilTail)
def next(item: String): Res =
leaf(NextRes(item))
def seq(first: Cof, second: Cof, more: Cof*): Cof =
def seq(first: Res, second: Res, more: Res*): Res =
Cofree[Chain, ResolvedOp](SeqRes, Eval.later(first +: second +: Chain.fromSeq(more)))
def par(first: Cof, second: Cof, more: Cof*): Cof =
def par(first: Res, second: Res, more: Res*): Res =
Cofree[Chain, ResolvedOp](ParRes, Eval.later(first +: second +: Chain.fromSeq(more)))
def xor(first: Cof, second: Cof): Cof =
def xor(first: Res, second: Res): Res =
Cofree[Chain, ResolvedOp](XorRes, Eval.later(Chain(first, second)))
def fold(item: String, iter: ValueModel, body: Cof): Cof =
def fold(item: String, iter: ValueModel, body: Res): Res =
Cofree[Chain, ResolvedOp](FoldRes(item, iter), Eval.now(Chain.one(body)))
def noop(onPeer: ValueModel): Cof =
def noop(onPeer: ValueModel): Res =
leaf(CallServiceRes(LiteralModel.quote("op"), "noop", Call(Nil, None), onPeer))
}

View File

@ -1,26 +1,27 @@
package aqua.model.topology
import aqua.model.{LiteralModel, ValueModel, VarModel}
import aqua.model.func.raw._
import cats.Eval
import cats.data.{Chain, NonEmptyChain, NonEmptyList, OptionT}
import cats.data.Chain.nil
import cats.free.Cofree
import aqua.model.cursor.ChainZipper
import aqua.model.func.raw._
import aqua.model.func.resolved._
import aqua.model.{LiteralModel, ValueModel, VarModel}
import aqua.types.{BoxType, ScalarType}
import wvlet.log.LogSupport
import cats.Eval
import cats.data.Chain.nil
import cats.data.{Chain, NonEmptyChain, NonEmptyList, OptionT}
import cats.free.Cofree
import cats.syntax.traverse._
import wvlet.log.LogSupport
object Topology extends LogSupport {
type Tree = Cofree[Chain, RawTag]
type Res = Cofree[Chain, ResolvedOp]
def resolve(op: Tree): Res =
def resolve(op: Tree): Res = {
val resolved = resolveOnMoves(op).value
Cofree
.cata[Chain, ResolvedOp, Res](resolveOnMoves(op).value) {
.cata[Chain, ResolvedOp, Res](resolved) {
case (SeqRes, children) =>
Eval.later(
Eval.later {
children.uncons
.filter(_._2.isEmpty)
.map(_._1)
@ -33,10 +34,11 @@ object Topology extends LogSupport {
})
)
)
)
}
case (head, children) => Eval.later(Cofree(head, Eval.now(children)))
}
.value
}
def wrap(cz: ChainZipper[Res]): Chain[Res] =
Chain.one(
@ -44,60 +46,64 @@ object Topology extends LogSupport {
else cz.current
)
def resolveOnMoves(op: Tree): Eval[Res] =
RawCursor(NonEmptyList.one(ChainZipper.one(op)))
private def rawToResolved(
currentPeerId: Option[ValueModel]
): PartialFunction[RawTag, ResolvedOp] = {
case SeqTag => SeqRes
case _: OnTag => SeqRes
case MatchMismatchTag(a, b, s) => MatchMismatchRes(a, b, s)
case ForTag(item, iter) => FoldRes(item, iter)
case ParTag | ParTag.Detach => ParRes
case XorTag | XorTag.LeftBiased => XorRes
case NextTag(item) => NextRes(item)
case CallServiceTag(serviceId, funcName, call) =>
CallServiceRes(
serviceId,
funcName,
call,
currentPeerId
.getOrElse(LiteralModel.initPeerId)
)
}
def resolveOnMoves(op: Tree): Eval[Res] = {
val cursor = RawCursor(NonEmptyList.one(ChainZipper.one(op)))
val resolvedCofree = cursor
.cata(wrap) { rc =>
debug(s"<:> $rc")
OptionT[Eval, ChainZipper[Res]](
({
case SeqTag => SeqRes
case _: OnTag => SeqRes
case MatchMismatchTag(a, b, s) => MatchMismatchRes(a, b, s)
case ForTag(item, iter) => FoldRes(item, iter)
case ParTag | ParTag.Detach => ParRes
case XorTag | XorTag.LeftBiased => XorRes
case NextTag(item) => NextRes(item)
case CallServiceTag(serviceId, funcName, call) =>
CallServiceRes(
serviceId,
funcName,
call,
rc.currentPeerId
.getOrElse(LiteralModel.initPeerId)
)
}: PartialFunction[RawTag, ResolvedOp]).lift
.apply(rc.tag)
.map(MakeRes.leaf)
.traverse(c =>
Eval.later {
val cz = ChainZipper(
through(rc.pathFromPrev),
c,
through(rc.pathToNext)
)
if (cz.next.nonEmpty || cz.prev.nonEmpty) {
debug(s"Resolved $rc -> $c")
if (cz.prev.nonEmpty)
trace("From prev: " + cz.prev.map(_.head).toList.mkString(" -> "))
if (cz.next.nonEmpty)
trace("To next: " + cz.next.map(_.head).toList.mkString(" -> "))
} else debug(s"EMPTY $rc -> $c")
cz
}
val resolved = rawToResolved(rc.currentPeerId).lift
.apply(rc.tag)
.map(MakeRes.leaf)
val chainZipperEv = resolved.traverse(cofree =>
Eval.later {
val cz = ChainZipper(
through(rc.pathFromPrev),
cofree,
through(rc.pathToNext)
)
if (cz.next.nonEmpty || cz.prev.nonEmpty) {
debug(s"Resolved $rc -> $cofree")
if (cz.prev.nonEmpty)
trace("From prev: " + cz.prev.map(_.head).toList.mkString(" -> "))
if (cz.next.nonEmpty)
trace("To next: " + cz.next.map(_.head).toList.mkString(" -> "))
} else debug(s"EMPTY $rc -> $cofree")
cz
}
)
OptionT[Eval, ChainZipper[Res]](chainZipperEv)
}
}
.map(NonEmptyChain.fromChain(_).map(_.uncons))
.map {
case None =>
error("Topology emitted nothing")
Cofree(SeqRes, MakeRes.nilTail)
case Some((el, `nil`)) => el
case Some((el, tail)) =>
warn("Topology emitted many nodes, that's unusual")
Cofree(SeqRes, Eval.now(el +: tail))
}
resolvedCofree.map(NonEmptyChain.fromChain(_).map(_.uncons)).map {
case None =>
error("Topology emitted nothing")
Cofree(SeqRes, MakeRes.nilTail)
case Some((el, `nil`)) => el
case Some((el, tail)) =>
warn("Topology emitted many nodes, that's unusual")
Cofree(SeqRes, Eval.now(el +: tail))
}
}
// Walks through peer IDs, doing a noop function on each
// If same IDs are found in a row, does noop only once

View File

@ -1,13 +1,11 @@
package aqua.model.transform
import aqua.model.{ValueModel, VarModel}
import aqua.model.func.{ArgDef, ArgsCall, ArgsDef, Call, FuncCallable}
import aqua.model.func.raw.{FuncOp, FuncOps}
import aqua.model.func._
import aqua.model.{ValueModel, VarModel}
import aqua.types.ArrowType
import cats.Eval
import cats.syntax.apply._
import cats.syntax.functor._
import wvlet.log.Logger
case class ResolveFunc(
transform: FuncOp => FuncOp,
@ -17,9 +15,6 @@ case class ResolveFunc(
arrowCallbackPrefix: String = "init_peer_callable_"
) {
private val logger = Logger.of[ResolveFunc]
import logger._
def returnCallback(retModel: ValueModel): FuncOp =
callback(
respFuncName,

View File

@ -323,7 +323,6 @@ class TopologySpec extends AnyFlatSpec with Matchers {
}
"topology resolver" should "get back to init peer after a long chain" in {
val init = on(
initPeer,
relay :: Nil,

View File

@ -45,6 +45,7 @@ object Token {
val `co`: P[Unit] = P.string("co")
val `:` : P[Unit] = P.char(':')
val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?)
val `anum_*` : P[Unit] = P.charsWhile(anum_).void
val `name`: P[String] = (P.charIn(az) ~ P.charsWhile(anum_).?).string
@ -55,7 +56,7 @@ object Token {
val `--` : P[Unit] = ` `.?.with1 *> P.string("--") <* ` `.?
val ` \n` : P[Unit] =
(` `.?.void *> (`--` *> P.charsWhile(_ != '\n')).?.void).with1 *> `\n`
(` `.?.void *> (`--` *> P.charsWhile0(_ != '\n')).?.void).with1 *> `\n`
val ` \n+` : P[Unit] = P.repAs[Unit, Unit](` \n`.backtrack, 1)(Accumulator0.unitAccumulator0)
val ` : \n+` : P[Unit] = ` `.?.with1 *> `:` *> ` \n+`

View File

@ -4,10 +4,10 @@ import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser
import aqua.parser.lift.LiftParser._
import aqua.types.LiteralType
import cats.{Comonad, Functor}
import cats.parse.{Numbers, Parser => P}
import cats.syntax.functor._
import cats.syntax.comonad._
import cats.syntax.functor._
import cats.{Comonad, Functor}
sealed trait Value[F[_]] extends Token[F]
@ -32,7 +32,7 @@ object Value {
P.oneOf(
("true" :: "false" :: Nil)
.map(t P.string(t).lift.map(fu => Literal(fu.as(t), LiteralType.bool)))
)
) <* P.not(`anum_*`)
def initPeerId[F[_]: LiftParser: Comonad]: P[Literal[F]] =
`%init_peer_id%`.string.lift.map(Literal(_, LiteralType.string))
@ -57,7 +57,7 @@ object Value {
.map(Literal(_, LiteralType.string))
def literal[F[_]: LiftParser: Comonad]: P[Literal[F]] =
P.oneOf(bool :: float.backtrack :: num :: string :: Nil)
P.oneOf(bool.backtrack :: float.backtrack :: num.backtrack :: string :: Nil)
def `value`[F[_]: LiftParser: Comonad]: P[Value[F]] =
P.oneOf(literal.backtrack :: initPeerId.backtrack :: varLambda :: Nil)

View File

@ -2,8 +2,7 @@ package aqua.parser
import aqua.AquaSpec
import aqua.parser.expr.ArrowTypeExpr
import aqua.types.ScalarType.string
import aqua.types.ScalarType.u32
import aqua.types.ScalarType.{string, u32}
import cats.Id
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
@ -21,6 +20,10 @@ class ArrowTypeExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
ArrowTypeExpr[Id]("onIn", toArrowType(List("Custom"), Some("Custom2")))
)
parseArrow("onIn(a: Custom, b: Custom2)") should be(
ArrowTypeExpr[Id]("onIn", toArrowType(List("Custom", "Custom2"), None))
)
parseArrow("onIn: Custom, string, u32, Custom3 -> Custom2") should be(
ArrowTypeExpr[Id](
"onIn",

View File

@ -1,12 +1,12 @@
package aqua.parser.lexer
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
import aqua.types.ScalarType
import aqua.types.ScalarType.u32
import cats.Id
import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import scala.language.implicitConversions
@ -27,6 +27,11 @@ class TypeTokenSpec extends AnyFlatSpec with Matchers with EitherValues {
ArrowTypeToken.`arrowdef`.parseAll("A -> B").right.value should be(
ArrowTypeToken[Id]((), CustomTypeToken[Id]("A") :: Nil, Some(CustomTypeToken[Id]("B")))
)
ArrowTypeToken.`arrowWithNames`.parseAll("(a: A) -> B").right.value should be(
ArrowTypeToken[Id]((), CustomTypeToken[Id]("A") :: Nil, Some(CustomTypeToken[Id]("B")))
)
ArrowTypeToken.`arrowdef`.parseAll("u32 -> Boo").right.value should be(
ArrowTypeToken[Id]((), (u32: BasicTypeToken[Id]) :: Nil, Some(CustomTypeToken[Id]("Boo")))
)