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: service Peer("peer"):
numOp = ?[] hodes: -> []string
strArr = [] timeout: i32, string -> string
strStream = *[]
strEmptyStream: *string func test_timeout() -> string:
for i <- ?[]: on HOST_PEER_ID:
strEmptyStream <<- "some" nodes <- Peer.hodes()
for i <- *[]: results: *string
strEmptyStream <<- "some"
for i <- []: for node <- nodes par:
strEmptyStream <<- "some" on node:
<- numOp, strArr, strStream, strEmptyStream, [], ?[], *[] 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()) start <- IO(System.currentTimeMillis())
_ <- AquaPathCompiler _ <- AquaPathCompiler
.compileFilesTo[IO]( .compileFilesTo[IO](
Path("./aqua-src/call_arrow.aqua"), Path("./aqua-src/hack.aqua"),
List(Path("./aqua")), List(Path("./aqua")),
Option(Path("./target")), Option(Path("./target")),
TypeScriptBackend, TypeScriptBackend,
TransformConfig(wrapWithXor = true) TransformConfig(wrapWithXor = false)
) )
.map { .map {
case Validated.Invalid(errs) => case Validated.Invalid(errs) =>

View File

@ -1,16 +1,14 @@
package aqua.raw.ops 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.Raw
import aqua.raw.arrow.FuncRaw
import aqua.raw.ops.RawTag.Tree import aqua.raw.ops.RawTag.Tree
import aqua.raw.value.{CallArrowRaw, ValueRaw}
import aqua.tree.{TreeNode, TreeNodeCompanion} import aqua.tree.{TreeNode, TreeNodeCompanion}
import aqua.types.{ArrowType, ProductType} import aqua.types.{ArrowType, ProductType}
import cats.{Eval, Show}
import cats.data.{Chain, NonEmptyList}
import cats.free.Cofree
sealed trait RawTag extends TreeNode[RawTag] { sealed trait RawTag extends TreeNode[RawTag] {
@ -46,6 +44,16 @@ sealed trait SeqGroupTag extends GroupTag
object SeqGroupTag extends SeqGroupTag { object SeqGroupTag extends SeqGroupTag {
override def toString: String = "SeqGroup" 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 sealed trait ParGroupTag extends GroupTag

View File

@ -30,15 +30,19 @@ trait RawTagGivens {
given Semigroup[RawTag.Tree] with given Semigroup[RawTag.Tree] with
override def combine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree = override def combine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree = {
(x.head, y.head) match { // Remove right-asscoc protection of Seq with single child
case (_, XorParTag(xor, par)) => combine(combine(x, xor), par) val flatX = SeqGroupTag.ungroupSingle(x)
case (XorParTag(xor, par), _) => combine(combine(xor, par), y) val flatY = SeqGroupTag.ungroupSingle(y)
case (SeqTag, SeqTag) => y.copy(tail = (x.tail, y.tail).mapN(_ ++ _)) (flatX.head, flatY.head) match {
case (_, SeqTag) => y.copy(tail = y.tail.map(_.prepend(x))) case (_, XorParTag(xor, par)) => combine(combine(flatX, xor), par)
case (SeqTag, _) => x.copy(tail = x.tail.map(_.append(y))) case (XorParTag(xor, par), _) => combine(combine(xor, par), flatY)
case _ => SeqTag.wrap(x, y) 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 // Semigroup for foldRight processing
def rightAssocCombine(x: RawTag.Tree, y: RawTag.Tree): RawTag.Tree = 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(_ ++ _))) SeqGroupTag.wrap(y.copy(tail = (x.tail, y.tail).mapN(_ ++ _)))
case (XorTag, ParTag) => XorParTag(x, y).leaf case (XorTag, ParTag) => XorParTag(x, y).leaf
case (_, ParTag | XorTag) => 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)) => case (_, XorParTag(xor, par)) =>
rightAssocCombine(rightAssocCombine(x, xor), par) rightAssocCombine(rightAssocCombine(x, xor), par)
case _ => x |+| y 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() { 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]] = override val p: Parser[Expr[Span.S]] =
`par`.lift.map(Token.lift[Span.S, Unit](_)).map(ParExpr(_)) `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.parser.lexer.Token
import aqua.semantics.rules.abilities.AbilitiesAlgebra import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra
import cats.Monad import cats.Monad
import cats.syntax.flatMap._ import cats.syntax.flatMap.*
import cats.syntax.functor._ import cats.syntax.functor.*
import scala.language.implicitConversions 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 (_: 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] { case class RunAfter[Alg[_]: Monad, A](prog: Alg[A]) extends Prog[Alg, A] {

View File

@ -1,6 +1,6 @@
package aqua.semantics package aqua.semantics
import aqua.raw.ops.FuncOp import aqua.raw.ops.{FuncOp, SeqGroupTag}
import aqua.raw.{Raw, RawContext, RawPart} import aqua.raw.{Raw, RawContext, RawPart}
import aqua.parser.lexer.Token import aqua.parser.lexer.Token
import aqua.parser.{Ast, Expr} import aqua.parser.{Ast, Expr}
@ -42,7 +42,10 @@ object Semantics extends Logging {
case (prev, acc) => prev :: acc 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[F, Raw] =
Prog Prog
.around( .around(
N.beginScope(expr.item) >> V.valueToRaw(expr.iterable).flatMap[Option[ValueRaw]] { V.valueToRaw(expr.iterable).flatMap[Option[ValueRaw]] {
case Some(vm) => case Some(vm) =>
vm.`type` match { vm.`type` match {
case t: BoxType => case t: BoxType =>
@ -71,7 +71,8 @@ class ForSem[S[_]](val expr: ForExpr[S]) extends AnyVal {
case _ => case _ =>
Raw.error("Wrong body of the For expression") Raw.error("Wrong body of the For expression")
} }
) <* N.endScope() )
) )
.namesScope[S](expr.token)
.abilitiesScope[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 CallArrowRawTag.service(LiteralRaw.quote("srv1"), "fn1", emptyCall, "A", arrowType).leaf
val expected = val expected =
ParTag.wrap( SeqGroupTag.wrap(
OnTag( ParTag.wrap(
LiteralRaw("\"other-peer\"", LiteralType.string), OnTag(
Chain.empty LiteralRaw("\"other-peer\"", LiteralType.string),
).wrap( Chain.empty
).wrap(
serviceCall
),
serviceCall serviceCall
), )
serviceCall
) )
proc.equalsOrShowDiff(expected) should be(true) proc.equalsOrShowDiff(expected) should be(true)