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 ea155ad8..806b9f39 100644 --- a/backend/air/src/main/scala/aqua/backend/air/AirGen.scala +++ b/backend/air/src/main/scala/aqua/backend/air/AirGen.scala @@ -50,7 +50,14 @@ object AirGen extends LogSupport { case SeqRes => Eval later ops.toList.reduceLeftOption(SeqGen).getOrElse(NullGen) case ParRes => - Eval later ops.toList.reduceLeftOption(ParGen).getOrElse(NullGen) + Eval later (ops.toList match { + case o :: Nil => ParGen(o, NullGen) + case _ => + ops.toList.reduceLeftOption(ParGen).getOrElse { + warn("ParRes with no children converted to Null") + NullGen + } + }) case XorRes => Eval later (ops.toList match { case o :: Nil => XorGen(o, NullGen) diff --git a/build.sbt b/build.sbt index 3488e14b..fdaafadb 100644 --- a/build.sbt +++ b/build.sbt @@ -24,7 +24,7 @@ val airframeLog = "org.wvlet.airframe" %% "airframe-log" % airframeLogV name := "aqua-hll" val commons = Seq( - baseAquaVersion := "0.1.7", + baseAquaVersion := "0.1.8", version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"), scalaVersion := dottyVersion, libraryDependencies ++= Seq( diff --git a/model/src/main/scala/aqua/model/func/raw/FuncOp.scala b/model/src/main/scala/aqua/model/func/raw/FuncOp.scala index 0fc53225..c832bb36 100644 --- a/model/src/main/scala/aqua/model/func/raw/FuncOp.scala +++ b/model/src/main/scala/aqua/model/func/raw/FuncOp.scala @@ -111,7 +111,8 @@ object FuncOp { object RightAssocSemi extends Semigroup[FuncOp] { override def combine(x: FuncOp, y: FuncOp): FuncOp = (x.tree.head, y.tree.head) match { - case (ParTag, ParTag) => FuncOp(y.tree.copy(tail = (x.tree.tail, y.tree.tail).mapN(_ ++ _))) + case (_: ParGroupTag, ParTag) => + FuncOp(y.tree.copy(tail = (x.tree.tail, y.tree.tail).mapN(_ ++ _))) case (XorTag, XorTag) => FuncOp(y.tree.copy(tail = (x.tree.tail, y.tree.tail).mapN(_ ++ _))) case (XorTag.LeftBiased, XorTag) => diff --git a/model/src/main/scala/aqua/model/func/raw/FuncOps.scala b/model/src/main/scala/aqua/model/func/raw/FuncOps.scala index 2063eefb..b6555003 100644 --- a/model/src/main/scala/aqua/model/func/raw/FuncOps.scala +++ b/model/src/main/scala/aqua/model/func/raw/FuncOps.scala @@ -64,6 +64,9 @@ object FuncOps { .map(FuncOp(_)) ) + def co(ops: FuncOp*): FuncOp = + FuncOp.wrap(ParTag.Detach, seq(ops: _*)) + def xor(left: FuncOp, right: FuncOp): FuncOp = FuncOp.node(XorTag, Chain(left, right)) diff --git a/model/src/main/scala/aqua/model/func/raw/PathFinder.scala b/model/src/main/scala/aqua/model/func/raw/PathFinder.scala index acaec064..79b58bcb 100644 --- a/model/src/main/scala/aqua/model/func/raw/PathFinder.scala +++ b/model/src/main/scala/aqua/model/func/raw/PathFinder.scala @@ -18,7 +18,7 @@ object PathFinder extends LogSupport { !isExit && to.leftSiblings.isEmpty && to.moveUp.exists(_.pathOn == to.pathOn) && - !to.parentTag.contains(ParTag) + !to.parentTag.exists(_.isInstanceOf[ParGroupTag]) if (wasHandled) { debug("Was handled") diff --git a/model/src/main/scala/aqua/model/func/raw/RawCursor.scala b/model/src/main/scala/aqua/model/func/raw/RawCursor.scala index 25813a4e..61e20993 100644 --- a/model/src/main/scala/aqua/model/func/raw/RawCursor.scala +++ b/model/src/main/scala/aqua/model/func/raw/RawCursor.scala @@ -44,14 +44,14 @@ case class RawCursor(tree: NonEmptyList[ChainZipper[FuncOp.Tree]]) lazy val lastExecuted: Option[RawCursor] = tag match { case XorTag => toFirstChild.flatMap(_.lastExecuted) case _: SeqGroupTag => toLastChild.flatMap(_.lastExecuted) - case ParTag => None + case _: ParGroupTag => None case _: NoExecTag => None case _ => Some(this) } lazy val firstExecuted: Option[RawCursor] = tag match { case _: SeqGroupTag => toLastChild.flatMap(_.lastExecuted) - case ParTag => None + case _: ParGroupTag => None case _: NoExecTag => None case _ => Some(this) } @@ -95,7 +95,7 @@ case class RawCursor(tree: NonEmptyList[ChainZipper[FuncOp.Tree]]) } lazy val pathToNext: Chain[ValueModel] = parentTag.fold(Chain.empty[ValueModel]) { - case ParTag => + case _: ParGroupTag => val exports = FuncOp(current).exportsVarNames.value if (exports.nonEmpty && checkNamesUsedLater(exports)) seqNext.fold(Chain.empty[ValueModel])(nxt => diff --git a/model/src/main/scala/aqua/model/func/raw/RawTag.scala b/model/src/main/scala/aqua/model/func/raw/RawTag.scala index 4f4d973b..05555ea4 100644 --- a/model/src/main/scala/aqua/model/func/raw/RawTag.scala +++ b/model/src/main/scala/aqua/model/func/raw/RawTag.scala @@ -35,12 +35,16 @@ sealed trait NoExecTag extends RawTag sealed trait GroupTag extends RawTag sealed trait SeqGroupTag extends GroupTag +sealed trait ParGroupTag extends GroupTag case object SeqTag extends SeqGroupTag -case object ParTag extends GroupTag + +case object ParTag extends ParGroupTag { + case object Detach extends ParGroupTag +} case object XorTag extends SeqGroupTag { - case object LeftBiased extends GroupTag + case object LeftBiased extends SeqGroupTag } case class XorParTag(xor: FuncOp, par: FuncOp) extends RawTag diff --git a/model/src/main/scala/aqua/model/topology/Topology.scala b/model/src/main/scala/aqua/model/topology/Topology.scala index f6bdbe5a..e06b2d87 100644 --- a/model/src/main/scala/aqua/model/topology/Topology.scala +++ b/model/src/main/scala/aqua/model/topology/Topology.scala @@ -54,7 +54,7 @@ object Topology extends LogSupport { case _: OnTag => SeqRes case MatchMismatchTag(a, b, s) => MatchMismatchRes(a, b, s) case ForTag(item, iter) => FoldRes(item, iter) - case ParTag => ParRes + case ParTag | ParTag.Detach => ParRes case XorTag | XorTag.LeftBiased => XorRes case NextTag(item) => NextRes(item) case CallServiceTag(serviceId, funcName, call) => diff --git a/parser/src/main/scala/aqua/parser/expr/CoExpr.scala b/parser/src/main/scala/aqua/parser/expr/CoExpr.scala new file mode 100644 index 00000000..6b79e292 --- /dev/null +++ b/parser/src/main/scala/aqua/parser/expr/CoExpr.scala @@ -0,0 +1,19 @@ +package aqua.parser.expr + +import aqua.parser.Expr +import aqua.parser.lexer.Token +import aqua.parser.lift.LiftParser +import aqua.parser.lift.LiftParser._ +import cats.Comonad +import cats.parse.Parser +import Token.`co` + +case class CoExpr[F[_]](point: Token[F]) extends Expr[F](CoExpr, point) + +object CoExpr extends Expr.Prefix { + override def continueWith: List[Expr.Lexem] = ParExpr.continueWith + + override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] = + `co`.lift.map(Token.lift[F, Unit](_)).map(CoExpr(_)) + +} diff --git a/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala b/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala index cefea854..ea9eecdc 100644 --- a/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/FuncExpr.scala @@ -30,6 +30,7 @@ object FuncExpr extends Expr.AndIndented { ElseOtherwiseExpr :: CatchExpr :: ParExpr :: + CoExpr :: DeclareStreamExpr :: Nil diff --git a/parser/src/main/scala/aqua/parser/expr/IfExpr.scala b/parser/src/main/scala/aqua/parser/expr/IfExpr.scala index db9c23fa..ae4530e4 100644 --- a/parser/src/main/scala/aqua/parser/expr/IfExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/IfExpr.scala @@ -18,6 +18,8 @@ object IfExpr extends Expr.AndIndented { CallArrowExpr :: AbilityIdExpr :: AssignmentExpr :: + Expr.defer(ParExpr) :: + Expr.defer(CoExpr) :: Expr.defer(TryExpr) :: Expr.defer(ForExpr) :: Expr.defer(IfExpr) :: diff --git a/parser/src/main/scala/aqua/parser/expr/OnExpr.scala b/parser/src/main/scala/aqua/parser/expr/OnExpr.scala index 700f12cb..8119685d 100644 --- a/parser/src/main/scala/aqua/parser/expr/OnExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/OnExpr.scala @@ -17,6 +17,7 @@ object OnExpr extends Expr.AndIndented { AbilityIdExpr :: AssignmentExpr :: ParExpr :: + CoExpr :: Expr.defer(TryExpr) :: Expr.defer(ForExpr) :: Expr.defer(IfExpr) :: diff --git a/parser/src/main/scala/aqua/parser/lexer/Token.scala b/parser/src/main/scala/aqua/parser/lexer/Token.scala index 1d1b9d54..ed5133f7 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Token.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Token.scala @@ -42,6 +42,7 @@ object Token { val `try`: P[Unit] = P.string("try") val `catch`: P[Unit] = P.string("catch") val `par`: P[Unit] = P.string("par") + val `co`: P[Unit] = P.string("co") val `:` : P[Unit] = P.char(':') val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?) diff --git a/semantics/src/main/scala/aqua/semantics/ExprSem.scala b/semantics/src/main/scala/aqua/semantics/ExprSem.scala index 25b1aa26..50558b87 100644 --- a/semantics/src/main/scala/aqua/semantics/ExprSem.scala +++ b/semantics/src/main/scala/aqua/semantics/ExprSem.scala @@ -35,6 +35,7 @@ object ExprSem { case expr: CatchExpr[F] => new CatchSem(expr).program[G] case expr: ElseOtherwiseExpr[F] => new ElseOtherwiseSem(expr).program[G] case expr: ParExpr[F] => new ParSem(expr).program[G] + case expr: CoExpr[F] => new CoSem(expr).program[G] case expr: ReturnExpr[F] => new ReturnSem(expr).program[G] case expr: ServiceExpr[F] => new ServiceSem(expr).program[G] case expr: RootExpr[F] => new RootSem(expr).program[G] diff --git a/semantics/src/main/scala/aqua/semantics/expr/CoSem.scala b/semantics/src/main/scala/aqua/semantics/expr/CoSem.scala new file mode 100644 index 00000000..7e11786b --- /dev/null +++ b/semantics/src/main/scala/aqua/semantics/expr/CoSem.scala @@ -0,0 +1,17 @@ +package aqua.semantics.expr + +import aqua.model.Model +import aqua.model.func.raw.{FuncOp, ParTag} +import aqua.parser.expr.CoExpr +import aqua.semantics.Prog +import cats.free.Free + +class CoSem[F[_]](val expr: CoExpr[F]) extends AnyVal { + + def program[Alg[_]]: Prog[Alg, Model] = + Prog.after[Alg, Model] { + case g: FuncOp => + Free.pure[Alg, Model](FuncOp.wrap(ParTag.Detach, g)) + case g => Free.pure[Alg, Model](g) + } +}