Skip to content

Commit

Permalink
Change if inlining, add fail model
Browse files Browse the repository at this point in the history
  • Loading branch information
InversionSpaces committed Jul 6, 2023
1 parent c1fe24b commit 78a1720
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 38 deletions.
5 changes: 5 additions & 0 deletions backend/air/src/main/scala/aqua/backend/air/Air.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ object Keyword {

case object Ap extends Keyword("ap")

case object Fail extends Keyword("fail")

case object Canon extends Keyword("canon")

case object Seq extends Keyword("seq")
Expand Down Expand Up @@ -110,6 +112,8 @@ object Air {

case class Ap(op: DataView, result: String) extends Air(Keyword.Ap)

case class Fail(op: DataView) extends Air(Keyword.Fail)

case class Canon(op: DataView, peerId: DataView, result: String) extends Air(Keyword.Canon)

case class Comment(comment: String, air: Air) extends Air(Keyword.NA)
Expand Down Expand Up @@ -143,6 +147,7 @@ object Air {
case Air.Call(triplet, args, res)
s" ${triplet.show} [${args.map(_.show).mkString(" ")}]${res.fold("")(" " + _)}"
case Air.Ap(operand, result) s" ${operand.show} $result"
case Air.Fail(operand) => s" ${operand.show}"
case Air.Canon(operand, peerId, result) s" ${peerId.show} ${operand.show} $result"
case Air.Comment(_, _) => ";; Should not be displayed"
}) + ")\n"
Expand Down
11 changes: 11 additions & 0 deletions backend/air/src/main/scala/aqua/backend/air/AirGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ object AirGen extends Logging {
ApGen(valueToData(operand), exportToString(exportTo))
)

case FailRes(operand) =>
Eval.later(
FailGen(valueToData(operand))
)

case CanonRes(operand, peerId, exportTo) =>
Eval.later(
CanonGen(valueToData(operand), valueToData(peerId), exportToString(exportTo))
Expand Down Expand Up @@ -164,6 +169,12 @@ case class ApGen(operand: DataView, result: String) extends AirGen {
Air.Ap(operand, result)
}

case class FailGen(operand: DataView) extends AirGen {

override def generate: Air =
Air.Fail(operand)
}

case class CanonGen(operand: DataView, peerId: DataView, result: String) extends AirGen {

override def generate: Air =
Expand Down
28 changes: 2 additions & 26 deletions model/inline/src/main/scala/aqua/model/inline/TagInliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import cats.data.{Chain, State, StateT}
import cats.syntax.show.*
import scribe.{log, Logging}
import aqua.model.inline.Inline.parDesugarPrefixOpt
import aqua.model.inline.tag.IfTagInliner

/**
* [[TagInliner]] prepares a [[RawTag]] for futher processing by converting [[ValueRaw]]s into [[ValueModel]]s.
Expand Down Expand Up @@ -200,32 +201,7 @@ object TagInliner extends Logging {
valueToModel(rightRaw) >>= canonicalizeIfStream.tupled
).mapN { case ((leftModel, leftPrefix), (rightModel, rightPrefix)) =>
val prefix = parDesugarPrefixOpt(leftPrefix, rightPrefix)
val toModel = (children: Chain[OpModel.Tree]) =>
XorModel.wrap(
children.uncons.map { case (ifBody, elseBody) =>
val elseBodyFiltered = elseBody.filterNot(
_.head == EmptyModel
)

/**
* Hack for xor with mismatch always have second branch
* TODO: Fix this in topology
* see https://linear.app/fluence/issue/LNG-69/if-inside-on-produces-invalid-topology
*/
val elseBodyAugmented =
if (elseBodyFiltered.isEmpty)
Chain.one(
NullModel.leaf
)
else elseBodyFiltered

MatchMismatchModel(
leftModel,
rightModel,
shouldMatch
).wrap(ifBody) +: elseBodyAugmented
}.getOrElse(children)
)
val toModel = IfTagInliner(leftModel, rightModel, shouldMatch).inline

TagInlined.Mapping(
toModel = toModel,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package aqua.model.inline.tag

import aqua.model.ValueModel
import aqua.model.*

import cats.data.Chain

final case class IfTagInliner(
left: ValueModel,
right: ValueModel,
shouldMatch: Boolean
) {
import IfTagInliner.*

def inline(children: Chain[OpModel.Tree]): OpModel.Tree =
children
.filterNot(_.head == EmptyModel)
.uncons
.map { case (ifBody, elseBody) =>
val elseOrNull =
if (elseBody.isEmpty)
Chain.one(NullModel.leaf)
else elseBody

XorModel.wrap(
MatchMismatchModel(left, right, shouldMatch).wrap(
ifBody
),
XorModel.wrap(
noError.wrap(
elseOrNull
),
rethrow.leaf
)
)
}
.getOrElse(EmptyModel.leaf)

}

object IfTagInliner {

val noError: MatchMismatchModel =
MatchMismatchModel(
left = ValueModel.lastErrorCode,
right = LiteralModel.emptyErrorCode,
shouldMatch = true
)

val rethrow: FailModel =
FailModel(
value = ValueModel.lastError
)
}
25 changes: 13 additions & 12 deletions model/raw/src/main/scala/aqua/raw/value/ValueRaw.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,22 @@ object ValueRaw {

val Nil: LiteralRaw = LiteralRaw("[]", StreamType(BottomType))

val LastError: VarRaw = VarRaw(
"%last_error%",
StructType(
"LastError",
NonEmptyMap.of(
// These two fields are mandatory for all errors
"message" -> ScalarType.string,
"error_code" -> ScalarType.i64,
// These fields are specific to AquaVM's errors only
"instruction" -> ScalarType.string,
"peer_id" -> ScalarType.string
)
val lastErrorType = StructType(
"LastError",
NonEmptyMap.of(
// These two fields are mandatory for all errors
"message" -> ScalarType.string,
"error_code" -> ScalarType.i64,
// These fields are specific to AquaVM's errors only
"instruction" -> ScalarType.string,
"peer_id" -> ScalarType.string
)
)

val LastError: VarRaw = VarRaw(
"%last_error%",
lastErrorType
)
}

case class ApplyPropertyRaw(value: ValueRaw, property: PropertyRaw) extends ValueRaw {
Expand Down
2 changes: 2 additions & 0 deletions model/res/src/main/scala/aqua/res/MakeRes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ object MakeRes {
ApRes(operand, CallModel.Export(assignTo, ArrayType(el))).leaf
case FlattenModel(operand, assignTo) =>
ApRes(operand, CallModel.Export(assignTo, operand.`type`)).leaf
case FailModel(value) =>
FailRes(value).leaf
case CallServiceModel(serviceId, funcName, CallModel(args, exportTo)) =>
CallServiceRes(
serviceId,
Expand Down
4 changes: 4 additions & 0 deletions model/res/src/main/scala/aqua/res/ResolvedOp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ case class ApRes(operand: ValueModel, exportTo: CallModel.Export) extends Resolv
override def toString: String = s"(ap $operand $exportTo)"
}

case class FailRes(operand: ValueModel) extends ResolvedOp {
override def toString: String = s"(fail $operand)"
}

case class CanonRes(operand: ValueModel, peerId: ValueModel, exportTo: CallModel.Export)
extends ResolvedOp {
override def toString: String = s"(canon $peerId $operand $exportTo)"
Expand Down
6 changes: 6 additions & 0 deletions model/src/main/scala/aqua/model/OpModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ case class FlattenModel(value: ValueModel, assignTo: String) extends OpModel {
override def exportsVarNames: Set[String] = Set(assignTo)
}

case class FailModel(value: ValueModel) extends OpModel {
override def usesVarNames: Set[String] = value.usesVarNames

override def exportsVarNames: Set[String] = Set.empty
}

case class PushToStreamModel(value: ValueModel, exportTo: CallModel.Export) extends OpModel {

override def usesVarNames: Set[String] = value.usesVarNames
Expand Down
33 changes: 33 additions & 0 deletions model/src/main/scala/aqua/model/ValueModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package aqua.model

import aqua.raw.value.*
import aqua.types.*

import cats.Eq
import cats.data.{Chain, NonEmptyMap}
import cats.syntax.option.*
import scribe.Logging

sealed trait ValueModel {
Expand All @@ -18,6 +20,19 @@ sealed trait ValueModel {

object ValueModel {

def errorCode(error: VarModel): Option[VarModel] =
error.intoField("error_code")

val lastError = VarModel(
name = ValueRaw.LastError.name,
baseType = ValueRaw.LastError.baseType
)

val lastErrorType = ValueRaw.lastErrorType

// NOTE: It should be safe as %last_error% should have `error_code` field
val lastErrorCode = errorCode(lastError).get

implicit object ValueModelEq extends Eq[ValueModel] {
override def eqv(x: ValueModel, y: ValueModel): Boolean = x == y
}
Expand Down Expand Up @@ -46,9 +61,16 @@ case class LiteralModel(value: String, `type`: Type) extends ValueModel {
}

object LiteralModel {

// AquaVM will return empty string for
// %last_error%.$.error_code if there is no %last_error%
val emptyErrorCode = quote("")

def fromRaw(raw: LiteralRaw): LiteralModel = LiteralModel(raw.value, raw.baseType)

def quote(str: String): LiteralModel = LiteralModel(s"\"$str\"", LiteralType.string)

def number(n: Int): LiteralModel = LiteralModel(n.toString, LiteralType.number)
}

sealed trait PropertyModel {
Expand Down Expand Up @@ -117,6 +139,17 @@ case class VarModel(name: String, baseType: Type, properties: Chain[PropertyMode
private def deriveFrom(vm: VarModel): VarModel =
vm.copy(properties = vm.properties ++ properties)

def intoField(field: String): Option[VarModel] = `type` match {
case StructType(_, fields) =>
fields(field)
.map(fieldType =>
copy(
properties = properties :+ IntoFieldModel(field, fieldType)
)
)
case _ => none
}

override def resolveWith(vals: Map[String, ValueModel]): ValueModel =
vals.get(name) match {
case Some(vv: VarModel) =>
Expand Down

0 comments on commit 78a1720

Please sign in to comment.