throw an error if assign to a variable result of a function that returns nothing. refactoring (#174)

This commit is contained in:
Dima 2021-06-18 11:13:54 +03:00 committed by GitHub
parent 8586d70364
commit 896cf7a228
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 36 deletions

View File

@ -9,12 +9,13 @@ import aqua.semantics.rules.ValuesAlgebra
import aqua.semantics.rules.abilities.AbilitiesAlgebra import aqua.semantics.rules.abilities.AbilitiesAlgebra
import aqua.semantics.rules.names.NamesAlgebra import aqua.semantics.rules.names.NamesAlgebra
import aqua.semantics.rules.types.TypesAlgebra import aqua.semantics.rules.types.TypesAlgebra
import aqua.types.{ArrowType, ScalarType, StreamType, Type} import aqua.types.{ArrowType, StreamType, Type}
import cats.Traverse import cats.Traverse
import cats.free.Free import cats.free.Free
import cats.syntax.apply._ import cats.syntax.apply._
import cats.syntax.flatMap._ import cats.syntax.flatMap._
import cats.syntax.functor._ import cats.syntax.functor._
import cats.syntax.traverse._
class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal { class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
@ -57,39 +58,49 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
case (Some(at), Some(sid)) => case (Some(at), Some(sid)) =>
Option(at -> sid) // Here we assume that Ability is a Service that must be resolved Option(at -> sid) // Here we assume that Ability is a Service that must be resolved
case _ => None case _ => None
}.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { case (arrowType, serviceId) => }.flatMap(_.map { case (arrowType, serviceId) =>
checkArgsRes(arrowType).map { callServiceTag(arrowType, Option(serviceId))
case (argsResolved, t) => }.traverse(identity))
Option(
FuncOp.leaf(
CallServiceTag(
serviceId = serviceId,
funcName = funcName.value,
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
)
)
)
case _ => None
}
})
case None => case None =>
N.readArrow(funcName) N.readArrow(funcName)
.flatMap(_.fold(Free.pure[Alg, Option[FuncOp]](None)) { arrowType => .flatMap(_.map { arrowType =>
checkArgsRes(arrowType).map { case (argsResolved, t) => callServiceTag(arrowType, None)
FuncOp.leaf( }.traverse(identity))
CallArrowTag(
funcName = funcName.value,
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
)
)
}
.map(Option(_))
})
} }
def callServiceTag[Alg[_]](arrowType: ArrowType, serviceId: Option[ValueModel])(implicit
N: NamesAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg],
T: TypesAlgebra[F, Alg],
V: ValuesAlgebra[F, Alg]
): Free[Alg, FuncOp] = {
checkArgsRes(arrowType).flatMap { case (argsResolved, tOp) =>
((variable, tOp) match {
case (Some(v), Some(t)) =>
Free.pure[Alg, Option[Call.Export]](Option(Call.Export(v.value, t)))
case (Some(v), None) =>
T.expectNoExport(v).map(_ => None)
case _ =>
Free.pure[Alg, Option[Call.Export]](None)
}).map(call =>
FuncOp.leaf(serviceId match {
case Some(sid) =>
CallServiceTag(
serviceId = sid,
funcName = funcName.value,
Call(argsResolved, call)
)
case None =>
CallArrowTag(
funcName = funcName.value,
Call(argsResolved, call)
)
})
)
}
}
def program[Alg[_]](implicit def program[Alg[_]](implicit
N: NamesAlgebra[F, Alg], N: NamesAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg], A: AbilitiesAlgebra[F, Alg],

View File

@ -1,7 +1,7 @@
package aqua.semantics.rules.types package aqua.semantics.rules.types
import aqua.model.LambdaModel import aqua.model.LambdaModel
import aqua.parser.lexer.{ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken} import aqua.parser.lexer._
import aqua.types.{ArrowType, Type} import aqua.types.{ArrowType, Type}
import cats.data.NonEmptyMap import cats.data.NonEmptyMap
@ -23,5 +23,7 @@ case class ResolveLambda[F[_]](root: Type, ops: List[LambdaOp[F]])
case class EnsureTypeMatches[F[_]](token: Token[F], expected: Type, given: Type) case class EnsureTypeMatches[F[_]](token: Token[F], expected: Type, given: Type)
extends TypeOp[F, Boolean] extends TypeOp[F, Boolean]
case class ExpectNoExport[F[_]](token: Token[F]) extends TypeOp[F, Unit]
case class CheckArgumentsNum[F[_]](token: Token[F], expected: Int, given: Int) case class CheckArgumentsNum[F[_]](token: Token[F], expected: Int, given: Int)
extends TypeOp[F, Boolean] extends TypeOp[F, Boolean]

View File

@ -1,7 +1,7 @@
package aqua.semantics.rules.types package aqua.semantics.rules.types
import aqua.model.LambdaModel import aqua.model.LambdaModel
import aqua.parser.lexer.{ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken} import aqua.parser.lexer._
import aqua.types.{ArrowType, Type} import aqua.types.{ArrowType, Type}
import cats.InjectK import cats.InjectK
import cats.data.NonEmptyMap import cats.data.NonEmptyMap
@ -36,6 +36,9 @@ class TypesAlgebra[F[_], Alg[_]](implicit T: InjectK[TypeOp[F, *], Alg]) {
def ensureTypeMatches(token: Token[F], expected: Type, given: Type): Free[Alg, Boolean] = def ensureTypeMatches(token: Token[F], expected: Type, given: Type): Free[Alg, Boolean] =
Free.liftInject[Alg](EnsureTypeMatches[F](token, expected, given)) Free.liftInject[Alg](EnsureTypeMatches[F](token, expected, given))
def expectNoExport(token: Token[F]): Free[Alg, Unit] =
Free.liftInject[Alg](ExpectNoExport[F](token))
def checkArgumentsNumber(token: Token[F], expected: Int, given: Int): Free[Alg, Boolean] = def checkArgumentsNumber(token: Token[F], expected: Int, given: Int): Free[Alg, Boolean] =
Free.liftInject[Alg](CheckArgumentsNum(token, expected, given)) Free.liftInject[Alg](CheckArgumentsNum(token, expected, given))
} }

View File

@ -1,15 +1,14 @@
package aqua.semantics.rules.types package aqua.semantics.rules.types
import aqua.semantics.rules.ReportError
import aqua.parser.lexer.Token import aqua.parser.lexer.Token
import aqua.semantics.rules.ReportError
import aqua.types.{ArrowType, ProductType} import aqua.types.{ArrowType, ProductType}
import cats.data.Validated.{Invalid, Valid} import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyMap, State} import cats.data.{NonEmptyMap, State}
import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.~> import cats.~>
import monocle.Lens import monocle.Lens
import cats.syntax.functor._
import cats.syntax.flatMap._
import scala.collection.immutable.SortedMap import scala.collection.immutable.SortedMap
@ -105,6 +104,12 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
report(etm.token, s"Types mismatch, expected: ${etm.expected}, given: ${etm.`given`}") report(etm.token, s"Types mismatch, expected: ${etm.expected}, given: ${etm.`given`}")
.as(false) .as(false)
case ene: ExpectNoExport[F] =>
report(
ene.token,
"Types mismatch. Cannot assign to a variable the result of a call that returns nothing"
).as(())
case ca: CheckArgumentsNum[F] => case ca: CheckArgumentsNum[F] =>
if (ca.expected == ca.given) State.pure(true) if (ca.expected == ca.given) State.pure(true)
else else