feat(compiler): Generate empty calls to responseHandlerSrv [LNG-286] (#979)

* Add noEmptyResponse

* Fix tests
This commit is contained in:
InversionSpaces 2023-11-17 11:43:13 +01:00 committed by GitHub
parent 11c8970fd8
commit cee444862a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 48 deletions

View File

@ -37,6 +37,8 @@ type CommonArgs = {
targetType?: "ts" | "js" | "air" | undefined;
/** Compile aqua in tracing mode (for debugging purposes). Default: false */
tracing?: boolean | undefined;
/** Do not generate response call if there are no returned values */
noEmptyResponse?: boolean | undefined;
};
type CodeString = {

View File

@ -7,6 +7,7 @@ function getConfig({
noXor = false,
targetType = "air",
tracing = false,
noEmptyResponse = false,
}) {
return new AquaConfig(
logLevel,
@ -19,6 +20,7 @@ function getConfig({
air: "air",
}[targetType],
tracing,
noEmptyResponse,
);
}

View File

@ -4,9 +4,9 @@ import aqua.api.AquaAPIConfig
import aqua.api.TargetType.*
import aqua.js.{FunctionDefJs, ServiceDefJs}
import aqua.model.transform.TransformConfig
import cats.data.Validated.{invalidNec, validNec}
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
import scala.scalajs.js
import scala.scalajs.js.JSConverters.*
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
@ -47,7 +47,9 @@ class AquaConfig(
@JSExport
val targetType: js.UndefOr[String],
@JSExport
val tracing: js.UndefOr[Boolean]
val tracing: js.UndefOr[Boolean],
@JSExport
val noEmptyResponse: js.UndefOr[Boolean]
)
object AquaConfig {
@ -69,7 +71,8 @@ object AquaConfig {
constants = cjs.constants.map(_.toList).getOrElse(Nil),
noXor = cjs.noXor.getOrElse(false),
noRelay = cjs.noRelay.getOrElse(false),
tracing = cjs.tracing.getOrElse(false)
tracing = cjs.tracing.getOrElse(false),
noEmptyResponse = cjs.noEmptyResponse.getOrElse(false)
)
}
}

View File

@ -10,12 +10,14 @@ case class AquaAPIConfig(
constants: List[String] = Nil,
noXor: Boolean = false, // TODO: Remove
noRelay: Boolean = false,
tracing: Boolean = false
tracing: Boolean = false,
noEmptyResponse: Boolean = false
) {
def getTransformConfig: TransformConfig = {
val config = TransformConfig(
tracing = Option.when(tracing)(TransformConfig.TracingConfig.default)
tracing = Option.when(tracing)(TransformConfig.TracingConfig.default),
noEmptyResponse = noEmptyResponse
)
if (noRelay) config.copy(relayVarName = None)

View File

@ -1,12 +1,15 @@
package aqua.compiler
import aqua.model.{CallModel, ForModel, FunctorModel, LiteralModel, ValueModel, VarModel}
import aqua.model.AquaContext
import aqua.model.CallServiceModel
import aqua.model.FlattenModel
import aqua.model.transform.ModelBuilder
import aqua.model.transform.TransformConfig
import aqua.model.transform.Transform
import aqua.parser.ParserError
import aqua.model.transform.TransformConfig
import aqua.model.{CallModel, ForModel, FunctorModel, LiteralModel, ValueModel, VarModel}
import aqua.parser.Ast
import aqua.parser.Parser
import aqua.parser.ParserError
import aqua.parser.lift.Span
import aqua.parser.lift.Span.S
import aqua.raw.ConstantRaw
@ -18,15 +21,12 @@ import aqua.types.{ArrayType, CanonStreamType, LiteralType, ScalarType, StreamTy
import cats.Id
import cats.data.{Chain, NonEmptyChain, NonEmptyMap, Validated, ValidatedNec}
import cats.instances.string.*
import cats.syntax.show.*
import cats.syntax.option.*
import cats.syntax.either.*
import cats.syntax.option.*
import cats.syntax.show.*
import org.scalatest.Inside
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatest.Inside
import aqua.model.AquaContext
import aqua.model.FlattenModel
import aqua.model.CallServiceModel
class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
import ModelBuilder.*
@ -358,7 +358,8 @@ class AquaCompilerSpec extends AnyFlatSpec with Matchers with Inside {
join(VarModel(streamName, streamType), arg),
decrement
)
)
),
emptyRespCall(transformCfg, initPeer)
),
errorCall(transformCfg, 0, initPeer)
)

View File

@ -1,25 +1,25 @@
package aqua.model.transform
import aqua.model.*
import aqua.model.inline.ArrowInliner
import aqua.model.inline.state.InliningState
import aqua.model.transform.TransformConfig.TracingConfig
import aqua.model.transform.funcop.*
import aqua.model.transform.pre.*
import aqua.model.transform.pre.{CallbackErrorHandler, ErrorHandler}
import aqua.model.transform.topology.Topology
import aqua.model.*
import aqua.raw.ops.RawTag
import aqua.raw.value.VarRaw
import aqua.res.*
import aqua.types.ScalarType
import aqua.model.transform.TransformConfig.TracingConfig
import aqua.model.transform.pre.{CallbackErrorHandler, ErrorHandler}
import cats.Eval
import cats.data.Chain
import cats.free.Cofree
import cats.instances.list.*
import cats.syntax.option.*
import cats.syntax.show.*
import cats.syntax.traverse.*
import cats.instances.list.*
import scribe.Logging
// API for transforming RawTag to Res
@ -90,7 +90,8 @@ object Transform extends Logging {
val resultsHandler: ResultsHandler = CallbackResultsHandler(
callbackSrvId = conf.callbackSrvId,
funcName = conf.respFuncName
funcName = conf.respFuncName,
noEmptyResponse = conf.noEmptyResponse
)
val errorHandler: ErrorHandler = CallbackErrorHandler(

View File

@ -1,19 +1,33 @@
package aqua.model.transform
import aqua.model.{AquaContext, LiteralModel, ValueModel, VarModel}
import aqua.raw.{ConstantRaw, RawContext, RawPart}
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
import aqua.raw.{ConstantRaw, RawContext, RawPart}
import aqua.types.ScalarType
import cats.data.Chain
import cats.kernel.Monoid
// TODO docs
/**
* Configuration for function pre transformer
*
* @param getDataService - name of the service that provides arguments
* @param callbackService - name of the service that provides callbacks
* @param errorHandlingService - name of the service that handles errors
* @param errorFuncName - name of the function that handles errors (in errorHandlingService)
* @param respFuncName - name of the function that handles responses (in getDataService)
* @param noEmptyResponse - if true, do not generate response call if there is no return values
* @param relayVarName - name of the relay variable
* @param tracing - tracing configuration
* @param constants - list of constants
*/
case class TransformConfig(
getDataService: String = "getDataSrv",
callbackService: String = "callbackSrv",
errorHandlingService: String = "errorHandlingSrv",
errorFuncName: String = "error",
respFuncName: String = "response",
noEmptyResponse: Boolean = false,
relayVarName: Option[String] = Some("-relay-"),
tracing: Option[TransformConfig.TracingConfig] = None,
constants: List[ConstantRaw] = Nil

View File

@ -1,8 +1,8 @@
package aqua.model.transform.pre
import aqua.types.Type
import aqua.raw.ops.{Call, CallArrowRawTag, RawTag}
import aqua.raw.value.{ValueRaw, VarRaw}
import aqua.types.Type
import cats.syntax.option.*
@ -10,11 +10,14 @@ trait ResultsHandler {
def handleResults(results: List[(String, Type)]): Option[RawTag.Tree]
}
case class CallbackResultsHandler(callbackSrvId: ValueRaw, funcName: String)
extends ResultsHandler {
case class CallbackResultsHandler(
callbackSrvId: ValueRaw,
funcName: String,
noEmptyResponse: Boolean
) extends ResultsHandler {
override def handleResults(results: List[(String, Type)]): Option[RawTag.Tree] =
if (results.isEmpty) none
if (results.isEmpty && noEmptyResponse) none
else {
val resultVars = results.map(VarRaw.apply.tupled)
val call = Call(

View File

@ -1,22 +1,22 @@
package aqua.model.transform
import aqua.model.*
import aqua.model.FailModel
import aqua.model.IntoIndexModel
import aqua.model.OnModel
import aqua.model.inline.raw.StreamGateInliner
import aqua.raw.ops.Call
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
import aqua.{model, res}
import aqua.res.{CallRes, CallServiceRes, MakeRes}
import aqua.types.{ArrayType, LiteralType, ScalarType}
import aqua.types.StreamType
import aqua.model.IntoIndexModel
import aqua.model.inline.raw.StreamGateInliner
import aqua.model.OnModel
import aqua.model.FailModel
import aqua.res.ResolvedOp
import aqua.res.{CallRes, CallServiceRes, MakeRes}
import aqua.types.StreamType
import aqua.types.{ArrayType, LiteralType, ScalarType}
import aqua.{model, res}
import scala.language.implicitConversions
import cats.data.Chain
import cats.data.Chain.==:
import cats.syntax.option.*
import scala.language.implicitConversions
object ModelBuilder {
implicit def rawToValue(raw: ValueRaw): ValueModel = ValueModel.fromRaw(raw)
@ -88,15 +88,24 @@ object ModelBuilder {
)
.leaf
def respCall(bc: TransformConfig, value: ValueModel, on: ValueModel = initPeer) =
res
.CallServiceRes(
ValueModel.fromRaw(bc.callbackSrvId),
bc.respFuncName,
CallRes(value :: Nil, None),
on
)
.leaf
def respCallImpl(
config: TransformConfig,
arguments: List[ValueModel],
on: ValueModel = initPeer
) = res
.CallServiceRes(
ValueModel.fromRaw(config.callbackSrvId),
config.respFuncName,
CallRes(arguments, None),
on
)
.leaf
def respCall(config: TransformConfig, value: ValueModel, on: ValueModel = initPeer) =
respCallImpl(config, value :: Nil, on)
def emptyRespCall(config: TransformConfig, on: ValueModel = initPeer) =
respCallImpl(config, Nil)
def dataCall(bc: TransformConfig, name: String, on: ValueModel = initPeer) =
res

View File

@ -4,15 +4,15 @@ import aqua.model.transform.ModelBuilder
import aqua.model.transform.{Transform, TransformConfig}
import aqua.model.{CallModel, FuncArrow, LiteralModel, VarModel}
import aqua.raw.ops.{Call, CallArrowRawTag, FuncOp, OnTag, RawTag, SeqTag}
import aqua.raw.value.{LiteralRaw, VarRaw}
import aqua.types.{ArrowType, NilType, ProductType, ScalarType}
import aqua.raw.value.{LiteralRaw, ValueRaw, VarRaw}
import aqua.raw.value.{LiteralRaw, VarRaw}
import aqua.res.{CallRes, CallServiceRes, MakeRes, SeqRes, XorRes}
import aqua.types.{ArrowType, NilType, ProductType, ScalarType}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import cats.data.Chain
import cats.syntax.show.*
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class TransformSpec extends AnyFlatSpec with Matchers {