This commit is contained in:
dmitry 2021-03-17 15:17:51 +03:00
parent b4a9979278
commit acb59d5582
22 changed files with 128 additions and 51 deletions

View File

@ -1,6 +1,7 @@
package aqua
import aqua.ast.{Ast, Compiler, Gen}
import aqua.ast.gen.Gen
import aqua.ast.{Ast, Compiler}
import cats.data.ValidatedNel
import aqua.parser.lift.Span

View File

@ -6,6 +6,7 @@ import aqua.ast.algebra.names.{NameOp, NamesAlgebra, NamesInterpreter, NamesStat
import aqua.ast.algebra.scope.{PeerIdAlgebra, PeerIdInterpreter, PeerIdOp, PeerIdState}
import aqua.ast.algebra.types.{TypeOp, TypesAlgebra, TypesInterpreter, TypesState}
import aqua.ast.expr._
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token
import cats.Eval
import cats.arrow.FunctionK

View File

@ -1,6 +1,7 @@
package aqua.ast.algebra.abilities
import aqua.ast.algebra.types.ArrowType
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.{Ability, Name, Token, Value}
import cats.InjectK
import cats.data.{NonEmptyList, NonEmptyMap}
@ -14,10 +15,10 @@ class AbilitiesAlgebra[F[_], Alg[_]](implicit A: InjectK[AbilityOp[F, *], Alg])
def purgeArrows(token: Token[F]): Free[Alg, Option[NonEmptyList[(Name[F], ArrowType)]]] =
Free.liftInject[Alg](PurgeArrows[F](token))
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowType]): Free[Alg, Boolean] =
def defineService(name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineService[F](name, arrows))
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowType]] =
def getArrow(name: Ability[F], arrow: Name[F]): Free[Alg, Option[ArrowGen]] =
Free.liftInject[Alg](GetArrow[F](name, arrow))
def setServiceId(name: Ability[F], id: Value[F]): Free[Alg, Boolean] =

View File

@ -2,6 +2,7 @@ package aqua.ast.algebra.abilities
import aqua.ast.algebra.{ReportError, StackInterpreter}
import aqua.ast.algebra.types.ArrowType
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.{Name, Token, Value}
import cats.data.{NonEmptyList, NonEmptyMap, State}
import cats.~>
@ -14,7 +15,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
extends StackInterpreter[F, X, AbilitiesState[F], AbilityStackFrame[F]](GenLens[AbilitiesState[F]](_.stack))
with (AbilityOp[F, *] ~> State[X, *]) {
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowType]]] =
private def getService(name: String): S[Option[NonEmptyMap[String, ArrowGen]]] =
getState.map(_.services.get(name))
override def apply[A](fa: AbilityOp[F, A]): State[X, A] =
@ -36,17 +37,15 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
case ga: GetArrow[F] =>
getService(ga.name.value).flatMap {
case Some(arrows) =>
// TODO: must be resolved
arrows(ga.arrow.value)
.fold(
report(
ga.arrow,
s"Service found, but arrow is undefined, available: ${arrows.value.keys.toNonEmptyList.toList.mkString(", ")}"
).as(Option.empty[ArrowType])
).as(Option.empty[ArrowGen])
)(a => State.pure(Some(a)))
case None =>
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType])
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowGen])
}
case s: SetServiceId[F] =>
@ -82,7 +81,7 @@ class AbilitiesInterpreter[F[_], X](implicit lens: Lens[X, AbilitiesState[F]], e
case class AbilitiesState[F[_]](
stack: List[AbilityStackFrame[F]] = Nil,
services: Map[String, NonEmptyMap[String, ArrowType]] = Map.empty,
services: Map[String, NonEmptyMap[String, ArrowGen]] = Map.empty,
rootServiceIds: Map[String, Value[F]] = Map.empty[String, Value[F]]
) {

View File

@ -1,6 +1,7 @@
package aqua.ast.algebra.abilities
import aqua.ast.algebra.types.ArrowType
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.{Ability, Name, Token, Value}
import cats.data.{NonEmptyList, NonEmptyMap}
@ -10,9 +11,9 @@ case class DefineArrow[F[_]](arrow: Name[F], `type`: ArrowType) extends AbilityO
case class PurgeArrows[F[_]](token: Token[F]) extends AbilityOp[F, Option[NonEmptyList[(Name[F], ArrowType)]]]
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowType]) extends AbilityOp[F, Boolean]
case class DefineService[F[_]](name: Ability[F], arrows: NonEmptyMap[String, ArrowGen]) extends AbilityOp[F, Boolean]
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowType]]
case class GetArrow[F[_]](name: Ability[F], arrow: Name[F]) extends AbilityOp[F, Option[ArrowGen]]
case class SetServiceId[F[_]](name: Ability[F], id: Value[F]) extends AbilityOp[F, Boolean]

View File

@ -1,15 +1,18 @@
package aqua.ast.algebra.names
import aqua.ast.algebra.types.{ArrowType, Type}
import aqua.ast.algebra.types.Type
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.{Name, Token}
sealed trait NameOp[F[_], T]
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 ReadArrow[F[_]](name: Name[F]) extends NameOp[F, Option[ArrowGen]]
case class DefineName[F[_]](name: Name[F], `type`: Type, isRoot: Boolean) extends NameOp[F, Boolean]
case class DefineName[F[_]](name: Name[F], `type`: Type) extends NameOp[F, Boolean]
case class DefineArrow[F[_]](name: Name[F], gen: ArrowGen, isRoot: Boolean) extends NameOp[F, Boolean]
case class BeginScope[F[_]](token: Token[F]) extends NameOp[F, Unit]

View File

@ -1,6 +1,7 @@
package aqua.ast.algebra.names
import aqua.ast.algebra.types.{ArrowType, Type}
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.{Name, Token}
import cats.InjectK
import cats.free.Free
@ -10,11 +11,14 @@ class NamesAlgebra[F[_], Alg[_]](implicit V: InjectK[NameOp[F, *], Alg]) {
def read(name: Name[F]): Free[Alg, Option[Type]] =
Free.liftInject[Alg](ReadName(name))
def readArrow(name: Name[F]): Free[Alg, Option[ArrowType]] =
def readArrow(name: Name[F]): Free[Alg, Option[ArrowGen]] =
Free.liftInject[Alg](ReadArrow(name))
def define(name: Name[F], `type`: Type, isRoot: Boolean = false): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineName(name, `type`, isRoot))
def define(name: Name[F], `type`: Type): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineName(name, `type`))
def defineArrow(name: Name[F], gen: ArrowGen, isRoot: Boolean): Free[Alg, Boolean] =
Free.liftInject[Alg](DefineArrow(name, gen, isRoot))
def beginScope(token: Token[F]): Free[Alg, Unit] =
Free.liftInject[Alg](BeginScope(token))

View File

@ -1,7 +1,8 @@
package aqua.ast.algebra.names
import aqua.ast.algebra.types.{ArrowType, Type}
import aqua.ast.algebra.types.Type
import aqua.ast.algebra.{ReportError, StackInterpreter}
import aqua.ast.gen.ArrowGen
import aqua.parser.lexer.Token
import cats.data.State
import cats.~>
@ -18,7 +19,13 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
getState.map { st =>
st.stack.collectFirst {
case frame if frame.names.contains(name) => frame.names(name)
} orElse st.rootNames.get(name)
case frame if frame.arrows.contains(name) => frame.arrows(name).`type`
} orElse st.rootArrows.get(name).map(_.`type`)
}
def readArrow(name: String): S[Option[ArrowGen]] =
getState.map { st =>
st.stack.flatMap(_.arrows.get(name)).headOption orElse st.rootArrows.get(name)
}
override def apply[A](fa: NameOp[F, A]): State[X, A] =
@ -30,29 +37,36 @@ class NamesInterpreter[F[_], X](implicit lens: Lens[X, NamesState[F]], error: Re
getState.flatMap(st => report(rn.name, "Undefined name, available: " + st.allNames.mkString(", ")))
}
case ra: ReadArrow[F] =>
readName(ra.name.value).flatMap {
case Some(t: ArrowType) =>
State.pure(Option(t))
case Some(t) =>
report(ra.name, s"Arrow type expected, got: $t").as(Option.empty[ArrowType])
readArrow(ra.name.value).flatMap {
case Some(g) => State.pure(Option(g))
case None =>
getState.flatMap(st =>
report(ra.name, "Undefined name, available: " + st.allNames.mkString(", ")).as(Option.empty[ArrowType])
report(ra.name, "Undefined arrow, available: " + st.allNames.mkString(", "))
.as(Option.empty[ArrowGen])
)
}
case dn: DefineName[F] =>
readName(dn.name.value).flatMap {
case Some(_) => report(dn.name, "This name was already defined in the scope").as(false)
case None =>
mapStackHead(
if (dn.isRoot)
modify(st => st.copy(rootNames = st.rootNames.updated(dn.name.value, dn.`type`)))
report(dn.name, "Cannot define a variable in the root scope")
.as(false)
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
}
case da: DefineArrow[F] =>
readName(da.name.value).flatMap {
case Some(_) => report(da.name, "This name was already defined in the scope").as(false)
case None =>
mapStackHead(
if (da.isRoot)
modify(st => st.copy(rootArrows = st.rootArrows.updated(da.name.value, da.gen)))
.as(true)
else
report(dn.name, "Cannot define a variable in the root scope")
report(da.name, "Cannot define a variable in the root scope")
.as(false)
)(fr => fr.addName(dn.name.value, dn.`type`) -> true)
)(fr => fr.addArrow(da.name.value, da.gen) -> true)
}
case bs: BeginScope[F] =>
beginScope(NamesFrame(bs.token))
@ -61,10 +75,20 @@ 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, rootNames: Map[String, Type] = Map.empty) {
def allNames: LazyList[String] = LazyList.from(stack).flatMap(_.names.keys).appendedAll(rootNames.keys)
case class NamesState[F[_]](stack: List[NamesFrame[F]] = Nil, rootArrows: Map[String, ArrowGen] = Map.empty) {
def allNames: LazyList[String] =
LazyList.from(stack).flatMap(s => s.names.keys ++ s.arrows.keys).appendedAll(rootArrows.keys)
def allArrows: LazyList[String] =
LazyList.from(stack).flatMap(_.arrows.keys).appendedAll(rootArrows.keys)
}
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,
arrows: Map[String, ArrowGen] = Map.empty
) {
def addName(n: String, t: Type): NamesFrame[F] = copy[F](names = names.updated(n, t))
def addArrow(n: String, g: ArrowGen): NamesFrame[F] = copy[F](arrows = arrows.updated(n, g))
}

View File

@ -1,8 +1,9 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{Ability, Value}
import aqua.parser.lift.LiftParser

View File

@ -1,7 +1,8 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{CustomTypeToken, TypeToken}
import aqua.parser.lift.LiftParser

View File

@ -1,8 +1,9 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{ArrowTypeToken, Name}
import aqua.parser.lift.LiftParser

View File

@ -1,10 +1,11 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog, ServiceCallGen}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.names.NamesAlgebra
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.{Gen, ServiceCallGen}
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{Ability, Name, Value}
import aqua.parser.lift.LiftParser
@ -31,9 +32,9 @@ case class CoalgebraExpr[F[_]](
.fold(N.readArrow(funcName))(A.getArrow(_, funcName))
.flatMap {
case Some(at) =>
V.checkArguments(at, args) >> variable
V.checkArguments(at.`type`, args) >> variable
.fold(Free.pure[Alg, Boolean](true))(exportVar =>
at.res.fold(
at.`type`.res.fold(
// TODO: error! we're trying to export variable, but function has no export type
Free.pure[Alg, Boolean](false)
)(resType => N.define(exportVar, resType))

View File

@ -1,8 +1,9 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.names.NamesAlgebra
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.CustomTypeToken
import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser

View File

@ -1,7 +1,8 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{DataTypeToken, Name}
import aqua.parser.lift.LiftParser

View File

@ -2,11 +2,12 @@ package aqua.ast.expr
import aqua.ast.Ast.Tree
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.{AirGen, Expr, FuncBodyGen, FuncGen, Gen, Indent, Prog}
import aqua.ast.{Expr, Indent, Prog}
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.names.NamesAlgebra
import aqua.ast.algebra.scope.PeerIdAlgebra
import aqua.ast.algebra.types.{ArrowType, Type, TypesAlgebra}
import aqua.ast.gen.{AirGen, ArrowGen, FuncBodyGen, FuncGen, Gen}
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
import aqua.parser.lift.LiftParser
@ -41,6 +42,8 @@ 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: ArrowType) =>
N.defineArrow(argName, ArrowGen.arg(t), isRoot = false).as(acc.enqueue(t))
case Some(t) =>
N.define(argName, t).as(acc.enqueue(t))
case None =>
@ -67,7 +70,7 @@ case class FuncExpr[F[_]](name: Name[F], args: List[Arg[F]], ret: Option[DataTyp
// Erase arguments and internal variables
>> A.endScope() >> N.endScope() >> (bodyGen match {
case bg: AirGen if ret.isDefined == retValue.isDefined =>
N.define(name, funcArrow, isRoot = true) as FuncGen(
N.defineArrow(name, ArrowGen.func(funcArrow), isRoot = true) as FuncGen(
name.value, // TODO: handle return value
FuncBodyGen(bg)
)
@ -94,7 +97,7 @@ object FuncExpr extends Expr.AndIndented(OnExpr, AbilityIdExpr, ReturnExpr, Coal
Parser.pure(
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
)
case l =>
case _ =>
Parser.failWith(
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
)

View File

@ -1,9 +1,10 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.scope.PeerIdAlgebra
import aqua.ast.gen.Gen
import aqua.parser.lexer.Token._
import aqua.parser.lexer.Value
import aqua.parser.lift.LiftParser

View File

@ -1,6 +1,7 @@
package aqua.ast.expr
import aqua.ast.{AirGen, Expr, Gen, ParGen, Prog}
import aqua.ast.gen.{AirGen, Gen, ParGen}
import aqua.ast.{Expr, Prog}
import aqua.parser.lexer.Token._
import aqua.parser.lift.LiftParser
import aqua.parser.lift.LiftParser._

View File

@ -1,7 +1,8 @@
package aqua.ast.expr
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.gen.Gen
import aqua.ast.{Expr, Prog}
import aqua.parser.lexer.Token._
import aqua.parser.lexer.Value
import aqua.parser.lift.LiftParser

View File

@ -1,6 +1,7 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog, ScriptGen}
import aqua.ast.gen.{Gen, ScriptGen}
import aqua.ast.{Expr, Prog}
import cats.syntax.semigroup._
import scala.collection.immutable.Queue

View File

@ -1,10 +1,11 @@
package aqua.ast.expr
import aqua.ast.{Expr, Gen, Prog}
import aqua.ast.{Expr, Prog}
import aqua.ast.algebra.ValuesAlgebra
import aqua.ast.algebra.abilities.AbilitiesAlgebra
import aqua.ast.algebra.names.NamesAlgebra
import aqua.ast.algebra.types.TypesAlgebra
import aqua.ast.gen.{ArrowGen, Gen}
import aqua.parser.lexer.Token._
import aqua.parser.lexer.{Ability, Value}
import aqua.parser.lift.LiftParser
@ -28,7 +29,7 @@ case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Exp
(_: Unit, body: Gen) =>
(A.purgeArrows(name) <* A.endScope()).flatMap {
case Some(nel) =>
A.defineService(name, nel.map(kv => kv._1.value -> kv._2).toNem) >>
A.defineService(name, nel.map(kv => kv._1.value -> ArrowGen.service(name.value, kv._2)).toNem) >>
id.fold(Free.pure[Alg, Gen](Gen.noop))(idV =>
V.ensureIsString(idV) >> A.setServiceId(name, idV) as Gen.noop
)

View File

@ -0,0 +1,29 @@
package aqua.ast.gen
import aqua.ast.algebra.types.ArrowType
import aqua.parser.lexer.{Ability, Name}
import cats.free.Free
abstract class ArrowGen(val `type`: ArrowType) {
def gen[Alg[_], F[_]](result: Option[Name[F]]): Free[Alg, AirGen]
}
object ArrowGen {
def func(`type`: ArrowType): ArrowGen =
new ArrowGen(`type`) {
override def gen[Alg[_], F[_]](result: Option[Name[F]]): Free[Alg, AirGen] =
???
}
def service(name: String, `type`: ArrowType): ArrowGen =
new ArrowGen(`type`) {
override def gen[Alg[_], F[_]](result: Option[Name[F]]): Free[Alg, AirGen] = ???
}
def arg(`type`: ArrowType): ArrowGen =
new ArrowGen(`type`) {
override def gen[Alg[_], F[_]](result: Option[Name[F]]): Free[Alg, AirGen] = ???
}
}

View File

@ -1,4 +1,4 @@
package aqua.ast
package aqua.ast.gen
import cats.Semigroup
import cats.free.Free