Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(compiler): Add fail statement [fixes LNG-98] #769

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion model/raw/src/main/scala/aqua/raw/ops/RawTag.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ::
Expand Down
26 changes: 26 additions & 0 deletions parser/src/main/scala/aqua/parser/expr/func/FailExpr.scala
Original file line number Diff line number Diff line change
@@ -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)

}
9 changes: 6 additions & 3 deletions parser/src/main/scala/aqua/parser/lexer/Token.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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(` `.?)
Expand Down Expand Up @@ -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)
}

Expand Down
1 change: 1 addition & 0 deletions semantics/src/main/scala/aqua/semantics/ExprSem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
36 changes: 36 additions & 0 deletions semantics/src/main/scala/aqua/semantics/expr/func/FailSem.scala
Original file line number Diff line number Diff line change
@@ -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")
)
}