mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Type checker works
This commit is contained in:
parent
e33b499c42
commit
6b1f7dd0af
@ -1,43 +1,15 @@
|
||||
package aqua
|
||||
|
||||
import aqua.context.{Abilities, AbilitiesResolve, ArgsAndVars, Arrows, Types, VarTypes}
|
||||
import aqua.context.scope.ScopeWalker
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
import cats.parse.{Parser => P, Parser0 => P0}
|
||||
import aqua.ast.{Ast, Gen}
|
||||
import cats.data.ValidatedNel
|
||||
import aqua.parser.lift.Span
|
||||
import cats.data.Validated.Valid
|
||||
import shapeless.HNil
|
||||
|
||||
object Aqua {
|
||||
private val parser: P0[List[Block[Span.F, HNil]]] = Block.blocks[Span.F]
|
||||
|
||||
val step1 =
|
||||
Walker
|
||||
.hnil[Span.F]
|
||||
.andThen(new ScopeWalker(_))
|
||||
.andThen(new Arrows.ExpDef(_))
|
||||
.andThen(new ArgsAndVars.ExpDef(_))
|
||||
.andThen(new Types.ExpDef(_))
|
||||
.andThen(new Abilities.ExpDef(_))
|
||||
.andThen(new AbilitiesResolve.ExpDef(_))
|
||||
def parse(input: String): ValidatedNel[AquaError, Ast[Span.F]] =
|
||||
Ast.fromString[Span.F](input)
|
||||
|
||||
val step2 =
|
||||
new VarTypes.Checker[Span.F, step1.Out, step1.Out](Walker.noopFrom(step1))
|
||||
def compile(input: String): ValidatedNel[AquaError, Gen] =
|
||||
parse(input).andThen(ast => Compiler.compile(ast).leftMap(_.map(ts => CompilerError(ts._1.unit._1, ts._2))))
|
||||
|
||||
def parse(input: String): ValidatedNel[AquaError, List[Block[Span.F, step2.Out]]] =
|
||||
Validated
|
||||
.fromEither(
|
||||
parser
|
||||
.parseAll(input)
|
||||
.left
|
||||
.map(pe => NonEmptyList.one[AquaError](SyntaxError(pe.failedAtOffset, pe.expected)))
|
||||
)
|
||||
.andThen { blocks =>
|
||||
step1.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => CompilerError(sv._1, sv._2)))
|
||||
}
|
||||
.andThen { blocks =>
|
||||
step2.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => CompilerError(sv._1, sv._2)))
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,5 @@
|
||||
package aqua
|
||||
|
||||
import aqua.context.Types
|
||||
import aqua.ast.algebra.names.NameOp
|
||||
import aqua.ast.{Ast, Expr}
|
||||
import aqua.parser.lift.Span
|
||||
import cats.Eval
|
||||
import cats.effect.{IO, IOApp}
|
||||
import cats.data.Validated
|
||||
|
||||
@ -14,8 +9,8 @@ object Main extends IOApp.Simple {
|
||||
|
||||
override def run: IO[Unit] =
|
||||
IO {
|
||||
def tryParse(str: String) =
|
||||
Aqua.parse(str) match {
|
||||
def process(str: String) =
|
||||
Aqua.compile(str) match {
|
||||
case Validated.Valid(v) ⇒
|
||||
println(v)
|
||||
println(Console.GREEN + "Aqua script processed successfully" + Console.RESET)
|
||||
@ -25,18 +20,7 @@ object Main extends IOApp.Simple {
|
||||
}
|
||||
|
||||
val script = Source.fromResource("typecheck.aqua").mkString
|
||||
//tryParse(experimental)
|
||||
|
||||
val ast = Ast
|
||||
.fromString[Span.F](script)
|
||||
.andThen(
|
||||
Compiler
|
||||
.compile[Span.F](_)
|
||||
.leftMap(_.map(ts => CompilerError(ts._1.unit._1, ts._2)))
|
||||
)
|
||||
.leftMap(_.map(_.showForConsole(script)).map(println))
|
||||
|
||||
ast.map(println(_))
|
||||
process(script)
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ case class ReadName[F[_]](name: Name[F]) extends NameOp[F, Option[Type]]
|
||||
|
||||
case class ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowType]]
|
||||
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
|
||||
case class DefineName[F[_]](name: Name[F], `type`: Type, isRoot: Boolean) extends NameOp[F, Boolean]
|
||||
|
||||
case class BeginScope[F[_]](token: Token[F]) extends NameOp[F, Unit]
|
||||
|
||||
|
@ -13,8 +13,8 @@ class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
|
||||
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
|
||||
Free.liftInject[Alg](ReadArrow(name))
|
||||
|
||||
def define(name: Name[F], `type`: Type): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`))
|
||||
def define(name: Name[F], `type`: Type, isRoot: Boolean = false): Free[Alg, Boolean] =
|
||||
Free.liftInject[Alg](DefineName(name, `type`, isRoot))
|
||||
|
||||
def beginScope(token: Token[F]): Free[Alg, Unit] =
|
||||
Free.liftInject[Alg](BeginScope(token))
|
||||
|
@ -16,9 +16,11 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
with (NameOp[F, *] ~> State[X, *]) {
|
||||
|
||||
def readName(name: String): S[Option[Type]] =
|
||||
getState.map(_.stack.collectFirst {
|
||||
case frame if frame.names.contains(name) => frame.names(name)
|
||||
})
|
||||
getState.map { st =>
|
||||
st.stack.collectFirst {
|
||||
case frame if frame.names.contains(name) => frame.names(name)
|
||||
} orElse st.rootNames.get(name)
|
||||
}
|
||||
|
||||
override def apply[A](fa: NameOp[F, A]): State[X, A] =
|
||||
(fa match {
|
||||
@ -40,9 +42,10 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
readName(dn.name.value).flatMap {
|
||||
case Some(_) => report(dn.name, "This name was already defined in the scope").as(false)
|
||||
case None =>
|
||||
mapStackHead(report(dn.name, "Cannot define a variable in the root scope").as(false))(
|
||||
_.focus(_.names).index(dn.name.value).replace(dn.`type`) -> true
|
||||
)
|
||||
mapStackHead(
|
||||
if (dn.isRoot) modify(_.focus(_.rootNames).index(dn.name.value).replace(dn.`type`)).as(true)
|
||||
else report(dn.name, "Cannot define a variable in the root scope").as(false)
|
||||
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
|
||||
}
|
||||
case bs: BeginScope[F] =>
|
||||
beginScope(NamesFrame(bs.token))
|
||||
@ -51,6 +54,8 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
|
||||
}).asInstanceOf[State[X, A]]
|
||||
}
|
||||
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil)
|
||||
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootNames: Map[String, Type] = Map.empty)
|
||||
|
||||
case class NamesFrame[F[_]](token: Token[F], names: Map[String, Type] = Map.empty)
|
||||
case class NamesFrame[F[_]](token: Token[F], names: Map[String, Type] = Map.empty) {
|
||||
def addName(n: String, t: Type): NamesFrame[F] = copy[F](names = names.updated(n, t))
|
||||
}
|
||||
|
@ -15,7 +15,9 @@ sealed trait Type {
|
||||
}
|
||||
sealed trait DataType extends Type
|
||||
|
||||
case class ScalarType private (name: String) extends DataType
|
||||
case class ScalarType private (name: String) extends DataType {
|
||||
override def toString: String = name
|
||||
}
|
||||
|
||||
object ScalarType {
|
||||
// TODO https://github.com/fluencelabs/interface-types/blob/master/crates/it-types/src/values.rs#L45-L49
|
||||
@ -46,18 +48,27 @@ object ScalarType {
|
||||
}
|
||||
}
|
||||
|
||||
case class LiteralType private (oneOf: Set[ScalarType]) extends Type
|
||||
|
||||
object LiteralType {
|
||||
val float = LiteralType(ScalarType.float)
|
||||
val signed = LiteralType(ScalarType.signed)
|
||||
val number = LiteralType(ScalarType.number)
|
||||
val bool = LiteralType(Set(ScalarType.bool))
|
||||
val string = LiteralType(Set(ScalarType.string))
|
||||
case class LiteralType private (oneOf: Set[ScalarType], name: String) extends Type {
|
||||
override def toString: String = name
|
||||
}
|
||||
|
||||
case class ArrayType(element: Type) extends DataType
|
||||
case class ProductType(name: String, fields: NonEmptyMap[String, Type]) extends DataType
|
||||
object LiteralType {
|
||||
val float = LiteralType(ScalarType.float, "float")
|
||||
val signed = LiteralType(ScalarType.signed, "signed")
|
||||
val number = LiteralType(ScalarType.number, "number")
|
||||
val bool = LiteralType(Set(ScalarType.bool), "bool")
|
||||
val string = LiteralType(Set(ScalarType.string), "string")
|
||||
}
|
||||
|
||||
case class ArrayType(element: Type) extends DataType {
|
||||
override def toString: String = "[]" + element
|
||||
}
|
||||
|
||||
case class ProductType(name: String, fields: NonEmptyMap[String, Type]) extends DataType {
|
||||
|
||||
override def toString: String =
|
||||
s"$name{${fields.map(_.toString).toNel.toList.map(kv => kv._1 + ": " + kv._2).mkString(", ")}}"
|
||||
}
|
||||
|
||||
sealed trait CallableType extends Type {
|
||||
def acceptsAsArguments(valueTypes: List[Type]): Boolean
|
||||
@ -70,16 +81,7 @@ case class ArrowType(args: List[Type], res: Option[Type]) extends CallableType {
|
||||
override def acceptsAsArguments(valueTypes: List[Type]): Boolean =
|
||||
(args.length == valueTypes.length) && args.zip(valueTypes).forall(av => av._1.acceptsValueOf(av._2))
|
||||
|
||||
}
|
||||
|
||||
case class FuncArrowType(funcArgs: List[(String, Type)], res: Option[Type]) extends CallableType {
|
||||
|
||||
lazy val toArrowType: ArrowType = ArrowType(funcArgs.map(_._2), res)
|
||||
|
||||
override def acceptsAsArguments(valueTypes: List[Type]): Boolean =
|
||||
toArrowType.acceptsAsArguments(valueTypes)
|
||||
|
||||
override def args: List[Type] = toArrowType.args
|
||||
override def toString: String = args.map(_.toString).mkString(", ") + " -> " + res.map(_.toString).getOrElse("()")
|
||||
}
|
||||
|
||||
object Type {
|
||||
@ -119,10 +121,10 @@ object Type {
|
||||
else
|
||||
(l, r) match {
|
||||
case (x: ScalarType, y: ScalarType) => ScalarType.scalarOrder.partialCompare(x, y)
|
||||
case (LiteralType(xs), y: ScalarType) if xs == Set(y) => 0.0
|
||||
case (LiteralType(xs), y: ScalarType) if xs(y) => -1.0
|
||||
case (x: ScalarType, LiteralType(ys)) if ys == Set(x) => 0.0
|
||||
case (x: ScalarType, LiteralType(ys)) if ys(x) => 1.0
|
||||
case (LiteralType(xs, _), y: ScalarType) if xs == Set(y) => 0.0
|
||||
case (LiteralType(xs, _), y: ScalarType) if xs(y) => -1.0
|
||||
case (x: ScalarType, LiteralType(ys, _)) if ys == Set(x) => 0.0
|
||||
case (x: ScalarType, LiteralType(ys, _)) if ys(x) => 1.0
|
||||
case (x: ArrayType, y: ArrayType) => cmp(x.element, y.element)
|
||||
case (ProductType(_, xFields), ProductType(_, yFields)) =>
|
||||
cmpProd(xFields, yFields)
|
||||
|
@ -1,10 +1,8 @@
|
||||
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,
|
||||
@ -16,9 +14,8 @@ import aqua.parser.lexer.{
|
||||
TypeToken
|
||||
}
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State, Validated, ValidatedNel}
|
||||
import cats.free.Free
|
||||
import cats.{~>, Comonad}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap, State, ValidatedNel}
|
||||
import cats.~>
|
||||
import monocle.Lens
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.flatMap._
|
||||
|
@ -37,8 +37,10 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
|
||||
// Resolve arg type, remember it
|
||||
f.flatMap(acc =>
|
||||
T.resolveType(argType).flatMap {
|
||||
case Some(t) => N.define(argName, t).as(acc.enqueue(t))
|
||||
case None => Free.pure(acc)
|
||||
case Some(t) =>
|
||||
N.define(argName, t).as(acc.enqueue(t))
|
||||
case None =>
|
||||
Free.pure(acc)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -50,7 +52,9 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
|
||||
.map(argsAndRes => ArrowType(argsAndRes._1, argsAndRes._2)),
|
||||
(funcArrow: ArrowType, bodyGen: Gen) =>
|
||||
// Erase arguments and internal variables
|
||||
A.endScope() >> N.endScope() >> N.define(name, funcArrow) as Gen("Function defined, wrap + " + bodyGen)
|
||||
A.endScope() >> N.endScope() >> N.define(name, funcArrow, isRoot = true) as Gen(
|
||||
"Function defined, wrap + " + bodyGen
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user