feat(compiler): Handle error function exit in tracing mode [LNG-250] (#921)

* Wrap function calls with xor

* Do not detach tracing call in case of error exit

* Fix comment
This commit is contained in:
InversionSpaces 2023-10-17 15:42:38 +02:00 committed by GitHub
parent 030a0d464b
commit 03d23eb577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 32 deletions

View File

@ -25,11 +25,16 @@ object ValueModel {
def errorCode(error: VarModel): Option[VarModel] =
error.intoField("error_code")
def errorMessage(error: VarModel): Option[VarModel] =
error.intoField("message")
val error = VarModel.fromVarRaw(ValueRaw.error)
val errorType = ValueRaw.errorType
// NOTE: It should be safe as `:error:` should have `error_code` field
val lastErrorCode = errorCode(error).get
// NOTE: It should be safe as `:error:` should have `message` field
val lastErrorMessage = errorMessage(error).get
implicit object ValueModelEq extends Eq[ValueModel] {
override def eqv(x: ValueModel, y: ValueModel): Boolean = x == y

View File

@ -1,23 +1,15 @@
package aqua.model.transform.funcop
import cats.data.Chain
import cats.Eval
import aqua.model.{
CallModel,
CallServiceModel,
LiteralModel,
MetaModel,
OpModel,
SeqModel,
ValueModel
}
import aqua.model.*
import aqua.model.transform.pre.InitPeerCallable
import aqua.model.ParModel
import aqua.model.DetachModel
import aqua.model.transform.TransformConfig.TracingConfig
import cats.data.Chain
import cats.Eval
import aqua.types.ScalarType
final case class Tracing(
enabledConfig: Option[TracingConfig],
initCallable: InitPeerCallable
@ -41,20 +33,41 @@ final case class Tracing(
.fold(child)(traceCall =>
/* seq:
detach: call tracing enter
xor:
seq:
<call-arrow-code>
detach: call tracing exit */
detach: call tracing exit
seq:
call tracing error exit
rethrow error
*/
SeqModel.wrap(
DetachModel.wrap(
initCallable.onInitPeer.wrap(
traceCall(Event.Enter)
)
),
XorModel.wrap(
SeqModel.wrap(
child,
DetachModel.wrap(
initCallable.onInitPeer.wrap(
traceCall(Event.Exit)
)
)
),
SeqModel.wrap(
/**
* NOTE: Here we don't wrap trace call
* with detach because Aqua VM ignores
* it if it is detached.
*/
initCallable.onInitPeer.wrap(
traceCall(Event.ErrorExit)
),
FailModel(ValueModel.error).leaf
)
)
)
)
)
@ -64,23 +77,47 @@ final case class Tracing(
object Tracing {
enum Event {
case Enter, Exit
case Enter, Exit, ErrorExit
def toArg: ValueModel = LiteralModel.quote(this match {
def toArg(suffix: String = ""): ValueModel = LiteralModel.quote((this match {
case Enter => "enter"
case Exit => "exit"
})
case ErrorExit => "exit with error"
}) + suffix)
}
def traceCallModel(config: TracingConfig, arrowName: String)(
private def traceCallModel(config: TracingConfig, arrowName: String)(
event: Event
): OpModel.Tree =
): OpModel.Tree = {
val serviceCall = (msg: ValueModel) =>
CallServiceModel(
LiteralModel.quote(config.serviceId),
config.serviceFuncName,
CallModel(
args = List(LiteralModel.quote(arrowName), event.toArg),
args = List(LiteralModel.quote(arrowName), msg),
exportTo = Nil
)
).leaf
event match {
case Event.ErrorExit =>
val errorName = "-return-error-msg-"
RestrictionModel(
errorName,
ScalarType.string
).wrap(
CallServiceModel(
LiteralModel.quote("op"),
"concat_strings",
CallModel(
args = List(event.toArg(": "), ValueModel.lastErrorMessage),
exportTo = List(CallModel.Export(errorName, ScalarType.string))
)
).leaf,
serviceCall(VarModel(errorName, ScalarType.string))
)
case _ => serviceCall(event.toArg())
}
}
}