Fix for greedy par (#487)

This commit is contained in:
Dmitry Kurinskiy 2022-04-12 16:27:04 +03:00 committed by GitHub
parent e9a686aac6
commit abd101c4f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 82 additions and 44 deletions

View File

@ -1,12 +1,18 @@
func emptySugar() -> []u32, []string, []string, *string, ?u32, []u32, ?string:
numOp = ?[]
strArr = []
strStream = *[]
strEmptyStream: *string
for i <- ?[]:
strEmptyStream <<- "some"
for i <- *[]:
strEmptyStream <<- "some"
for i <- []:
strEmptyStream <<- "some"
<- numOp, strArr, strStream, strEmptyStream, [], ?[], *[]
service Peer("peer"):
hodes: -> []string
timeout: i32, string -> string
func test_timeout() -> string:
on HOST_PEER_ID:
nodes <- Peer.hodes()
results: *string
for node <- nodes par:
on node:
results <<- node
timeout: *string
join results[999]
par join results[123]
<- timeout!

View File

@ -22,11 +22,11 @@ object Test extends IOApp.Simple {
start <- IO(System.currentTimeMillis())
_ <- AquaPathCompiler
.compileFilesTo[IO](
Path("./aqua-src/call_arrow.aqua"),
Path("./aqua-src/hack.aqua"),
List(Path("./aqua")),
Option(Path("./target")),
TypeScriptBackend,
TransformConfig(wrapWithXor = true)
TransformConfig(wrapWithXor = false)
)
.map {
case Validated.Invalid(errs) =>

View File

@ -1,16 +1,14 @@
package aqua.raw.ops
import aqua.raw.arrow.FuncRaw
import aqua.raw.value.ValueRaw
import aqua.raw.value.CallArrowRaw
import cats.data.{Chain, NonEmptyList}
import cats.free.Cofree
import cats.Show
import cats.Eval
import aqua.raw.Raw
import aqua.raw.arrow.FuncRaw
import aqua.raw.ops.RawTag.Tree
import aqua.raw.value.{CallArrowRaw, ValueRaw}
import aqua.tree.{TreeNode, TreeNodeCompanion}
import aqua.types.{ArrowType, ProductType}
import cats.{Eval, Show}
import cats.data.{Chain, NonEmptyList}
import cats.free.Cofree
sealed trait RawTag extends TreeNode[RawTag] {
@ -46,6 +44,16 @@ sealed trait SeqGroupTag extends GroupTag
object SeqGroupTag extends SeqGroupTag {
override def toString: String = "SeqGroup"
def ungroupSingle(tree: Tree): Tree = tree.head match {
case SeqGroupTag =>
val children = tree.tail.value
children.headOption.fold(tree) {
case h if children.length == 1 => h
case _ => tree
}
case _ => tree
}
}
sealed trait ParGroupTag extends GroupTag

View File

@ -30,15 +30,19 @@ trait RawTagGivens {
given Semigroup[RawTag.Tree] with
override def combine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree =
(x.head, y.head) match {
case (_, XorParTag(xor, par)) => combine(combine(x, xor), par)
case (XorParTag(xor, par), _) => combine(combine(xor, par), y)
case (SeqTag, SeqTag) => y.copy(tail = (x.tail, y.tail).mapN(_ ++ _))
case (_, SeqTag) => y.copy(tail = y.tail.map(_.prepend(x)))
case (SeqTag, _) => x.copy(tail = x.tail.map(_.append(y)))
case _ => SeqTag.wrap(x, y)
override def combine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree = {
// Remove right-asscoc protection of Seq with single child
val flatX = SeqGroupTag.ungroupSingle(x)
val flatY = SeqGroupTag.ungroupSingle(y)
(flatX.head, flatY.head) match {
case (_, XorParTag(xor, par)) => combine(combine(flatX, xor), par)
case (XorParTag(xor, par), _) => combine(combine(xor, par), flatY)
case (SeqTag, SeqTag) => flatY.copy(tail = (flatX.tail, flatY.tail).mapN(_ ++ _))
case (_, SeqTag) => flatY.copy(tail = flatY.tail.map(_.prepend(flatX)))
case (SeqTag, _) => flatX.copy(tail = flatX.tail.map(_.append(flatY)))
case _ => SeqTag.wrap(flatX, flatY)
}
}
// Semigroup for foldRight processing
def rightAssocCombine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree =
@ -51,7 +55,10 @@ trait RawTagGivens {
SeqGroupTag.wrap(y.copy(tail = (x.tail, y.tail).mapN(_ ++ _)))
case (XorTag, ParTag) => XorParTag(x, y).leaf
case (_, ParTag | XorTag) =>
SeqTag.wrap(y.copy(tail = y.tail.map(_.prepend(x))))
// When right-associative tag is combined with left-associative,
// we need result to be left-associative to prevent greedy behavior.
// SeqGroupTag does just this.
SeqGroupTag.wrap(y.copy(tail = y.tail.map(_.prepend(x))))
case (_, XorParTag(xor, par)) =>
rightAssocCombine(rightAssocCombine(x, xor), par)
case _ => x |+| y

View File

@ -18,7 +18,9 @@ case class ParExpr[F[_]](point: Token[F]) extends Expr[F](ParExpr, point) {
}
object ParExpr extends Expr.Prefix() {
override def continueWith: List[Expr.Lexem] = CallArrowExpr :: OnExpr :: ForExpr :: Nil
override def continueWith: List[Expr.Lexem] =
CallArrowExpr :: OnExpr :: ForExpr :: JoinExpr :: Nil
override val p: Parser[Expr[Span.S]] =
`par`.lift.map(Token.lift[Span.S, Unit](_)).map(ParExpr(_))

View File

@ -2,9 +2,10 @@ package aqua.semantics
import aqua.parser.lexer.Token
import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import cats.Monad
import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.flatMap.*
import cats.syntax.functor.*
import scala.language.implicitConversions
@ -28,6 +29,14 @@ sealed abstract class Prog[Alg[_]: Monad, A] extends (Alg[A] => Alg[A]) {
(_: Unit, m: A) => Ab.endScope() as m
)
)
def namesScope[S[_]](token: Token[S])(implicit N: NamesAlgebra[S, Alg]): Prog[Alg, A] =
wrap(
RunAround(
N.beginScope(token),
(_: Unit, m: A) => N.endScope() as m
)
)
}
case class RunAfter[Alg[_]: Monad, A](prog: Alg[A]) extends Prog[Alg, A] {

View File

@ -1,6 +1,6 @@
package aqua.semantics
import aqua.raw.ops.FuncOp
import aqua.raw.ops.{FuncOp, SeqGroupTag}
import aqua.raw.{Raw, RawContext, RawPart}
import aqua.parser.lexer.Token
import aqua.parser.{Ast, Expr}
@ -42,7 +42,10 @@ object Semantics extends Logging {
case (prev, acc) => prev :: acc
}
}
.map(_.reduceLeftOption(_ |+| _).getOrElse(Raw.empty("AST is empty")))
.map(
_.reduceLeftOption(_ |+| _)
.getOrElse(Raw.empty("AST is empty"))
)
)
}

View File

@ -27,7 +27,7 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
): Prog[F, Raw] =
Prog
.around(
N.beginScope(expr.item) >> V.valueToRaw(expr.iterable).flatMap[Option[ValueRaw]] {
V.valueToRaw(expr.iterable).flatMap[Option[ValueRaw]] {
case Some(vm) =>
vm.`type` match {
case t: BoxType =>
@ -71,7 +71,8 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
case _ =>
Raw.error("Wrong body of the For expression")
}
) <* N.endScope()
)
)
.namesScope[S](expr.token)
.abilitiesScope[S](expr.token)
}

View File

@ -46,14 +46,16 @@ class SemanticsSpec extends AnyFlatSpec with Matchers {
CallArrowRawTag.service(LiteralRaw.quote("srv1"), "fn1", emptyCall, "A", arrowType).leaf
val expected =
ParTag.wrap(
OnTag(
LiteralRaw("\"other-peer\"", LiteralType.string),
Chain.empty
).wrap(
SeqGroupTag.wrap(
ParTag.wrap(
OnTag(
LiteralRaw("\"other-peer\"", LiteralType.string),
Chain.empty
).wrap(
serviceCall
),
serviceCall
),
serviceCall
)
)
proc.equalsOrShowDiff(expected) should be(true)