mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Types interpreter
This commit is contained in:
parent
ab4a26ee96
commit
401b7a31df
@ -14,6 +14,12 @@ abstract class StackInterpreter[F[_], X, St, Fr](stackLens: Lens[St, List[Fr]])(
|
||||
protected def getState: S[St] = State.get.map(lens.get)
|
||||
protected def setState(st: St): S[Unit] = State.modify(s => lens.replace(st)(s))
|
||||
|
||||
protected def report(t: Token[F], hint: String): S[Unit] =
|
||||
State.modify(error(_, t, hint))
|
||||
|
||||
protected def modify(f: St => St): S[Unit] =
|
||||
State.modify(lens.modify(f))
|
||||
|
||||
protected def mapStackHead[A](ifStackEmpty: S[A])(f: Fr => (Fr, A)): S[A] =
|
||||
getState.map(stackLens.get).flatMap {
|
||||
case h :: tail =>
|
||||
@ -38,12 +44,6 @@ abstract class StackInterpreter[F[_], X, St, Fr](stackLens: Lens[St, List[Fr]])(
|
||||
ifStackEmpty
|
||||
}
|
||||
|
||||
protected def report(t: Token[F], hint: String): S[Unit] =
|
||||
State.modify(error(_, t, hint))
|
||||
|
||||
protected def modify(f: St => St): S[Unit] =
|
||||
State.modify(lens.modify(f))
|
||||
|
||||
protected def endScope: S[Unit] =
|
||||
modify(stackLens.modify(_.tail))
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
package aqua.ast.algebra.types
|
||||
|
||||
import aqua.parser.lexer.{ArrowDef, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
|
||||
sealed trait TypeOp[F[_], T]
|
||||
|
||||
case class ResolveType[F[_]](token: TypeToken[F]) extends TypeOp[F, Type]
|
||||
case class ResolveArrowDef[F[_]](arrowDef: ArrowDef[F]) extends TypeOp[F, ArrowType]
|
||||
case class ResolveType[F[_]](token: TypeToken[F]) extends TypeOp[F, Option[Type]]
|
||||
case class ResolveArrowDef[F[_]](arrowDef: ArrowTypeToken[F]) extends TypeOp[F, Option[ArrowType]]
|
||||
|
||||
case class DefineField[F[_]](name: Name[F], `type`: Type) extends TypeOp[F, Unit]
|
||||
case class PurgeFields[F[_]]() extends TypeOp[F, NonEmptyList[(Name[F], Type)]]
|
||||
case class DefineDataType[F[_]](name: CustomTypeToken[F], fields: NonEmptyMap[String, Type]) extends TypeOp[F, Unit]
|
||||
case class DefineAlias[F[_]](name: CustomTypeToken[F], target: Type) extends TypeOp[F, Unit]
|
||||
case class DefineField[F[_]](name: Name[F], `type`: Type) extends TypeOp[F, Boolean]
|
||||
case class PurgeFields[F[_]](token: Token[F]) extends TypeOp[F, Option[NonEmptyMap[String, Type]]]
|
||||
case class DefineDataType[F[_]](name: CustomTypeToken[F], fields: NonEmptyMap[String, Type]) extends TypeOp[F, Boolean]
|
||||
case class DefineAlias[F[_]](name: CustomTypeToken[F], target: Type) extends TypeOp[F, Boolean]
|
||||
|
||||
case class ResolveLambda[F[_]](root: Type, ops: List[LambdaOp[F]]) extends TypeOp[F, Option[Type]]
|
||||
case class EnsureTypeMatches[F[_]](token: Token[F], expected: Type, given: Type) extends TypeOp[F, Boolean]
|
||||
|
@ -1,28 +1,28 @@
|
||||
package aqua.ast.algebra.types
|
||||
|
||||
import aqua.parser.lexer.{ArrowDef, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import aqua.parser.lexer.{ArrowDef, ArrowTypeToken, CustomTypeToken, LambdaOp, Name, Token, TypeToken}
|
||||
import cats.InjectK
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.free.Free
|
||||
|
||||
class TypesAlgebra[F[_], Alg[_]](implicit T: InjectK[TypeOp[F, *], Alg]) {
|
||||
|
||||
def resolveType(token: TypeToken[F]): Free[Alg, Type] =
|
||||
def resolveType(token: TypeToken[F]): Free[Alg, Option[Type]] =
|
||||
Free.liftInject[Alg](ResolveType(token))
|
||||
|
||||
def resolveArrowDef(arrowDef: ArrowDef[F]): Free[Alg, ArrowType] =
|
||||
def resolveArrowDef(arrowDef: ArrowTypeToken[F]): Free[Alg, Option[ArrowType]] =
|
||||
Free.liftInject[Alg](ResolveArrowDef(arrowDef))
|
||||
|
||||
def defineField(name: Name[F], `type`: Type): Free[Alg, Unit] =
|
||||
def defineField(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineField[F](name, `type`))
|
||||
|
||||
def purgeFields(): Free[Alg, NonEmptyList[(Name[F], Type)]] =
|
||||
Free.liftInject[Alg](PurgeFields[F]())
|
||||
def purgeFields(token: Token[F]): Free[Alg, Option[NonEmptyMap[String, Type]]] =
|
||||
Free.liftInject[Alg](PurgeFields[F](token))
|
||||
|
||||
def defineDataType(name: CustomTypeToken[F], fields: NonEmptyMap[String, Type]): Free[Alg, Unit] =
|
||||
def defineDataType(name: CustomTypeToken[F], fields: NonEmptyMap[String, Type]): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineDataType(name, fields))
|
||||
|
||||
def defineAlias(name: CustomTypeToken[F], target: Type): Free[Alg, Unit] =
|
||||
def defineAlias(name: CustomTypeToken[F], target: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineAlias(name, target))
|
||||
|
||||
def resolveLambda(root: Type, ops: List[LambdaOp[F]]): Free[Alg, Option[Type]] =
|
||||
|
159
src/main/scala/aqua/ast/algebra/types/TypesInterpreter.scala
Normal file
159
src/main/scala/aqua/ast/algebra/types/TypesInterpreter.scala
Normal file
@ -0,0 +1,159 @@
|
||||
package aqua.ast.algebra.types
|
||||
|
||||
import aqua.ast.algebra.ReportError
|
||||
import aqua.context.VarTypes.{Err, ExpectedProduct, FieldNotFound, NotAnArray}
|
||||
import aqua.parser.lexer.{
|
||||
ArrayTypeToken,
|
||||
ArrowDef,
|
||||
ArrowTypeToken,
|
||||
BasicTypeToken,
|
||||
CustomTypeToken,
|
||||
IntoArray,
|
||||
IntoField,
|
||||
LambdaOp,
|
||||
Name,
|
||||
Token,
|
||||
TypeToken
|
||||
}
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State, Validated, ValidatedNel}
|
||||
import cats.free.Free
|
||||
import cats.{~>, Comonad}
|
||||
import monocle.Lens
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.flatMap._
|
||||
|
||||
import scala.collection.immutable.{Queue, SortedMap}
|
||||
|
||||
class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: ReportError[F, X])
|
||||
extends (TypeOp[F, *] ~> State[X, *]) {
|
||||
|
||||
type S[A] = State[X, A]
|
||||
type St = TypesState[F]
|
||||
|
||||
protected def getState: S[St] = State.get.map(lens.get)
|
||||
protected def setState(st: St): S[Unit] = State.modify(s => lens.replace(st)(s))
|
||||
|
||||
protected def report(t: Token[F], hint: String): S[Unit] =
|
||||
State.modify(error(_, t, hint))
|
||||
|
||||
protected def modify(f: St => St): S[Unit] =
|
||||
State.modify(lens.modify(f))
|
||||
|
||||
override def apply[A](fa: TypeOp[F, A]): State[X, A] =
|
||||
fa match {
|
||||
case rt: ResolveType[F] =>
|
||||
getState.map(_.resolveTypeToken(rt.token)).flatMap {
|
||||
case Some(t) => State.pure(Some(t))
|
||||
case None => report(rt.token, s"Unresolved type").as(None)
|
||||
}
|
||||
case ra: ResolveArrowDef[F] =>
|
||||
getState.map(_.resolveArrowDef(ra.arrowDef)).flatMap {
|
||||
case Valid(t) => State.pure[X, Option[ArrowType]](Some(t))
|
||||
case Invalid(errs) =>
|
||||
errs
|
||||
.foldLeft[S[Option[ArrowType]]](State.pure(None)) {
|
||||
case (n, (tkn, hint)) => report(tkn, hint) >> n
|
||||
}
|
||||
}
|
||||
|
||||
case df: DefineField[F] =>
|
||||
getState.map(_.fields.get(df.name.value)).flatMap {
|
||||
case None =>
|
||||
modify(st => st.copy(fields = st.fields.updated(df.name.value, df.name -> df.`type`))).as(true)
|
||||
case Some(_) =>
|
||||
report(df.name, s"Cannot define field `${df.name.value}`, it was already defined above").as(false)
|
||||
}
|
||||
case pf: PurgeFields[F] =>
|
||||
getState.map(_.fields.view.mapValues(_._2)).map(SortedMap.from(_)).map(NonEmptyMap.fromMap(_)).flatMap {
|
||||
case Some(fs) => modify(_.copy(fields = Map.empty)).as(Some(fs))
|
||||
case None => report(pf.token, "Cannot define a data type without fields").as(None)
|
||||
}
|
||||
|
||||
case ddt: DefineDataType[F] =>
|
||||
getState.map(_.isDefined(ddt.name.value)).flatMap {
|
||||
case true => report(ddt.name, s"Type `${ddt.name.value}` was already defined").as(false)
|
||||
case false =>
|
||||
modify(st => st.copy(strict = st.strict.updated(ddt.name.value, ProductType(ddt.name.value, ddt.fields))))
|
||||
.as(true)
|
||||
}
|
||||
|
||||
case da: DefineAlias[F] =>
|
||||
getState.map(_.isDefined(da.name.value)).flatMap {
|
||||
case true => report(da.name, s"Type `${da.name.value}` was already defined").as(false)
|
||||
case false => modify(st => st.copy(strict = st.strict.updated(da.name.value, da.target))).as(true)
|
||||
}
|
||||
|
||||
case rl: ResolveLambda[F] =>
|
||||
getState.map(_.resolveOps(rl.root, rl.ops)).flatMap {
|
||||
case Left((tkn, hint)) => report(tkn, hint).as(None)
|
||||
case Right(t) => State.pure(Some(t))
|
||||
}
|
||||
|
||||
case etm: EnsureTypeMatches[F] =>
|
||||
if (etm.expected.acceptsValueOf(etm.`given`)) State.pure(true)
|
||||
else report(etm.token, s"Types mismatch, expected: ${etm.expected}, given: ${etm.`given`}").as(false)
|
||||
}
|
||||
}
|
||||
|
||||
case class TypesState[F[_]](
|
||||
fields: Map[String, (Name[F], Type)],
|
||||
strict: Map[String, Type]
|
||||
) {
|
||||
def isDefined(t: String): Boolean = strict.contains(t)
|
||||
|
||||
def resolveTypeToken(tt: TypeToken[F]): Option[Type] =
|
||||
tt match {
|
||||
case ArrayTypeToken(_, dtt) =>
|
||||
resolveTypeToken(dtt).collect {
|
||||
case it: DataType => ArrayType(it)
|
||||
}
|
||||
case ctt: CustomTypeToken[F] => strict.get(ctt.value)
|
||||
case btt: BasicTypeToken[F] => Some(btt.value)
|
||||
case ArrowTypeToken(_, args, res) =>
|
||||
val strictArgs = args.map(resolveTypeToken).collect {
|
||||
case Some(dt: DataType) => dt
|
||||
}
|
||||
val strictRes = res.flatMap(resolveTypeToken).collect {
|
||||
case dt: DataType => dt
|
||||
}
|
||||
Option.when(strictRes.isDefined == res.isDefined && strictArgs.length == args.length)(
|
||||
ArrowType(strictArgs, strictRes)
|
||||
)
|
||||
}
|
||||
|
||||
def resolveArrowDef(ad: ArrowTypeToken[F]): ValidatedNel[(Token[F], String), ArrowType] =
|
||||
ad.resType.flatMap(resolveTypeToken) match {
|
||||
case resType if resType.isDefined == ad.resType.isDefined =>
|
||||
val (errs, argTypes) = ad.argTypes
|
||||
.map(tt => resolveTypeToken(tt).toRight(tt -> s"Type unresolved"))
|
||||
.foldLeft[(Queue[(Token[F], String)], Queue[Type])]((Queue.empty, Queue.empty)) {
|
||||
case ((errs, argTypes), Right(at)) => (errs, argTypes.enqueue(at))
|
||||
case ((errs, argTypes), Left(e)) => (errs.enqueue(e), argTypes)
|
||||
}
|
||||
|
||||
NonEmptyList
|
||||
.fromList(errs.toList)
|
||||
.fold[ValidatedNel[(Token[F], String), ArrowType]](Valid(ArrowType(argTypes.toList, resType)))(Invalid(_))
|
||||
|
||||
case _ => Invalid(NonEmptyList.of(ad.resType.getOrElse(ad) -> "Cannot resolve the result type"))
|
||||
}
|
||||
|
||||
def resolveOps(rootT: Type, ops: List[LambdaOp[F]]): Either[(Token[F], String), Type] =
|
||||
ops.headOption.fold[Either[(Token[F], String), Type]](Right(rootT)) {
|
||||
case i @ IntoArray(f) =>
|
||||
rootT match {
|
||||
case ArrayType(intern) => resolveOps(intern, ops.tail).map[Type](ArrayType)
|
||||
case _ => Left(i -> s"Expected $rootT to be an array")
|
||||
}
|
||||
case i @ IntoField(name) =>
|
||||
rootT match {
|
||||
case pt @ ProductType(_, fields) =>
|
||||
fields(i.value)
|
||||
.toRight(i -> s"Field `${i.value}` not found in type `${pt.name}``")
|
||||
.flatMap(resolveOps(_, ops.tail))
|
||||
case _ => Left(i -> s"Expected product to resolve a field, got $rootT")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -6,15 +6,17 @@ import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{CustomTypeToken, TypeToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
for {
|
||||
t <- T.resolveType(target)
|
||||
_ <- T.defineAlias(name, t)
|
||||
} yield Gen.noop
|
||||
T.resolveType(target).flatMap {
|
||||
case Some(t) => T.defineAlias(name, t).as(Gen.noop)
|
||||
case None => Free.pure(Gen.noop)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,17 @@ import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{ArrowTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg], A: AbilitiesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
for {
|
||||
t <- T.resolveArrowDef(`type`)
|
||||
_ <- A.defineArrow(name, t)
|
||||
} yield Gen.noop
|
||||
T.resolveArrowDef(`type`).flatMap {
|
||||
case Some(t) => A.defineArrow(name, t).as(Gen.noop)
|
||||
case None => Free.pure(Gen.noop)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import aqua.parser.lexer.CustomTypeToken
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
@ -17,10 +18,11 @@ case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F] {
|
||||
T: TypesAlgebra[F, Alg]
|
||||
): Prog[Alg, Gen] =
|
||||
Prog after T
|
||||
.purgeFields()
|
||||
.map(_.map(kv => kv._1.value -> kv._2).toNem)
|
||||
.flatMap(T.defineDataType(name, _))
|
||||
.as(Gen("Data struct created"))
|
||||
.purgeFields(name)
|
||||
.flatMap {
|
||||
case Some(fields) => T.defineDataType(name, fields).as(Gen("Data struct created"))
|
||||
case None => Free.pure(Gen.noop)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,15 +6,17 @@ import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{DataTypeToken, Name}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
import cats.free.Free
|
||||
import cats.parse.Parser
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends Expr[F] {
|
||||
|
||||
def program[Alg[_]](implicit T: TypesAlgebra[F, Alg]): Prog[Alg, Gen] =
|
||||
for {
|
||||
t <- T.resolveType(`type`)
|
||||
_ <- T.defineField(name, t)
|
||||
} yield Gen.noop
|
||||
T.resolveType(`type`).flatMap {
|
||||
case Some(t) => T.defineField(name, t).as(Gen.noop)
|
||||
case None => Free.pure(Gen.noop)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -36,16 +36,17 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
|
||||
) {
|
||||
case (f, Arg(argName, argType)) =>
|
||||
// Resolve arg type, remember it
|
||||
for {
|
||||
acc <- f
|
||||
t <- T.resolveType(argType)
|
||||
_ <- N.define(argName, t)
|
||||
} yield acc.enqueue(t)
|
||||
f.flatMap(acc =>
|
||||
T.resolveType(argType).flatMap {
|
||||
case Some(t) => N.define(argName, t).as(acc.enqueue(t))
|
||||
case None => Free.pure(acc)
|
||||
}
|
||||
)
|
||||
}
|
||||
.map(_.toList),
|
||||
// Resolve return type
|
||||
// TODO handle return VALUE!
|
||||
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_).map(Some(_)))
|
||||
ret.fold(Free.pure[Alg, Option[Type]](None))(T.resolveType(_))
|
||||
)
|
||||
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2)),
|
||||
(funcArrow: ArrowType, bodyGen: Gen) =>
|
||||
|
Loading…
Reference in New Issue
Block a user