diff --git a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala index 3a359b7e4..011583758 100644 --- a/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala +++ b/model/raw/src/main/scala/aqua/raw/ops/RawTag.scala @@ -265,7 +265,7 @@ case class CanonicalizeTag(operand: ValueRaw, exportTo: Call.Export) extends Raw override def renameExports(map: Map[String, String]): RawTag = copy(exportTo = exportTo.mapName(n => map.getOrElse(n, n))) - override def toString: String = s"(can $operand $exportTo)" + override def toString: String = s"(canon $operand $exportTo)" } case class JoinTag(operands: NonEmptyList[ValueRaw]) extends RawTag { @@ -275,3 +275,12 @@ case class JoinTag(operands: NonEmptyList[ValueRaw]) extends RawTag { override def toString: String = s"(join ${operands.toList.mkString(" ")})" } + +case class FailTag(error: ValueRaw) extends RawTag { + + override def mapValues(f: ValueRaw => ValueRaw): RawTag = + FailTag(f(error)) + + override def toString(): String = + s"(fail $error)" +} diff --git a/model/transform/src/main/scala/aqua/model/transform/Transform.scala b/model/transform/src/main/scala/aqua/model/transform/Transform.scala index b717dcd04..86d0e4242 100644 --- a/model/transform/src/main/scala/aqua/model/transform/Transform.scala +++ b/model/transform/src/main/scala/aqua/model/transform/Transform.scala @@ -113,6 +113,8 @@ object Transform extends Logging { conf.respFuncName ) + println(func.body.show) + for { // Pre transform and inline the function model <- funcToModelTree(func, preTransformer) diff --git a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala index 64ffb14f4..c99313040 100644 --- a/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala +++ b/parser/src/main/scala/aqua/parser/expr/func/ArrowExpr.scala @@ -32,6 +32,7 @@ object ArrowExpr extends Expr.AndIndented { Expr.defer(ParExpr) :: Expr.defer(CoExpr) :: Expr.defer(JoinExpr) :: + Expr.defer(FailExpr) :: DeclareStreamExpr :: Expr.defer(ClosureExpr) :: AssignmentExpr :: diff --git a/parser/src/main/scala/aqua/parser/expr/func/FailExpr.scala b/parser/src/main/scala/aqua/parser/expr/func/FailExpr.scala new file mode 100644 index 000000000..88ea45fc4 --- /dev/null +++ b/parser/src/main/scala/aqua/parser/expr/func/FailExpr.scala @@ -0,0 +1,26 @@ +package aqua.parser.expr.func + +import aqua.parser.Expr +import aqua.parser.lexer.ValueToken +import aqua.parser.lift.Span.S +import aqua.parser.lexer.Token.* + +import cats.Comonad +import cats.arrow.FunctionK +import cats.parse.Parser + +final case class FailExpr[F[_]]( + value: ValueToken[F] +) extends Expr[F](FailExpr, value) { + + override def mapK[K[_]: Comonad](fk: FunctionK[F, K]): Expr[K] = + FailExpr[K](value.mapK(fk)) + +} + +object FailExpr extends Expr.Leaf { + + override def p: Parser[Expr[S]] = + (`fail` *> ` ` *> ValueToken.`value`).map(FailExpr.apply) + +} diff --git a/parser/src/main/scala/aqua/parser/lexer/Token.scala b/parser/src/main/scala/aqua/parser/lexer/Token.scala index 7476b5016..044170f30 100644 --- a/parser/src/main/scala/aqua/parser/lexer/Token.scala +++ b/parser/src/main/scala/aqua/parser/lexer/Token.scala @@ -65,6 +65,7 @@ object Token { val `par`: P[Unit] = P.string("par") val `co`: P[Unit] = P.string("co") val `join`: P[Unit] = P.string("join") + val `fail`: P[Unit] = P.string("fail") val `copy`: P[Unit] = P.string("copy") val `:` : P[Unit] = P.char(':') val ` : ` : P[Unit] = P.char(':').surroundedBy(` `.?) @@ -117,9 +118,11 @@ object Token { val `/s*` : P0[Unit] = ` \n+`.backtrack | ` *`.void val namedArg: P[(String, ValueToken[S])] = - P.defer(`name`.between(` *`, `/s*`) ~ - `=`.between(` *`, `/s*`).void ~ - ValueToken.`value`.between(` *`, `/s*`)).map { case ((name, _), vt) => + P.defer( + `name`.between(` *`, `/s*`) ~ + `=`.between(` *`, `/s*`).void ~ + ValueToken.`value`.between(` *`, `/s*`) + ).map { case ((name, _), vt) => (name, vt) } diff --git a/semantics/src/main/scala/aqua/semantics/ExprSem.scala b/semantics/src/main/scala/aqua/semantics/ExprSem.scala index 5b8c12b6c..76faade27 100644 --- a/semantics/src/main/scala/aqua/semantics/ExprSem.scala +++ b/semantics/src/main/scala/aqua/semantics/ExprSem.scala @@ -48,6 +48,7 @@ object ExprSem { case expr: ElseOtherwiseExpr[S] => new ElseOtherwiseSem(expr).program[G] case expr: ParExpr[S] => new ParSem(expr).program[G] case expr: CoExpr[S] => new CoSem(expr).program[G] + case expr: FailExpr[S] => new FailSem(expr).program[G] case expr: JoinExpr[S] => new JoinSem(expr).program[G] case expr: ReturnExpr[S] => new ReturnSem(expr).program[G] case expr: ServiceExpr[S] => new ServiceSem(expr).program[G] diff --git a/semantics/src/main/scala/aqua/semantics/expr/func/FailSem.scala b/semantics/src/main/scala/aqua/semantics/expr/func/FailSem.scala new file mode 100644 index 000000000..09b635597 --- /dev/null +++ b/semantics/src/main/scala/aqua/semantics/expr/func/FailSem.scala @@ -0,0 +1,36 @@ +package aqua.semantics.expr.func + +import aqua.parser.expr.func.FailExpr +import aqua.semantics.rules.ValuesAlgebra +import aqua.semantics.rules.types.TypesAlgebra +import aqua.semantics.Prog +import aqua.raw.Raw +import aqua.types.ScalarType +import aqua.raw.ops.FailTag + +import cats.Monad +import cats.syntax.flatMap.* +import cats.syntax.functor.* +import cats.syntax.traverse.* + +class FailSem[S[_]](val expr: FailExpr[S]) extends AnyVal { + + def program[Alg[_]: Monad](implicit + V: ValuesAlgebra[S, Alg], + T: TypesAlgebra[S, Alg] + ): Prog[Alg, Raw] = for { + maybeValue <- V.valueToRaw(expr.value) + result <- maybeValue.traverse(vr => + T.ensureTypeMatches( + token = expr.value, + expected = ScalarType.string, + givenType = vr.`type` + ).map(isStr => + if (isStr) FailTag(vr).funcOpLeaf + else Raw.error("Argument of `fail` is not a string") + ) + ) + } yield result.getOrElse( + Raw.error("Resolution for `fail` argument failed") + ) +}