From 76fbb12563cca8a5e1791b096a9ebf4a68a7dfd5 Mon Sep 17 00:00:00 2001 From: InversionSpaces Date: Tue, 25 Jul 2023 14:00:37 +0000 Subject: [PATCH] Implement inlining --- .../inline/raw/ApplyBoolOpRawInliner.scala | 89 ++++++++++++++++++- .../inline/raw/ApplyIntoCopyRawInliner.scala | 5 +- .../inline/raw/CallArrowRawInliner.scala | 2 +- .../main/scala/aqua/model/ValueModel.scala | 15 ++++ 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBoolOpRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBoolOpRawInliner.scala index f84ff5bf6..573e9f8e9 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBoolOpRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyBoolOpRawInliner.scala @@ -9,6 +9,7 @@ import aqua.model.inline.Inline import aqua.model.inline.RawValueInliner.{unfold, valueToModel} import aqua.types.{ArrowType, ScalarType} import aqua.raw.value.ApplyBoolOpRaw +import aqua.raw.value.ApplyBoolOpRaw.BoolOpRaw.* import cats.data.Chain import cats.syntax.traverse.* @@ -17,14 +18,96 @@ import cats.syntax.functor.* import cats.syntax.flatMap.* import cats.syntax.apply.* import cats.syntax.foldable.* +import cats.syntax.applicative.* object ApplyBoolOpRawInliner extends RawInliner[ApplyBoolOpRaw] { override def apply[S: Mangler: Exports: Arrows]( raw: ApplyBoolOpRaw, propertiesAllowed: Boolean - ): State[S, (ValueModel, Inline)] = - (unfold(raw.left), unfold(raw.right)).flatMapN { case ((lm, linline), (rm, rinline)) => - ??? + ): State[S, (ValueModel, Inline)] = for { + left <- unfold(raw.left) + (lmodel, linline) = left + right <- unfold(raw.right) + (rmodel, rinline) = right + + result <- (lmodel, rmodel) match { + // Optimize in case of left value is known at compile time + case (LiteralModel.Bool(lvalue), _) => + (raw.op match { + case And if !lvalue => (LiteralModel.bool(false), linline) + case Or if lvalue => (LiteralModel.bool(true), linline) + case _ => (rmodel, Inline(linline.predo ++ rinline.predo)) + }).pure[State[S, *]] + // Optimize in case of right value is known at compile time and it has no computation + case (_, LiteralModel.Bool(rvalue)) if rinline.predo.isEmpty => + (raw.op match { + case And if !rvalue => (LiteralModel.bool(false), linline) + case Or if rvalue => (LiteralModel.bool(true), linline) + case _ => (lmodel, linline) + }).pure[State[S, *]] + // Produce unoptimized inline + case _ => fullInline(lmodel, rmodel, linline, rinline, raw.op) + } + } yield result + + private def fullInline[S: Mangler: Exports: Arrows]( + lmodel: ValueModel, + rmodel: ValueModel, + linline: Inline, + rinline: Inline, + op: ApplyBoolOpRaw.BoolOpRaw + ): State[S, (ValueModel, Inline)] = { + val (name, compareWith) = op match { + case And => ("and", true) + case Or => ("or", false) } + + /* + * (seq + * + * (xor + * (match + * (seq + * + * (ap ) + * ) + * ) + * (ap ) + * ) + * ) + * + * TODO: Handle errors in + */ + val predo = (resName: String) => + SeqModel.wrap( + linline.predo :+ XorModel.wrap( + MatchMismatchModel( + lmodel, + LiteralModel.bool(compareWith), + shouldMatch = true + ).wrap( + SeqModel.wrap( + rinline.predo :+ FlattenModel( + rmodel, + resName + ).leaf + ) + ), + FlattenModel( + lmodel, + resName + ).leaf + ) + ) + + Mangler[S] + .findAndForbidName(name) + .map(resName => + ( + VarModel(resName, ScalarType.bool), + Inline(Chain.one(predo(resName))) + ) + ) + } } diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala index b1f2f124f..fb4da3ad4 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/ApplyIntoCopyRawInliner.scala @@ -22,6 +22,7 @@ import cats.syntax.monoid.* import cats.syntax.functor.* import cats.syntax.flatMap.* import cats.syntax.apply.* +import cats.syntax.foldable.* object ApplyIntoCopyRawInliner extends Logging { @@ -53,14 +54,14 @@ object ApplyIntoCopyRawInliner extends Logging { name <- Mangler[S].findAndForbidName(value.name + "_obj_copy") foldedFields <- intoCopy.fields.nonEmptyTraverse(unfold(_)) varModel = VarModel(name, value.baseType) - valsInline = foldedFields.toSortedMap.values.map(_._2).fold(Inline.empty)(_ |+| _).desugar + valsInline = foldedFields.toList.foldMap { case (_, inline) => inline }.desugar fields = foldedFields.map(_._1) objCopy <- copyObj(value, fields, varModel) } yield { ( varModel, Inline( - Chain.one(SeqModel.wrap((valsInline.predo :+ objCopy).toList: _*)), + Chain.one(SeqModel.wrap(valsInline.predo :+ objCopy)), SeqMode ) ) diff --git a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala index 476677d7c..da46b0d5a 100644 --- a/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala +++ b/model/inline/src/main/scala/aqua/model/inline/raw/CallArrowRawInliner.scala @@ -32,7 +32,7 @@ object CallArrowRawInliner extends RawInliner[CallArrowRaw] with Logging { Chain( SeqModel.wrap( sd._2.toList ++ - cd._2.toList :+ CallServiceModel(sd._1, value.name, cd._1).leaf: _* + cd._2.toList :+ CallServiceModel(sd._1, value.name, cd._1).leaf ) ) ) diff --git a/model/src/main/scala/aqua/model/ValueModel.scala b/model/src/main/scala/aqua/model/ValueModel.scala index 547a0fccd..b904853b9 100644 --- a/model/src/main/scala/aqua/model/ValueModel.scala +++ b/model/src/main/scala/aqua/model/ValueModel.scala @@ -62,6 +62,19 @@ case class LiteralModel(value: String, `type`: Type) extends ValueModel { object LiteralModel { + /** + * Used to match bool literals in pattern matching + */ + object Bool { + + def unapply(lm: LiteralModel): Option[Boolean] = + lm match { + case LiteralModel("true", ScalarType.bool | LiteralType.bool) => true.some + case LiteralModel("false", ScalarType.bool | LiteralType.bool) => false.some + case _ => none + } + } + // AquaVM will return empty string for // %last_error%.$.error_code if there is no %last_error% val emptyErrorCode = quote("") @@ -71,6 +84,8 @@ object LiteralModel { def quote(str: String): LiteralModel = LiteralModel(s"\"$str\"", LiteralType.string) def number(n: Int): LiteralModel = LiteralModel(n.toString, LiteralType.forInt(n)) + + def bool(b: Boolean): LiteralModel = LiteralModel(b.toString.toLowerCase, LiteralType.bool) } sealed trait PropertyModel {