Verifies (with bugs)

This commit is contained in:
dmitry 2021-03-15 15:19:32 +03:00
parent 401b7a31df
commit e33b499c42
8 changed files with 78 additions and 35 deletions

View File

@ -35,9 +35,9 @@ object Aqua {
.map(pe => NonEmptyList.one[AquaError](SyntaxError(pe.failedAtOffset, pe.expected)))
)
.andThen { blocks =>
step1.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => WalkerError(sv._1, sv._2)))
step1.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => CompilerError(sv._1, sv._2)))
}
.andThen { blocks =>
step2.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => WalkerError(sv._1, sv._2)))
step2.walkValidate(blocks).leftMap(_.map(_.toStringF).map(sv => CompilerError(sv._1, sv._2)))
}
}

View File

@ -19,7 +19,7 @@ case class SyntaxError(offset: Int, expectations: NonEmptyList[Expectation]) ext
) + Console.RESET + "\n"
}
case class WalkerError(span: Span, hint: String) extends AquaError {
case class CompilerError(span: Span, hint: String) extends AquaError {
override def showForConsole(script: String): String =
span
@ -27,12 +27,3 @@ case class WalkerError(span: Span, hint: String) extends AquaError {
.map(_.toConsoleStr(hint, Console.CYAN))
.getOrElse("(Dup error, but offset is beyond the script)") + "\n"
}
case class GetTypeError(span: Span, hint: String) extends AquaError {
override def showForConsole(script: String): String =
span
.focus(script, 3)
.map(_.toConsoleStr(hint, Console.MAGENTA))
.getOrElse("(Get type error, but offset is beyond the script)") + "\n"
}

View File

@ -1,5 +1,6 @@
package aqua
import aqua.ast.algebra.ReportError
import aqua.ast.expr.{
AbilityIdExpr,
AliasExpr,
@ -13,19 +14,26 @@ import aqua.ast.expr.{
RootExpr,
ServiceExpr
}
import aqua.ast.algebra.abilities.{AbilitiesAlgebra, AbilityOp}
import aqua.ast.algebra.names.{NameOp, NamesAlgebra}
import aqua.ast.algebra.scope.{PeerIdAlgebra, PeerIdOp}
import aqua.ast.algebra.types.{TypeOp, TypesAlgebra}
import aqua.ast.algebra.abilities.{AbilitiesAlgebra, AbilitiesInterpreter, AbilitiesState, AbilityOp}
import aqua.ast.algebra.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesState}
import aqua.ast.algebra.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
import aqua.ast.algebra.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
import aqua.ast.{Ast, Expr, Gen, Prog}
import cats.data.EitherK
import aqua.parser.lexer.Token
import cats.arrow.FunctionK
import cats.data.Validated.{Invalid, Valid}
import cats.data.{EitherK, NonEmptyList, State, ValidatedNel}
import cats.{Comonad, Eval}
import cats.free.Free
import cats.syntax.flatMap._
import monocle.Lens
import monocle.macros.GenLens
import scala.collection.immutable.Queue
object Compiler {
private def exprToProg[F[_]: Comonad, G[_]](
private def exprToProg[F[_], G[_]](
expr: Expr[F]
)(implicit
A: AbilitiesAlgebra[F, G],
@ -47,7 +55,7 @@ object Compiler {
case _: RootExpr[F] => Free.pure[G, Gen](Gen("Root expr"))
}
def folder[F[_]: Comonad, G[_]](implicit
def folder[F[_], G[_]](implicit
A: AbilitiesAlgebra[F, G],
N: NamesAlgebra[F, G],
P: PeerIdAlgebra[F, G],
@ -65,7 +73,52 @@ object Compiler {
type Alg1[F[_], A] = EitherK[PeerIdOp[F, *], Alg0[F, *], A]
type Alg[F[_], A] = EitherK[TypeOp[F, *], Alg1[F, *], A]
def transpile[F[_]: Comonad](ast: Ast[F]): Free[Alg[F, *], Gen] =
def transpile[F[_]](ast: Ast[F]): Free[Alg[F, *], Gen] =
ast.cata(folder[F, Alg[F, *]]).value
case class CompilerState[F[_]](
errors: Queue[(Token[F], String)] = Queue.empty[(Token[F], String)],
names: NamesState[F] = NamesState[F](),
abilities: AbilitiesState[F] = AbilitiesState[F](),
peerId: PeerIdState[F] = PeerIdState[F](),
types: TypesState[F] = TypesState[F]()
)
def interpret[F[_]](free: Free[Alg[F, *], Gen]): State[CompilerState[F], Gen] = {
import monocle.macros.syntax.all._
implicit val re: ReportError[F, CompilerState[F]] =
(st: CompilerState[F], token: Token[F], hint: String) => st.focus(_.errors).modify(_.enqueue(token -> hint))
implicit val ns: Lens[CompilerState[F], NamesState[F]] = GenLens[CompilerState[F]](_.names)
val names = new NamesInterpreter[F, CompilerState[F]]()
implicit val as: Lens[CompilerState[F], AbilitiesState[F]] = GenLens[CompilerState[F]](_.abilities)
val abilities = new AbilitiesInterpreter[F, CompilerState[F]]()
implicit val ps: Lens[CompilerState[F], PeerIdState[F]] = GenLens[CompilerState[F]](_.peerId)
val peerId = new PeerIdInterpreter[F, CompilerState[F]]()
implicit val ts: Lens[CompilerState[F], TypesState[F]] = GenLens[CompilerState[F]](_.types)
val types = new TypesInterpreter[F, CompilerState[F]]()
val interpreter0: FunctionK[Alg0[F, *], State[CompilerState[F], *]] = abilities or names
val interpreter1: FunctionK[Alg1[F, *], State[CompilerState[F], *]] = peerId or interpreter0
val interpreter: FunctionK[Alg[F, *], State[CompilerState[F], *]] = types or interpreter1
free.foldMap[State[CompilerState[F], *]](interpreter)
}
def compile[F[_]](ast: Ast[F]): ValidatedNel[(Token[F], String), Gen] =
(transpile[F] _ andThen interpret[F])(ast)
.run(CompilerState[F]())
.map {
case (state, gen) =>
NonEmptyList.fromList(state.errors.toList).fold[ValidatedNel[(Token[F], String), Gen]](Valid(gen))(Invalid(_))
}
.value
}

View File

@ -24,14 +24,19 @@ object Main extends IOApp.Simple {
println(Console.RED + s"Aqua script errored, total ${errs.length} problems found" + Console.RESET)
}
val experimental = Source.fromResource("experimental.aqua").mkString
val script = Source.fromResource("typecheck.aqua").mkString
//tryParse(experimental)
val ast = Ast
.fromString[Span.F](experimental)
.leftMap(_.map(_.showForConsole(experimental)))
.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(Compiler.transpile(_)).map(println(_))
ast.map(println(_))
}

View File

@ -44,11 +44,6 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
_.focus(_.names).index(dn.name.value).replace(dn.`type`) -> true
)
}
mapStackHeadE(report(dn.name, "Cannot define in the root scope"))(fr =>
fr.names.get(dn.name.value) match {
case Some(_) => Left((dn.name, "Variable with this name was already defined", false))
}
)
case bs: BeginScope[F] =>
beginScope(NamesFrame(bs.token))
case _: EndScope[F] =>
@ -56,6 +51,6 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
}).asInstanceOf[State[X, A]]
}
case class NamesState[F[_]](stack: List[NamesFrame[F]])
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil)
case class NamesFrame[F[_]](token: Token[F], names: Map[String, Type] = Map.empty)

View File

@ -22,4 +22,4 @@ class PeerIdInterpreter[F[_], X](implicit lens: Lens[X, PeerIdState[F]], error:
}).asInstanceOf[State[X, A]]
}
case class PeerIdState[F[_]](stack: List[Value[F]])
case class PeerIdState[F[_]](stack: List[Value[F]] = Nil)

View File

@ -97,8 +97,8 @@ class TypesInterpreter[F[_], X](implicit lens: Lens[X, TypesState[F]], error: Re
}
case class TypesState[F[_]](
fields: Map[String, (Name[F], Type)],
strict: Map[String, Type]
fields: Map[String, (Name[F], Type)] = Map.empty[String, (Name[F], Type)],
strict: Map[String, Type] = Map.empty[String, Type]
) {
def isDefined(t: String): Boolean = strict.contains(t)

View File

@ -22,8 +22,7 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
T: TypesAlgebra[F, Alg],
N: NamesAlgebra[F, Alg],
P: PeerIdAlgebra[F, Alg],
A: AbilitiesAlgebra[F, Alg],
F: Comonad[F]
A: AbilitiesAlgebra[F, Alg]
): Prog[Alg, Gen] =
Prog.around(
A.beginScope(name) >> Applicative[Free[Alg, *]]