mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Removed old contexts and expression parsers
This commit is contained in:
parent
6b1f7dd0af
commit
e3ad4f4ed1
@ -1,77 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{AbilityMarker, ServiceAbility}
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.parser.{AbilityFuncCall, AbilityId, Block, DefService, Extract, FuncExpr}
|
||||
import aqua.parser.lexer.Ability
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
case class Abilities[F[_]](expDef: ExpectAndDefine[Ability[F], AbilityMarker[F]]) {
|
||||
def clearDefinitions: Abilities[F] = copy(expDef.clearDefinitions)
|
||||
|
||||
def clearExpectations: Abilities[F] = copy(expDef.clearExpectations)
|
||||
|
||||
def expect(a: Ability[F])(implicit F: Comonad[F]): Abilities[F] =
|
||||
copy(expDef.expect(Acc.one(a.name.extract, a)))
|
||||
}
|
||||
|
||||
object Abilities {
|
||||
type Acc[F[_]] = ExpectAndDefine[Ability[F], AbilityMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, Ability[F], AbilityMarker[F]]
|
||||
def empty[F[_]]: Abilities[F] = Abilities[F](emptyAcc[F])
|
||||
|
||||
case class DuplicateAbility[F[_]](name: String, marker: AbilityMarker[F]) extends Walker.DupError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = marker.toError(s"Duplicate ability definition: ${name}")
|
||||
}
|
||||
|
||||
case class UndefinedAbility[F[_]](name: String, usage: Ability[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Undefined ability $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O]) extends Walker[F, I, Abilities[F] :: O] {
|
||||
type Ctx = Abilities[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
(op match {
|
||||
case aid: AbilityId[F, I] =>
|
||||
prev.head.expect(aid.ability)
|
||||
case ac: AbilityFuncCall[F, I] =>
|
||||
prev.head.expect(ac.ability)
|
||||
case Extract(_, ac: AbilityFuncCall[F, I], _) =>
|
||||
prev.head.expect(ac.ability)
|
||||
case _ =>
|
||||
prev.head
|
||||
}) :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
(block match {
|
||||
case defs: DefService[F, I] =>
|
||||
Abilities(emptyAcc[F].defined(defs.name.name.extract, ServiceAbility(defs.name, defs)))
|
||||
case _ =>
|
||||
empty[F]
|
||||
|
||||
}) :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
Walker.collectDups(prev.head.expDef, next.head.expDef, DuplicateAbility[F]) ::: extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
Abilities(prev.head.expDef combineSeq block.head.expDef) :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UndefinedAbility[F])
|
||||
(curErrs ::: extErrs, Abilities(curExpDef) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{AbilityResolveMarker, ResolvedMarker}
|
||||
import aqua.context.scope.Scope
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.parser.lexer.Ability
|
||||
import aqua.parser._
|
||||
import cats.syntax.comonad._
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import shapeless.ops.hlist.Selector
|
||||
|
||||
case class AbilitiesResolve[F[_]](expDef: ExpectAndDefine[Ability[F], AbilityResolveMarker[F]]) {
|
||||
|
||||
def resolve[L](ar: AbilityResolve[F, L])(implicit F: Comonad[F]): AbilitiesResolve[F] =
|
||||
copy(
|
||||
expDef.copy(defineAcc = expDef.defineAcc.updated(ar.ability.name.extract, ResolvedMarker(ar)))
|
||||
)
|
||||
|
||||
def clearDefinitions: AbilitiesResolve[F] = copy(expDef.clearDefinitions)
|
||||
|
||||
def expect(a: Ability[F])(implicit F: Comonad[F]): AbilitiesResolve[F] =
|
||||
copy(expDef.expect(Acc.one(a.name.extract, a)))
|
||||
}
|
||||
|
||||
object AbilitiesResolve {
|
||||
type Acc[F[_]] = ExpectAndDefine[Ability[F], AbilityResolveMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, Ability[F], AbilityResolveMarker[F]]
|
||||
def empty[F[_]]: AbilitiesResolve[F] = AbilitiesResolve[F](emptyAcc[F])
|
||||
|
||||
case class UnresolvedAbility[F[_]](name: String, usage: Ability[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Unresolved ability $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O])(implicit getScope: Selector[O, Scope[F]])
|
||||
extends Walker[F, I, AbilitiesResolve[F] :: O] {
|
||||
type Ctx = AbilitiesResolve[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
(group match {
|
||||
case _ => last.head.clearDefinitions
|
||||
}) :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx = {
|
||||
lazy val in = extend.funcOpCtx(op, prev.tail)
|
||||
val data = prev.head
|
||||
lazy val mode = getScope(in).mode.map(_.extract)
|
||||
|
||||
def combinedWith(other: AbilitiesResolve[F] => AbilitiesResolve[F]): AbilitiesResolve[F] =
|
||||
AbilitiesResolve[F](data.expDef.combine(other(empty[F]).expDef, mode))
|
||||
|
||||
(op match {
|
||||
case ac: AbilityFuncCall[F, I] =>
|
||||
combinedWith(_.expect(ac.ability))
|
||||
case Extract(_, ac: AbilityFuncCall[F, I], _) =>
|
||||
combinedWith(_.expect(ac.ability))
|
||||
case ar: AbilityResolve[F, I] =>
|
||||
combinedWith(_.resolve(ar))
|
||||
case _ =>
|
||||
prev.head
|
||||
}) :: in
|
||||
}
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
empty[F] :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
AbilitiesResolve(prev.head.expDef combineSeq block.head.expDef).clearDefinitions :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UnresolvedAbility[F])
|
||||
(curErrs ::: extErrs, AbilitiesResolve(curExpDef) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{ArgVarMarker, ExtractedVarMarker, FuncArgMarker}
|
||||
import aqua.context.scope.Scope
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.parser.{AbilityFuncCall, AbilityId, Block, DefFunc, Extract, FuncCall, FuncExpr, On, Par}
|
||||
import aqua.parser.lexer.{DataTypeToken, Name, Value}
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import shapeless.ops.hlist.Selector
|
||||
import cats.syntax.comonad._
|
||||
|
||||
case class ArgsAndVars[F[_]](expDef: ExpectAndDefine[Value[F], ArgVarMarker[F]]) {
|
||||
def clearDefinitions: ArgsAndVars[F] = copy(expDef.clearDefinitions)
|
||||
def clearExpectations: ArgsAndVars[F] = copy(expDef.clearExpectations)
|
||||
}
|
||||
|
||||
object ArgsAndVars {
|
||||
type Acc[F[_]] = ExpectAndDefine[Value[F], ArgVarMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, Value[F], ArgVarMarker[F]]
|
||||
def empty[F[_]]: ArgsAndVars[F] = ArgsAndVars[F](emptyAcc[F])
|
||||
|
||||
case class DuplicateDef[F[_]](name: String, marker: ArgVarMarker[F]) extends Walker.DupError[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
marker.toError(s"Duplicate variable or arg definition: ${name}")
|
||||
}
|
||||
|
||||
case class UnresolvedVar[F[_]](name: String, usage: Value[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Unresolved variable $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O])(implicit
|
||||
getScope: Selector[O, Scope[F]]
|
||||
) extends Walker[F, I, ArgsAndVars[F] :: O] {
|
||||
type Ctx = ArgsAndVars[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx = {
|
||||
lazy val in = extend.funcOpCtx(op, prev.tail)
|
||||
val data = prev.head
|
||||
lazy val mode = getScope(in).mode.map(_.extract)
|
||||
def combinedWith(other: Acc[F] => Acc[F]): ArgsAndVars[F] =
|
||||
ArgsAndVars[F](data.expDef.combine(other(emptyAcc[F]), mode))
|
||||
|
||||
op match {
|
||||
case FuncCall(_, args, _) =>
|
||||
combinedWith(_ expect Acc.fromValues(args)) :: in
|
||||
case AbilityFuncCall(_, _, _, args, _) =>
|
||||
combinedWith(_ expect Acc.fromValues(args)) :: in
|
||||
case ex @ Extract(n, fc, _) =>
|
||||
val f = funcOpCtx(fc, prev)
|
||||
f.head
|
||||
.copy(
|
||||
f.head.expDef.combine(empty[F].expDef.defined(n.name.extract, ExtractedVarMarker(n, ex)), mode)
|
||||
) :: f.tail
|
||||
case AbilityId(_, id, _) =>
|
||||
combinedWith(_ expect Acc.fromValues(id :: Nil)) :: in
|
||||
case On(p, _, _) =>
|
||||
combinedWith(_ expect Acc.fromValues(p :: Nil)) :: in
|
||||
case Par(_, _, _) =>
|
||||
data :: in
|
||||
}
|
||||
}
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
(block match {
|
||||
case DefFunc(head, _, _) =>
|
||||
head.args
|
||||
.foldLeft(empty[F]) {
|
||||
case (acc, (k, v, dt: DataTypeToken[F])) =>
|
||||
acc.copy(acc.expDef.defined(k, FuncArgMarker(Name(v), dt)))
|
||||
case (acc, _) => acc
|
||||
}
|
||||
|
||||
case _ =>
|
||||
empty[F]
|
||||
|
||||
}) :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
Walker.collectDups(prev.head.expDef, next.head.expDef, DuplicateDef[F]) ::: extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
ArgsAndVars(prev.head.expDef combineSeq block.head.expDef).clearDefinitions :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UnresolvedVar[F])
|
||||
(curErrs ::: extErrs, ArgsAndVars(curExpDef) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{AbilityArrow, ArrowMarker, FuncArrow, LocalArrow}
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.parser.{AbilityFuncCall, Block, DefFunc, DefService, Extract, FuncCall, FuncExpr}
|
||||
import aqua.parser.lexer.{ArrowTypeToken, Name}
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
case class Arrows[F[_]](expDef: ExpectAndDefine[Name[F], ArrowMarker[F]]) {
|
||||
|
||||
def clearLocal: Arrows[F] =
|
||||
copy(expDef.collectDefinitions {
|
||||
case fa: FuncArrow[F, _] => fa
|
||||
case aa: AbilityArrow[F, _] => aa
|
||||
})
|
||||
def clearExpectations: Arrows[F] = copy(expDef.clearExpectations)
|
||||
|
||||
def expect(a: Name[F])(implicit F: Comonad[F]): Arrows[F] =
|
||||
copy(expDef.combineSeq(Arrows.emptyAcc.expect(Acc.one(a.name.extract, a))))
|
||||
|
||||
def defined(name: String, marker: ArrowMarker[F]): Arrows[F] =
|
||||
copy(expDef.defined(name, marker))
|
||||
}
|
||||
|
||||
object Arrows {
|
||||
type Acc[F[_]] = ExpectAndDefine[Name[F], ArrowMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, Name[F], ArrowMarker[F]]
|
||||
def empty[F[_]]: Arrows[F] = Arrows[F](emptyAcc[F])
|
||||
|
||||
case class DuplicateArrow[F[_]](name: String, marker: ArrowMarker[F]) extends Walker.DupError[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
marker.toError(s"Duplicate function or arrow definition: ${name}")
|
||||
}
|
||||
|
||||
case class UnresolvedArrow[F[_]](name: String, usage: Name[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Unresolved arrow $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O]) extends Walker[F, I, Arrows[F] :: O] {
|
||||
type Ctx = Arrows[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
(op match {
|
||||
case FuncCall(a, _, _) =>
|
||||
prev.head.expect(a)
|
||||
case afc: AbilityFuncCall[F, I] =>
|
||||
prev.head.expect(afc.arrow)
|
||||
|
||||
case Extract(_, fc, _) =>
|
||||
fc match {
|
||||
case FuncCall(a, _, _) =>
|
||||
prev.head.expect(a)
|
||||
case afc: AbilityFuncCall[F, I] =>
|
||||
prev.head.expect(afc.arrow)
|
||||
}
|
||||
case _ =>
|
||||
prev.head
|
||||
}) :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
(block match {
|
||||
case DefFunc(head, _, _) =>
|
||||
head.args
|
||||
.foldLeft(empty[F]) {
|
||||
case (acc, (k, _, at: ArrowTypeToken[F])) =>
|
||||
acc.defined(k, LocalArrow(at))
|
||||
case (acc, _) => acc
|
||||
}
|
||||
|
||||
case DefService(ab, funcs, _) =>
|
||||
val prefix = ab.name.extract + "."
|
||||
funcs.toNel.foldLeft(empty[F]) {
|
||||
case (acc, (n, at)) =>
|
||||
acc.defined(prefix + n, AbilityArrow(ab, at))
|
||||
}
|
||||
|
||||
case _ =>
|
||||
empty[F]
|
||||
|
||||
}) :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
Walker.collectDups(prev.head.expDef, next.head.expDef, DuplicateArrow[F]) ::: extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
Arrows(prev.head.expDef combineSeq block.head.expDef).clearLocal :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UnresolvedArrow[F])
|
||||
(curErrs ::: extErrs, Arrows(curExpDef) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.{TypeAlias, TypeDef, TypeMarker}
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.context.walker.{Acc, ExpectAndDefine, Walker}
|
||||
import aqua.ast.algebra.types.{ArrayType, ArrowType, DataType, ProductType, Type}
|
||||
import aqua.parser.{Block, DefAlias, DefFunc, DefService, DefType, FuncExpr}
|
||||
import aqua.parser.lexer.{ArrayTypeToken, ArrowDef, ArrowTypeToken, BasicTypeToken, CustomTypeToken, TypeToken}
|
||||
import cats.data.NonEmptyMap
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
case class Types[F[_]](
|
||||
expDef: ExpectAndDefine[CustomTypeToken[F], TypeMarker[F]],
|
||||
strict: Map[String, Type] = Map.empty
|
||||
) {
|
||||
def clearDefinitions: Types[F] = copy(expDef.clearDefinitions)
|
||||
def clearExpectations: Types[F] = copy(expDef.clearExpectations)
|
||||
|
||||
def resolveTypeToken(tt: TypeToken[F])(implicit F: Comonad[F]): Option[Type] =
|
||||
Types.resolveTypeToken(strict, tt)
|
||||
|
||||
def resolveArrowDef(ad: ArrowDef[F])(implicit F: Comonad[F]): Option[ArrowType] =
|
||||
Types.resolveArrowDef(strict, ad)
|
||||
}
|
||||
|
||||
object Types {
|
||||
|
||||
def resolveTypeToken[F[_]: Comonad](strict: Map[String, Type], tt: TypeToken[F]): Option[Type] =
|
||||
tt match {
|
||||
case ArrayTypeToken(_, dtt) =>
|
||||
resolveTypeToken(strict, dtt).collect {
|
||||
case it: DataType => ArrayType(it)
|
||||
}
|
||||
case CustomTypeToken(n) => strict.get(n.extract)
|
||||
case BasicTypeToken(v) => Some(v.extract)
|
||||
case ArrowTypeToken(_, args, res) =>
|
||||
val strictArgs = args.map(resolveTypeToken(strict, _)).collect {
|
||||
case Some(dt: DataType) => dt
|
||||
}
|
||||
val strictRes = res.flatMap(resolveTypeToken(strict, _)).collect {
|
||||
case dt: DataType => dt
|
||||
}
|
||||
Option.when(strictRes.isDefined == res.isDefined && strictArgs.length == args.length)(
|
||||
ArrowType(strictArgs, strictRes)
|
||||
)
|
||||
}
|
||||
|
||||
def resolveArrowDef[F[_]: Comonad](strict: Map[String, Type], ad: ArrowDef[F]): Option[ArrowType] =
|
||||
ad.resType.flatMap(resolveTypeToken(strict, _)) match {
|
||||
case resType if resType.isDefined == ad.resType.isDefined =>
|
||||
ad.argTypes.flatMap(resolveTypeToken(strict, _)) match {
|
||||
case argTypes if argTypes.length == ad.argTypes.length => Some(ArrowType(argTypes, resType))
|
||||
case _ => None
|
||||
}
|
||||
|
||||
case _ => None
|
||||
}
|
||||
|
||||
type Acc[F[_]] = ExpectAndDefine[CustomTypeToken[F], TypeMarker[F]]
|
||||
def emptyAcc[F[_]]: Acc[F] = ExpectAndDefine.empty[F, CustomTypeToken[F], TypeMarker[F]]
|
||||
def empty[F[_]]: Types[F] = Types[F](emptyAcc[F], Map.empty)
|
||||
|
||||
case class DuplicateType[F[_]](name: String, marker: TypeMarker[F]) extends Walker.DupError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = marker.toError(s"Duplicate type definition: ${name}")
|
||||
}
|
||||
|
||||
case class UnresolvedType[F[_]](name: String, usage: CustomTypeToken[F]) extends Walker.UnresolvedError[F] {
|
||||
override def toStringF(implicit F: Functor[F]): F[String] = usage.as(s"Unresolved type $name")
|
||||
}
|
||||
|
||||
class ExpDef[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O]) extends Walker[F, I, Types[F] :: O] {
|
||||
type Ctx = Types[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
prev.head :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
(block match {
|
||||
case DefFunc(head, _, _) =>
|
||||
head.args
|
||||
.foldLeft(empty[F]) {
|
||||
case (acc, (_, _, ft)) =>
|
||||
acc.copy(acc.expDef.expect(Acc.fromType(ft)))
|
||||
}
|
||||
|
||||
case deft: DefType[F, I] =>
|
||||
Types(
|
||||
deft.fields.toNel
|
||||
.map(_._2._2)
|
||||
.map(Acc.fromType[F](_))
|
||||
.foldLeft(
|
||||
emptyAcc[F]
|
||||
.defined(deft.name.name.extract, TypeDef(deft))
|
||||
)(_ expect _)
|
||||
)
|
||||
|
||||
case defs: DefService[F, I] =>
|
||||
Types(
|
||||
defs.funcs.toNel
|
||||
.map(_._2)
|
||||
.map(Acc.fromType[F](_))
|
||||
.foldLeft(
|
||||
emptyAcc[F]
|
||||
)(_ expect _)
|
||||
)
|
||||
case a: DefAlias[F, I] =>
|
||||
Types(
|
||||
emptyAcc[F]
|
||||
.expect(Acc.fromType(a.target))
|
||||
.defined(a.alias.name.extract, TypeAlias(a.alias, a.target))
|
||||
)
|
||||
|
||||
}) :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] =
|
||||
Walker.collectDups(prev.head.expDef, next.head.expDef, DuplicateType[F]) ::: extend
|
||||
.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = empty[F] :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
Types(
|
||||
prev.head.expDef combineSeq block.head.expDef,
|
||||
block.head.expDef.defineAcc.foldLeft(prev.head.strict) {
|
||||
case (strict, (k, TypeAlias(_, marker))) =>
|
||||
resolveTypeToken(strict, marker).fold(strict)(t => strict + (k -> t))
|
||||
case (strict, (k, TypeDef(dt))) =>
|
||||
val resTypes = dt.fields.map(_._2).map(resolveTypeToken(strict, _)).toSortedMap.collect {
|
||||
case (kk, Some(t: DataType)) => kk -> t
|
||||
}
|
||||
NonEmptyMap
|
||||
.fromMap(resTypes)
|
||||
.filter(_.length == dt.fields.length)
|
||||
.fold(strict)(fields => strict + (k -> ProductType(dt.name.name.extract, fields)))
|
||||
|
||||
}
|
||||
) :: extend.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = {
|
||||
val (extErrs, extCtx) = extend.unresolved(ctx.tail)
|
||||
val (curErrs, curExpDef) = Walker.collectUnresolved(ctx.head.expDef, UnresolvedType[F])
|
||||
(curErrs ::: extErrs, Types(curExpDef, ctx.head.strict) :: extCtx)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,242 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.marker.FuncArgMarker
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.context.walker.Walker.UnresolvedError
|
||||
import aqua.ast.algebra.types.{ArrayType, ArrowType, ProductType, ScalarType, Type}
|
||||
import aqua.parser.lexer.{
|
||||
ArrowDef,
|
||||
DataTypeToken,
|
||||
IntoArray,
|
||||
IntoField,
|
||||
LambdaOp,
|
||||
Literal,
|
||||
Name,
|
||||
TypeToken,
|
||||
Value,
|
||||
VarLambda
|
||||
}
|
||||
import aqua.parser.{Block, CallExpr, Extract, FuncExpr}
|
||||
import cats.{Comonad, Functor}
|
||||
import shapeless._
|
||||
import shapeless.ops.hlist.Selector
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
case class VarTypes[F[_]](
|
||||
vars: Map[String, Type] = Map.empty[String, Type],
|
||||
errorsQ: Queue[VarTypes.Err[F]] = Queue.empty
|
||||
) {
|
||||
def error(err: VarTypes.Err[F]): VarTypes[F] = copy(errorsQ = errorsQ.appended(err))
|
||||
|
||||
def errors: List[VarTypes.Err[F]] = errorsQ.toList
|
||||
|
||||
def resolve(varname: String, t: Type): VarTypes[F] = copy(vars + (varname -> t))
|
||||
def get(varname: String): Option[Type] = vars.get(varname)
|
||||
}
|
||||
|
||||
object VarTypes {
|
||||
sealed trait Err[F[_]] extends UnresolvedError[F]
|
||||
|
||||
case class TypeMismatch[F[_]](point: F[Unit], expected: Type, given: Type) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Type mismatch, expected: `$expected`, given: `$given`")
|
||||
}
|
||||
|
||||
case class TypeUndefined[F[_]](point: F[String]) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.map(v => s"Undefined: $v")
|
||||
}
|
||||
|
||||
case class NotAnArray[F[_]](point: F[Unit], t: Type) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Expected array, but type is $t")
|
||||
}
|
||||
|
||||
case class ExpectedProduct[F[_]](point: F[String], t: Type) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.map(f => s"Expected product with field `$f`, but type is $t")
|
||||
}
|
||||
|
||||
case class FieldNotFound[F[_]](point: F[String], t: ProductType) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.map(f =>
|
||||
s"Expected product with field `$f`, but type `${t.name}` has only `${t.fields.keys.toNonEmptyList.toList.mkString("`, `")}`"
|
||||
)
|
||||
}
|
||||
|
||||
case class LiteralTypeMismatch[F[_]: Comonad](
|
||||
point: F[Unit],
|
||||
expected: TypeToken[F],
|
||||
given: Set[ScalarType]
|
||||
) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Literal type mismatch, expected: `${expected}`, given: (`${given.mkString("`, `")}`)")
|
||||
}
|
||||
|
||||
case class VarUntyped[F[_]: Comonad](point: F[Unit], name: String) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Untyped variable: `${name}`")
|
||||
}
|
||||
|
||||
case class ArrowUntyped[F[_]: Comonad](point: F[Unit], name: String) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Untyped arrow: `${name}`")
|
||||
}
|
||||
|
||||
case class ArgNumMismatch[F[_]](point: F[Unit], expected: Int, given: Int) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Wrong number of arguments, expected: `$expected`, given: `$given`")
|
||||
}
|
||||
|
||||
case class ArrowResultMismatch[F[_]](
|
||||
point: F[Unit],
|
||||
expected: Option[DataTypeToken[F]],
|
||||
given: Option[DataTypeToken[F]]
|
||||
) extends Err[F] {
|
||||
|
||||
override def toStringF(implicit F: Functor[F]): F[String] =
|
||||
point.as(s"Arrow result mismatch, expected: `$expected`, given: `$given`")
|
||||
}
|
||||
|
||||
class Checker[F[_]: Comonad, I <: HList, O <: HList](extend: Walker[F, I, O])(implicit
|
||||
getArrows: Selector[I, Arrows[F]],
|
||||
getTypes: Selector[O, Types[F]],
|
||||
getArgsAndVars: Selector[I, ArgsAndVars[F]]
|
||||
) extends Walker[F, I, VarTypes[F] :: O] {
|
||||
type Ctx = VarTypes[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
last.head :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
def getArrowDef(name: String, inCtx: I, ctx: Ctx): Option[ArrowDef[F]] =
|
||||
getArrows(inCtx).expDef.defineAcc.get(name).map(_.arrowDef)
|
||||
|
||||
def getArrowType(name: String, inCtx: I, ctx: Ctx): Option[ArrowType] =
|
||||
getArrowDef(name, inCtx, ctx).flatMap(getTypes(ctx.tail).resolveArrowDef(_))
|
||||
|
||||
def resolveIdent(name: Name[F], inCtx: I, prev: Ctx): Either[Err[F], Type] =
|
||||
prev.head.vars
|
||||
.get(name.name.extract)
|
||||
.orElse(
|
||||
getArgsAndVars(inCtx).expDef.defineAcc
|
||||
.get(name.name.extract)
|
||||
.collect {
|
||||
case FuncArgMarker(_, dt) =>
|
||||
getTypes(prev.tail).resolveTypeToken(dt)
|
||||
}
|
||||
.flatten
|
||||
)
|
||||
.orElse(
|
||||
getArrowType(name.name.extract, inCtx, prev)
|
||||
)
|
||||
.toRight(TypeUndefined(name.name))
|
||||
|
||||
def resolveOp(rootT: Type, ops: List[LambdaOp[F]]): Either[Err[F], Type] =
|
||||
ops.headOption.fold[Either[Err[F], Type]](Right(rootT)) {
|
||||
case IntoArray(f) =>
|
||||
rootT match {
|
||||
case ArrayType(intern) => resolveOp(intern, ops.tail).map[Type](ArrayType)
|
||||
case _ => Left(NotAnArray(f, rootT))
|
||||
}
|
||||
case IntoField(name) =>
|
||||
rootT match {
|
||||
case pt @ ProductType(_, fields) =>
|
||||
fields(name.extract)
|
||||
.toRight(FieldNotFound(name, pt))
|
||||
.flatMap(resolveOp(_, ops.tail))
|
||||
case _ => Left(ExpectedProduct(name, rootT))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def resolveValueType(v: Value[F], inCtx: I, prev: Ctx): Either[Err[F], Type] =
|
||||
v match {
|
||||
case Literal(_, ts) => Right(ts) // We want to collect errors with pointers!
|
||||
case VarLambda(name, lambda) =>
|
||||
resolveIdent(name, inCtx, prev).flatMap(resolveOp(_, lambda))
|
||||
|
||||
}
|
||||
|
||||
def funcCall(
|
||||
fc: CallExpr[F, I],
|
||||
arrowDef: ArrowDef[F],
|
||||
prev: Ctx
|
||||
): VarTypes[F] = {
|
||||
val funcType = getTypes(prev.tail).resolveArrowDef(arrowDef)
|
||||
val (valueErrs, valueTypes) = fc.args
|
||||
.map(v => resolveValueType(v, fc.context, prev).map(_ -> v))
|
||||
.foldLeft[(Queue[Err[F]], Queue[(Type, Value[F])])](Queue.empty -> Queue.empty) {
|
||||
case ((errs, args), Right(t)) => (errs, args.appended(t))
|
||||
case ((errs, args), Left(t)) => (errs.appended(t), args)
|
||||
}
|
||||
|
||||
if (valueErrs.nonEmpty) valueErrs.foldLeft(prev.head)(_.error(_))
|
||||
else {
|
||||
funcType.fold(prev.head) {
|
||||
case ft if ft.args.length != valueTypes.length =>
|
||||
prev.head.error(ArgNumMismatch(fc.arrow.unit, ft.args.length, valueTypes.length))
|
||||
case ft =>
|
||||
ft.args.zip(valueTypes).foldLeft(prev.head) {
|
||||
case (acc, (expectedType, (givenType, _))) if expectedType.acceptsValueOf(givenType) => acc
|
||||
case (acc, (expectedType, (givenType, v))) =>
|
||||
acc.error(TypeMismatch(v.unit, expectedType, givenType))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
(op match {
|
||||
case Extract(vr, fc, _) =>
|
||||
getArrowDef(fc.arrow.name.extract, fc.context, prev)
|
||||
.fold(prev.head.error(ArrowUntyped(fc.arrow.unit, fc.arrow.name.extract))) { arrowDef =>
|
||||
val withFC = funcCall(fc, arrowDef, prev)
|
||||
|
||||
arrowDef.resType
|
||||
.flatMap(getTypes(prev.tail).resolveTypeToken)
|
||||
.fold(withFC)(withFC.resolve(vr.name.extract, _))
|
||||
}
|
||||
|
||||
case fc: CallExpr[F, I] =>
|
||||
getArrowDef(fc.arrow.name.extract, fc.context, prev)
|
||||
.fold(prev.head.error(ArrowUntyped(fc.arrow.unit, fc.arrow.name.extract))) { arrowDef =>
|
||||
funcCall(fc, arrowDef, prev)
|
||||
}
|
||||
|
||||
case _ =>
|
||||
prev.head
|
||||
}) :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx =
|
||||
VarTypes[F]() :: extend.blockCtx(block)
|
||||
|
||||
override def emptyCtx: Ctx =
|
||||
VarTypes[F]() :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
VarTypes[F](errorsQ = prev.head.errorsQ appendedAll block.head.errorsQ) :: extend
|
||||
.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[Walker.DupError[F]] =
|
||||
extend.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[Walker.UnresolvedError[F]], Out) = {
|
||||
val (extErr, extCtx) = extend.unresolved(ctx.tail)
|
||||
(ctx.head.errors ::: extErr, ctx.head :: extCtx)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.DefService
|
||||
import aqua.parser.lexer.{Ability, Token}
|
||||
|
||||
sealed trait AbilityMarker[F[_]] extends Marker[F]
|
||||
|
||||
case class ServiceAbility[F[_], L](ability: Ability[F], service: DefService[F, L]) extends AbilityMarker[F] {
|
||||
override def pointer: Token[F] = ability
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.AbilityResolve
|
||||
import aqua.parser.lexer.Token
|
||||
|
||||
trait AbilityResolveMarker[F[_]] extends Marker[F]
|
||||
|
||||
case class ResolvedMarker[F[_], L](resolve: AbilityResolve[F, L]) extends AbilityResolveMarker[F] {
|
||||
override def pointer: Token[F] = resolve.ability
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.Extract
|
||||
import aqua.parser.lexer.{DataTypeToken, Name, Token}
|
||||
|
||||
sealed trait ArgVarMarker[F[_]] extends Marker[F]
|
||||
|
||||
case class FuncArgMarker[F[_]](v: Name[F], dt: DataTypeToken[F]) extends ArgVarMarker[F] {
|
||||
override def pointer: Token[F] = v
|
||||
}
|
||||
|
||||
case class ExtractedVarMarker[F[_], L](v: Name[F], extract: Extract[F, L]) extends ArgVarMarker[F] {
|
||||
override def pointer: Token[F] = v
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.DefFunc
|
||||
import aqua.parser.lexer.{Ability, ArrowDef, ArrowTypeToken, Token}
|
||||
|
||||
sealed trait ArrowMarker[F[_]] extends Marker[F] {
|
||||
def arrowDef: ArrowDef[F]
|
||||
}
|
||||
|
||||
case class LocalArrow[F[_], L](arr: ArrowTypeToken[F]) extends ArrowMarker[F] {
|
||||
override def pointer: Token[F] = arr
|
||||
|
||||
override def arrowDef: ArrowDef[F] = arr
|
||||
}
|
||||
|
||||
case class FuncArrow[F[_], L](funcDef: DefFunc[F, L]) extends ArrowMarker[F] {
|
||||
override def pointer: Token[F] = funcDef.head.name
|
||||
|
||||
override def arrowDef: ArrowDef[F] = funcDef.head.arrowDef
|
||||
}
|
||||
|
||||
case class AbilityArrow[F[_], L](ability: Ability[F], arr: ArrowTypeToken[F]) extends ArrowMarker[F] {
|
||||
override def pointer: Token[F] = arr
|
||||
|
||||
override def arrowDef: ArrowDef[F] = arr
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.lexer.Token
|
||||
import cats.Functor
|
||||
|
||||
trait Marker[F[_]] {
|
||||
def pointer: Token[F]
|
||||
|
||||
def toError(str: String)(implicit F: Functor[F]): F[String] = pointer.as(str)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
package aqua.context.marker
|
||||
|
||||
import aqua.parser.DefType
|
||||
import aqua.parser.lexer.{CustomTypeToken, Token, TypeToken}
|
||||
|
||||
sealed trait TypeMarker[F[_]] extends Marker[F]
|
||||
|
||||
case class TypeAlias[F[_], L](alias: CustomTypeToken[F], forType: TypeToken[F]) extends TypeMarker[F] {
|
||||
override def pointer: Token[F] = alias
|
||||
}
|
||||
|
||||
case class TypeDef[F[_], L](forDef: DefType[F, L]) extends TypeMarker[F] {
|
||||
override def pointer: Token[F] = forDef.name
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package aqua.context.scope
|
||||
|
||||
sealed trait Mode
|
||||
case object ParMode extends Mode
|
||||
case object XorMode extends Mode
|
@ -1,17 +0,0 @@
|
||||
package aqua.context.scope
|
||||
|
||||
import aqua.parser.lexer.Value
|
||||
import cats.Functor
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class Scope[F[_]](mode: Option[F[Mode]] = None, peerId: Option[Value[F]] = None) {
|
||||
def par(f: F[Unit])(implicit F: Functor[F]): Scope[F] = copy(mode = Some(f.as(ParMode)))
|
||||
|
||||
def xor(f: F[Unit])(implicit F: Functor[F]): Scope[F] = copy(mode = Some(f.as(XorMode)))
|
||||
|
||||
def on(v: Value[F]): Scope[F] = copy(peerId = Some(v))
|
||||
|
||||
def unsetMode: Scope[F] = copy(mode = None)
|
||||
|
||||
def unsetPeer: Scope[F] = copy(peerId = None)
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package aqua.context.scope
|
||||
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.{Block, FuncExpr, On, Par}
|
||||
import cats.Functor
|
||||
import shapeless._
|
||||
|
||||
class ScopeWalker[F[_]: Functor, I <: HList, O <: HList](extend: Walker[F, I, O]) extends Walker[F, I, Scope[F] :: O] {
|
||||
type Ctx = Scope[F] :: O
|
||||
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, I], last: Ctx): Ctx =
|
||||
(group match {
|
||||
case _: Par[F, I] =>
|
||||
last.head.unsetMode
|
||||
case _: On[F, I] =>
|
||||
last.head.unsetPeer
|
||||
case _ =>
|
||||
last.head
|
||||
}) :: extend.exitFuncExprGroup(group, last.tail)
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, I], prev: Ctx): Ctx =
|
||||
(op match {
|
||||
case p: Par[F, I] => prev.head.par(p.f)
|
||||
case o: On[F, I] => prev.head.on(o.peer)
|
||||
case _ => prev.head
|
||||
}) :: extend.funcOpCtx(op, prev.tail)
|
||||
|
||||
override def blockCtx(block: Block[F, I]): Ctx = Scope[F]() :: extend.blockCtx(block)
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[Walker.DupError[F]] =
|
||||
extend.duplicates(prev.tail, next.tail)
|
||||
|
||||
override def emptyCtx: Out = Scope[F]() :: extend.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out =
|
||||
Scope[F]() :: extend.combineBlockCtx(prev.tail, block.tail)
|
||||
|
||||
override def unresolved(ctx: Out): (List[Walker.UnresolvedError[F]], Out) = Nil -> ctx
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package aqua.context.walker
|
||||
|
||||
import aqua.parser.lexer._
|
||||
import cats.Comonad
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class Acc[T](data: Map[String, NonEmptyList[T]]) {
|
||||
|
||||
def add(other: Acc[T], subtract: Set[String] = Set.empty): Acc[T] =
|
||||
copy(data = (other.data -- subtract).foldLeft(data) {
|
||||
case (accD, (k, v)) =>
|
||||
accD.updatedWith(k)(dv => Option(dv.fold(v)(_ ++ v.toList)))
|
||||
})
|
||||
|
||||
def keys: Set[String] = data.keySet
|
||||
|
||||
def sub(n: String): Acc[T] = copy(data = data - n)
|
||||
|
||||
def erase: Acc[T] = Acc.empty[T]
|
||||
|
||||
def addOne(n: String, v: T): Acc[T] = add(Acc.one(n, v))
|
||||
|
||||
def takeKeys(keys: Set[String]): Acc[T] = copy(data = data.view.filterKeys(keys).toMap)
|
||||
}
|
||||
|
||||
object Acc {
|
||||
def empty[T]: Acc[T] = Acc(Map.empty[String, NonEmptyList[T]])
|
||||
|
||||
def one[T](n: String, v: T): Acc[T] = Acc(Map(n -> NonEmptyList.one(v)))
|
||||
|
||||
def fromValues[F[_]: Comonad](args: List[Value[F]]): Acc[Value[F]] =
|
||||
args.collect {
|
||||
case arg @ VarLambda(name, _) => Acc.one[Value[F]](name.name.extract, arg)
|
||||
}.foldLeft(Acc.empty[Value[F]])(_ add _)
|
||||
|
||||
def fromType[F[_]: Comonad](t: TypeToken[F]): Acc[CustomTypeToken[F]] =
|
||||
t match {
|
||||
case ct: CustomTypeToken[F] =>
|
||||
Acc.one(ct.name.extract, ct)
|
||||
case at: ArrayTypeToken[F] =>
|
||||
fromType(at.data)
|
||||
case at: ArrowTypeToken[F] =>
|
||||
at.args
|
||||
.widen[TypeToken[F]]
|
||||
.prependedAll(at.res)
|
||||
.map[Acc[CustomTypeToken[F]]](v => fromType[F](v))
|
||||
.foldLeft[Acc[CustomTypeToken[F]]](Acc.empty[CustomTypeToken[F]])(_ add _)
|
||||
case _: BasicTypeToken[F] =>
|
||||
Acc.empty
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package aqua.context.walker
|
||||
|
||||
import aqua.context.marker.Marker
|
||||
import aqua.context.scope.{Mode, ParMode, XorMode}
|
||||
import aqua.parser.lexer.Token
|
||||
|
||||
case class ExpectAndDefine[In, Out](
|
||||
expectAcc: Acc[In],
|
||||
defineAcc: Map[String, Out]
|
||||
) {
|
||||
type Self = ExpectAndDefine[In, Out]
|
||||
|
||||
def combine(other: Self, mode: Option[Mode]): Self =
|
||||
mode match {
|
||||
case None => combineSeq(other)
|
||||
case Some(XorMode) => combineXor(other)
|
||||
case Some(ParMode) => combinePar(other)
|
||||
}
|
||||
|
||||
def combineSeq(other: Self): Self =
|
||||
copy(expectAcc = expectAcc.add(other.expectAcc, defineAcc.keySet), defineAcc = defineAcc ++ other.defineAcc)
|
||||
|
||||
def combinePar(other: Self): Self =
|
||||
copy(expectAcc = expectAcc add other.expectAcc, defineAcc = defineAcc ++ other.defineAcc)
|
||||
|
||||
def combineXor(other: Self): Self =
|
||||
copy(expectAcc = expectAcc add other.expectAcc)
|
||||
|
||||
def expect(addition: Acc[In]): Self =
|
||||
copy(expectAcc = expectAcc add addition)
|
||||
|
||||
def resolved(rem: String): Self =
|
||||
copy(expectAcc = expectAcc sub rem)
|
||||
|
||||
def defined(k: String, v: Out): Self =
|
||||
copy(defineAcc = defineAcc + (k -> v))
|
||||
|
||||
def collectDefinitions(pf: PartialFunction[Out, Out]): Self =
|
||||
copy(defineAcc = defineAcc.filter {
|
||||
case (_, v) if pf.isDefinedAt(v) => true
|
||||
case _ => false
|
||||
})
|
||||
|
||||
def undefine(rem: String): Self =
|
||||
copy(defineAcc = defineAcc - rem)
|
||||
|
||||
def clearDefinitions: Self = copy(defineAcc = Map.empty[String, Out])
|
||||
def clearExpectations: Self = copy(expectAcc = expectAcc.erase)
|
||||
}
|
||||
|
||||
object ExpectAndDefine {
|
||||
|
||||
def empty[F[_], In <: Token[F], Out <: Marker[F]]: ExpectAndDefine[In, Out] =
|
||||
ExpectAndDefine(Acc.empty[In], Map.empty[String, Out])
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package aqua.context.walker
|
||||
|
||||
import aqua.context.marker.Marker
|
||||
import aqua.context.walker.Walker.{DupError, UnresolvedError}
|
||||
import aqua.parser._
|
||||
import aqua.parser.lexer.Token
|
||||
import cats.Functor
|
||||
import cats.data.Validated.{Invalid, Valid}
|
||||
import cats.data.{NonEmptyList, ValidatedNel}
|
||||
import cats.syntax.functor._
|
||||
import shapeless._
|
||||
|
||||
import scala.collection.immutable.Queue
|
||||
|
||||
trait Walker[F[_], I <: HList, O <: HList] {
|
||||
type Out = O
|
||||
|
||||
def exitFuncExprGroup(group: FuncExpr[F, I], last: O): O
|
||||
|
||||
def funcOpCtx(op: FuncExpr[F, I], prev: O): O
|
||||
|
||||
def blockCtx(block: Block[F, I]): O
|
||||
|
||||
def mapFuncOp(op: FuncExpr[F, I], prev: O): FuncExpr[F, O] = {
|
||||
val ctx = funcOpCtx(op, prev)
|
||||
op match {
|
||||
case p @ Par(_, inner, _) =>
|
||||
val inOp = mapFuncOp(inner, ctx)
|
||||
p.copy(op = inOp.asInstanceOf[InstrExpr[F, O]], context = exitFuncExprGroup(p, inOp.context))
|
||||
case o @ On(_, ops, _) =>
|
||||
val (inOps, inCtx) = mapFuncOps(ops, ctx)
|
||||
o.copy(
|
||||
ops = inOps.asInstanceOf[NonEmptyList[ExecExpr[F, O]]],
|
||||
context = exitFuncExprGroup(o, exitFuncExprGroup(o, inCtx))
|
||||
)
|
||||
case _ =>
|
||||
op.as(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
def mapFuncOps(ops: NonEmptyList[FuncExpr[F, I]], context: O): (NonEmptyList[FuncExpr[F, O]], O) = {
|
||||
val (queue, lastCtx) = ops.foldLeft[(Queue[FuncExpr[F, O]], O)](Queue.empty -> context) {
|
||||
case ((acc, o), op) =>
|
||||
val mapped = mapFuncOp(op, o)
|
||||
acc.appended(mapped) -> mapped.context
|
||||
}
|
||||
NonEmptyList.fromListUnsafe(queue.toList) -> lastCtx
|
||||
}
|
||||
|
||||
def emptyCtx: Out
|
||||
|
||||
def combineBlockCtx(prev: Out, block: Out): Out
|
||||
|
||||
def mapBlock(block: Block[F, I], prevCtx: Out): (List[Walker.Error[F]], Block[F, Out]) = {
|
||||
val ctx = blockCtx(block)
|
||||
|
||||
val dupErr = duplicates(prevCtx, ctx)
|
||||
val (unresolvedErrs, combinedBlock) = block match {
|
||||
case df @ DefFunc(_, body, _) =>
|
||||
val (newBody, bodyCtx) = mapFuncOps(body, ctx)
|
||||
val (errs, bCtx) = unresolved(combineBlockCtx(prevCtx, bodyCtx))
|
||||
errs -> df.copy(body = newBody, context = bCtx)
|
||||
case ds: DefService[F, I] =>
|
||||
val (unresErrs, bCtx) = unresolved(combineBlockCtx(prevCtx, ctx))
|
||||
unresErrs -> ds.copy(context = bCtx)
|
||||
case al: DefAlias[F, I] =>
|
||||
val (unresErrs, bCtx) = unresolved(combineBlockCtx(prevCtx, ctx))
|
||||
unresErrs -> al.copy(context = bCtx)
|
||||
case dt: DefType[F, I] =>
|
||||
val (unresErrs, bCtx) = unresolved(combineBlockCtx(prevCtx, ctx))
|
||||
unresErrs -> dt.copy(context = bCtx)
|
||||
}
|
||||
|
||||
(dupErr ::: unresolvedErrs) -> combinedBlock
|
||||
}
|
||||
|
||||
def andThen[O2 <: HList](f: Walker[F, I, O] => Walker[F, I, O2]): Walker[F, I, O2] = f(this)
|
||||
|
||||
def duplicates(prev: Out, next: Out): List[DupError[F]]
|
||||
def unresolved(ctx: Out): (List[UnresolvedError[F]], Out)
|
||||
|
||||
def walkValidate(blocks: List[Block[F, I]]): ValidatedNel[Walker.Error[F], List[Block[F, Out]]] = {
|
||||
val (errs, _, nblocks) =
|
||||
blocks.foldLeft[(Queue[Walker.Error[F]], Out, Queue[Block[F, Out]])]((Queue.empty, emptyCtx, Queue.empty)) {
|
||||
case ((errs, prevCtx, blockAcc), next) =>
|
||||
val (addErrs, mappedBlock) = mapBlock(next, prevCtx)
|
||||
(errs.appendedAll(addErrs), mappedBlock.context, blockAcc.appended(mappedBlock))
|
||||
}
|
||||
NonEmptyList
|
||||
.fromList(errs.toList)
|
||||
.fold[ValidatedNel[Walker.Error[F], List[Block[F, Out]]]](Valid(nblocks.toList))(Invalid(_))
|
||||
}
|
||||
}
|
||||
|
||||
object Walker {
|
||||
|
||||
trait Error[F[_]] {
|
||||
def toStringF(implicit F: Functor[F]): F[String]
|
||||
}
|
||||
trait DupError[F[_]] extends Error[F]
|
||||
trait UnresolvedError[F[_]] extends Error[F]
|
||||
|
||||
def collectDups[F[_], A <: Token[F], B <: Marker[F]](
|
||||
prev: ExpectAndDefine[A, B],
|
||||
next: ExpectAndDefine[A, B],
|
||||
toErr: (String, B) => DupError[F]
|
||||
): List[DupError[F]] =
|
||||
next.defineAcc.view.filterKeys(prev.defineAcc.keySet).toList.map {
|
||||
case (k, v) => toErr(k, v)
|
||||
}
|
||||
|
||||
def collectUnresolved[F[_], A <: Token[F], B <: Marker[F]](
|
||||
expDef: ExpectAndDefine[A, B],
|
||||
toErr: (String, A) => UnresolvedError[F]
|
||||
): (List[UnresolvedError[F]], ExpectAndDefine[A, B]) =
|
||||
expDef.expectAcc.data.flatMap {
|
||||
case (k, vs) => vs.toList.map(toErr(k, _))
|
||||
}.toList -> expDef.clearExpectations
|
||||
|
||||
def hnil[F[_]]: Walker[F, HNil, HNil] =
|
||||
new Walker[F, HNil, HNil] {
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, HNil], last: HNil): HNil = HNil
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, HNil], prev: HNil): HNil = HNil
|
||||
|
||||
override def blockCtx(block: Block[F, HNil]): HNil = HNil
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] = Nil
|
||||
|
||||
override def emptyCtx: Out = HNil
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out = HNil
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = Nil -> ctx
|
||||
}
|
||||
|
||||
def noopFrom[F[_], I <: HList, O <: HList](from: Walker[F, I, O]): Walker[F, O, O] =
|
||||
new Walker[F, O, O] {
|
||||
override def exitFuncExprGroup(group: FuncExpr[F, O], last: O): O = last
|
||||
|
||||
override def funcOpCtx(op: FuncExpr[F, O], prev: O): O = prev
|
||||
|
||||
override def blockCtx(block: Block[F, O]): O = block.context
|
||||
|
||||
override def emptyCtx: Out = from.emptyCtx
|
||||
|
||||
override def combineBlockCtx(prev: Out, block: Out): Out = block
|
||||
|
||||
override def duplicates(prev: Out, next: Out): List[DupError[F]] = Nil
|
||||
|
||||
override def unresolved(ctx: Out): (List[UnresolvedError[F]], Out) = (Nil, ctx)
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.DataTypeToken.`datatypedef`
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.TypeToken.`typedef`
|
||||
import aqua.parser.lexer.{Ability, AquaArrowType, ArrowTypeToken, CustomTypeToken, DataTypeToken, Name, TypeToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Comonad
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.parse.{Parser => P, Parser0 => P0}
|
||||
import cats.syntax.comonad._
|
||||
import shapeless.HNil
|
||||
|
||||
sealed trait Block[F[_], L] extends Expression[F, L]
|
||||
|
||||
case class DefType[F[_], L](
|
||||
name: CustomTypeToken[F],
|
||||
fields: NonEmptyMap[String, (Name[F], DataTypeToken[F])],
|
||||
context: L
|
||||
) extends Block[F, L]
|
||||
|
||||
case class DefService[F[_], L](name: Ability[F], funcs: NonEmptyMap[String, ArrowTypeToken[F]], context: L)
|
||||
extends Block[F, L]
|
||||
|
||||
// TODO arg is either Var, or ArrowName
|
||||
case class FuncHead[F[_]](
|
||||
name: Name[F],
|
||||
args: List[(String, F[String], TypeToken[F])],
|
||||
ret: Option[DataTypeToken[F]]
|
||||
) {
|
||||
|
||||
def arrowDef: AquaArrowType[F] =
|
||||
AquaArrowType(args.map(_._3), ret)
|
||||
}
|
||||
|
||||
case class DefFunc[F[_], L](head: FuncHead[F], body: NonEmptyList[FuncExpr[F, L]], context: L) extends Block[F, L]
|
||||
|
||||
case class DefAlias[F[_], L](alias: CustomTypeToken[F], target: TypeToken[F], context: L) extends Block[F, L]
|
||||
|
||||
object DefType {
|
||||
|
||||
def `dname`[F[_]: LiftParser: Comonad]: P[CustomTypeToken[F]] =
|
||||
`data` *> ` ` *> CustomTypeToken.ct[F] <* ` `.? <* `:` <* ` \n+`
|
||||
|
||||
def `dataname`[F[_]: LiftParser: Comonad](indent: String): P[(Name[F], DataTypeToken[F])] =
|
||||
(Name.p[F] <* ` : `) ~ `datatypedef`
|
||||
|
||||
def `deftype`[F[_]: LiftParser: Comonad]: P[DefType[F, HNil]] =
|
||||
(`dname` ~ indented(`dataname`(_), "")).map {
|
||||
case (n, t) ⇒ DefType(n, t.map(kv => kv._1.name.extract -> kv).toNem, HNil)
|
||||
}
|
||||
}
|
||||
|
||||
object DefFunc {
|
||||
|
||||
def `funcname`[F[_]: LiftParser: Comonad]: P[Name[F]] = ` `.?.with1 *> `func` *> ` ` *> Name.p <* ` `.?
|
||||
|
||||
def `funcargs`[F[_]: LiftParser: Comonad]: P[List[(String, F[String], TypeToken[F])]] =
|
||||
`(` *> comma0((`name`.lift <* ` : `) ~ `typedef`).map(_.map(kv => (kv._1.extract, kv._1, kv._2))) <* `)`
|
||||
|
||||
def `funchead`[F[_]: LiftParser: Comonad]: P[FuncHead[F]] =
|
||||
(`funcname` ~ (`funcargs` ~ (`->` *> `datatypedef`).?)).map {
|
||||
case (n, (a, r)) ⇒ FuncHead(n, a, r)
|
||||
}
|
||||
|
||||
// TODO: if funchead has return type, for the last op, add extract, add Return.reply(extracted)
|
||||
def `deffunc`[F[_]: LiftParser: Comonad]: P[DefFunc[F, HNil]] =
|
||||
((`funchead` <* ` : ` <* ` \n+`) ~ FuncExpr.body).map {
|
||||
case (h, b) ⇒ DefFunc(h, b, HNil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object DefService {
|
||||
|
||||
// TODO use name's [F] for ArrowName
|
||||
def `funcdef`[F[_]: LiftParser: Comonad]: P[(String, ArrowTypeToken[F])] =
|
||||
(`name` <* ` : `) ~ ArrowTypeToken.`arrowdef`
|
||||
|
||||
def `servicename`[F[_]: LiftParser: Comonad]: P[Ability[F]] =
|
||||
`service` *> ` ` *> Ability.ab[F] <* ` `.? <* `:` <* ` \n+`
|
||||
|
||||
// TODO switch to funchead?
|
||||
def `defservice`[F[_]: LiftParser: Comonad]: P[DefService[F, HNil]] =
|
||||
(`servicename` ~ indented(_ => `funcdef`, "").map(_.toNem)).map {
|
||||
case (n, f) ⇒ DefService(n, f, HNil)
|
||||
}
|
||||
}
|
||||
|
||||
object DefAlias {
|
||||
|
||||
def `defalias`[F[_]: LiftParser: Comonad]: P[DefAlias[F, HNil]] =
|
||||
((`alias` *> ` ` *> CustomTypeToken.ct[F] <* ` : `) ~ `typedef`).map {
|
||||
case (ct, t) => DefAlias(ct, t, HNil)
|
||||
}
|
||||
}
|
||||
|
||||
object Block {
|
||||
|
||||
def block[F[_]: LiftParser: Comonad]: P[Block[F, HNil]] =
|
||||
` \n+`.rep0.with1 *> P.oneOf(
|
||||
DefType.`deftype` ::
|
||||
DefService.`defservice` ::
|
||||
DefFunc.`deffunc` ::
|
||||
DefAlias.`defalias` ::
|
||||
Nil
|
||||
)
|
||||
|
||||
def blocks[F[_]: LiftParser: Comonad]: P0[List[Block[F, HNil]]] =
|
||||
P.repSep0(block[F], ` \n+`) <* ` \n+`.?
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package aqua.parser
|
||||
|
||||
trait Expression[F[_], L] {
|
||||
def context: L
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Ability, Name, Value}
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Parser => P}
|
||||
import aqua.parser.lexer.Value.`value`
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.comonad._
|
||||
import shapeless.HNil
|
||||
|
||||
sealed trait FuncExpr[F[_], L] extends Expression[F, L]
|
||||
sealed trait InstrExpr[F[_], L] extends FuncExpr[F, L]
|
||||
|
||||
sealed trait ExecExpr[F[_], L] extends InstrExpr[F, L]
|
||||
|
||||
sealed trait CallExpr[F[_], L] extends ExecExpr[F, L] {
|
||||
def arrow: Name[F]
|
||||
def args: List[Value[F]]
|
||||
}
|
||||
|
||||
case class FuncCall[F[_], L](arrow: Name[F], args: List[Value[F]], context: L) extends CallExpr[F, L]
|
||||
|
||||
case class AbilityFuncCall[F[_], L](
|
||||
ability: Ability[F],
|
||||
funcName: Name[F],
|
||||
arrow: Name[F],
|
||||
args: List[Value[F]],
|
||||
context: L
|
||||
) extends CallExpr[F, L]
|
||||
|
||||
case class Extract[F[_], L](vr: Name[F], from: CallExpr[F, L], context: L) extends ExecExpr[F, L]
|
||||
|
||||
case class On[F[_], L](peer: Value[F], ops: NonEmptyList[ExecExpr[F, L]], context: L) extends InstrExpr[F, L]
|
||||
|
||||
case class Par[F[_], L](f: F[Unit], op: InstrExpr[F, L], context: L) extends FuncExpr[F, L]
|
||||
|
||||
// TODO: can't be in Par, can be in On
|
||||
sealed trait AbilityResolve[F[_], L] extends ExecExpr[F, L] {
|
||||
def ability: Ability[F]
|
||||
}
|
||||
case class AbilityId[F[_], L](ability: Ability[F], id: Value[F], context: L) extends AbilityResolve[F, L]
|
||||
|
||||
object FuncExpr {
|
||||
|
||||
def funcCall[F[_]: LiftParser: Comonad]: P[FuncCall[F, HNil]] =
|
||||
(Name.p[F] ~ P.repSep0(`value`, `,`).between(`(`, `)`)).map {
|
||||
case (fnName, args) ⇒ FuncCall(fnName, args, HNil)
|
||||
}
|
||||
|
||||
def abilityFuncCall[F[_]: LiftParser: Comonad]: P[AbilityFuncCall[F, HNil]] =
|
||||
((Ability.ab[F] <* `.`) ~ funcCall).map {
|
||||
case (abName, fc) ⇒
|
||||
AbilityFuncCall(
|
||||
abName,
|
||||
fc.arrow,
|
||||
Name(fc.arrow.as(abName.name.extract + "." + fc.arrow.name.extract)),
|
||||
fc.args,
|
||||
HNil
|
||||
)
|
||||
}
|
||||
|
||||
def callOp[F[_]: LiftParser: Comonad]: P[CallExpr[F, HNil]] =
|
||||
P.oneOf(funcCall[F] :: abilityFuncCall[F] :: Nil)
|
||||
|
||||
def extract[F[_]: LiftParser: Comonad]: P[Extract[F, HNil]] =
|
||||
((Name.p <* `<-`) ~ callOp[F]).map {
|
||||
case (v, f) ⇒ Extract(v, f, HNil)
|
||||
}
|
||||
|
||||
def abilityResolve[F[_]: LiftParser: Comonad]: P[AbilityResolve[F, HNil]] =
|
||||
((Ability.ab <* ` `) ~ `value`).map {
|
||||
case (n, v) ⇒ AbilityId[F, HNil](n, v, HNil)
|
||||
}.widen[AbilityResolve[F, HNil]]
|
||||
|
||||
// TODO can't be in Par, can be in On
|
||||
def execOp[F[_]: LiftParser: Comonad]: P[ExecExpr[F, HNil]] =
|
||||
P.oneOf(
|
||||
callOp.backtrack
|
||||
:: abilityResolve.backtrack
|
||||
:: extract :: Nil
|
||||
)
|
||||
|
||||
def startOn[F[_]: LiftParser: Comonad]: P[Value[F]] = `on` *> ` ` *> `value` <* ` `.? <* `:` <* ` \n+`
|
||||
|
||||
def execOn[F[_]: LiftParser: Comonad](indent: String): P[On[F, HNil]] =
|
||||
(startOn ~ indented(_ => execOp[F], indent)).map {
|
||||
case (v, i) ⇒ On(v, i, HNil)
|
||||
}
|
||||
|
||||
def instrOp[F[_]: LiftParser: Comonad](indent: String): P[InstrExpr[F, HNil]] =
|
||||
P.oneOf(
|
||||
execOn(indent).backtrack
|
||||
:: execOp :: Nil
|
||||
)
|
||||
|
||||
def parOp[F[_]: LiftParser: Comonad](indent: String): P[Par[F, HNil]] =
|
||||
((`par`.lift <* ` `) ~ instrOp[F](indent)).map(pi => Par(pi._1, pi._2, HNil))
|
||||
|
||||
def `funcop`[F[_]: LiftParser: Comonad](indent: String): P[FuncExpr[F, HNil]] =
|
||||
P.oneOf(parOp(indent).backtrack :: instrOp(indent) :: Nil)
|
||||
|
||||
def body[F[_]: LiftParser: Comonad]: P[NonEmptyList[FuncExpr[F, HNil]]] = indented(`funcop`(_), "")
|
||||
|
||||
implicit def funcOpFunctor[F[_]]: Functor[FuncExpr[F, *]] =
|
||||
new Functor[FuncExpr[F, *]] {
|
||||
|
||||
override def map[A, B](fa: FuncExpr[F, A])(f: A => B): FuncExpr[F, B] =
|
||||
fa match {
|
||||
case fc @ FuncCall(_, _, ctx) => fc.copy(context = f(ctx))
|
||||
case afc @ AbilityFuncCall(_, _, _, _, ctx) => afc.copy(context = f(ctx))
|
||||
case e @ Extract(_, afc @ AbilityFuncCall(_, _, _, _, actx), ctx) =>
|
||||
e.copy(from = afc.copy(context = f(actx)), context = f(ctx))
|
||||
case e @ Extract(_, fc @ FuncCall(_, _, fctx), ctx) =>
|
||||
e.copy(from = fc.copy(context = f(fctx)), context = f(ctx))
|
||||
case on @ On(_, ops, ctx) => on.copy(ops = ops.map(map(_)(f).asInstanceOf[ExecExpr[F, B]]), context = f(ctx))
|
||||
case p @ Par(_, op, ctx) => p.copy(op = map(op)(f).asInstanceOf[InstrExpr[F, B]], context = f(ctx))
|
||||
case aid @ AbilityId(_, _, ctx) => aid.copy(context = f(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.scope.{Scope, ScopeWalker}
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import cats.Id
|
||||
import cats.data.Validated.Invalid
|
||||
import cats.data.{NonEmptyList, Validated}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import shapeless._
|
||||
|
||||
class AbilitiesResolveSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
val walker = Walker.hnil[Id].andThen(new ScopeWalker(_)).andThen(new AbilitiesResolve.ExpDef(_))
|
||||
|
||||
def parseBlocks(str: String): List[Block[Id, AbilitiesResolve[Id] :: Scope[Id] :: HNil]] =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
.toEither
|
||||
.right
|
||||
.value
|
||||
|
||||
def parseBlocksV(str: String) =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
|
||||
"Abilities resolve walker" should "collect no ability resolutions from a function" in {
|
||||
val bs = parseBlocks("""
|
||||
|func some():
|
||||
| Peer "peer"
|
||||
| Peer.timestamp()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
bs.length should be(1)
|
||||
val ctx = bs.head.context
|
||||
val acc = ctx.head.expDef
|
||||
acc.expectAcc.keys should be('empty)
|
||||
acc.defineAcc.keys should be('empty)
|
||||
}
|
||||
|
||||
"Abilities resolve walker" should "collect ability expectations from two functions" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| x <- First.arr()
|
||||
|
|
||||
|
|
||||
|func other(x: u32):
|
||||
| Peer "smth"
|
||||
| y <- Second.arr2(x)
|
||||
| Peer.timestamp()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
"Abilities resolve walker" should "resolve abilities in a function" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| y <- Smth.foo()
|
||||
| x <- Ab.f(z, y)
|
||||
|
|
||||
|alias T: u32
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.scope.{Scope, ScopeWalker}
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
import cats.Id
|
||||
import cats.data.{NonEmptyList, Validated}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import cats.data.Validated.Invalid
|
||||
import shapeless._
|
||||
|
||||
class ArgsAndVarsSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
val walker =
|
||||
Walker.hnil[Id].andThen(new ScopeWalker(_)).andThen(new ArgsAndVars.ExpDef(_))
|
||||
|
||||
def parseBlocks(str: String): List[Block[Id, ArgsAndVars[Id] :: Scope[Id] :: HNil]] =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
.toEither
|
||||
.right
|
||||
.value
|
||||
|
||||
def parseBlocksV(str: String) =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
|
||||
"Arguments and vars walker" should "collect no vars in a single function" in {
|
||||
val bs = parseBlocks("""
|
||||
|func some():
|
||||
| x <- arr()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
bs.length should be(1)
|
||||
val ctx = bs.head.context
|
||||
ctx.tail.head should be(Scope[Id]())
|
||||
val acc = ctx.head.expDef
|
||||
acc.expectAcc.keys should be('empty)
|
||||
acc.defineAcc.keys should be('empty)
|
||||
}
|
||||
|
||||
"Arguments and vars walker" should "collect no vars in two functions" in {
|
||||
val bs = parseBlocks("""
|
||||
|func some():
|
||||
| x <- arr()
|
||||
|
|
||||
|
|
||||
|func other(x: u32):
|
||||
| y <- arr2(x)
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
bs.length should be(2)
|
||||
val ctx = bs.last.context
|
||||
ctx.tail.head should be(Scope[Id]())
|
||||
val acc = ctx.head.expDef
|
||||
acc.expectAcc.keys should be('empty)
|
||||
acc.defineAcc.keys should be('empty)
|
||||
}
|
||||
|
||||
"Arguments and vars walker" should "catch undefined var in a function" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| x <- f(z, y)
|
||||
|
|
||||
|alias T: u32
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package aqua.context
|
||||
|
||||
import aqua.context.walker.Walker
|
||||
import aqua.parser.Block
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import cats.Id
|
||||
import cats.data.Validated.Invalid
|
||||
import cats.data.{NonEmptyList, Validated}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import shapeless._
|
||||
|
||||
class ArrowsSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
val walker = Walker.hnil[Id].andThen(new Arrows.ExpDef(_))
|
||||
|
||||
def parseBlocks(str: String): List[Block[Id, Arrows[Id] :: HNil]] =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
.toEither
|
||||
.right
|
||||
.value
|
||||
|
||||
def parseBlocksV(str: String) =
|
||||
Validated
|
||||
.fromEither(Block.blocks[Id].parseAll(str))
|
||||
.leftMap(_.toString)
|
||||
.leftMap(NonEmptyList.one)
|
||||
.andThen(
|
||||
walker.walkValidate
|
||||
)
|
||||
|
||||
"Arrows walker" should "collect no local arrows from a function" in {
|
||||
val bs = parseBlocks("""
|
||||
|func some(b: -> A):
|
||||
| b()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
bs.length should be(1)
|
||||
val ctx = bs.head.context
|
||||
val acc = ctx.head.expDef
|
||||
|
||||
acc.expectAcc.keys should be('empty)
|
||||
acc.defineAcc.keys should be('empty)
|
||||
}
|
||||
|
||||
"Arrows walker" should "collect arrows from two functions" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| x <- First.arr()
|
||||
|
|
||||
|
|
||||
|func other(x: u32):
|
||||
| Peer "smth"
|
||||
| y <- Second.arr2(x)
|
||||
| Peer.timestamp()
|
||||
|
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (3)
|
||||
}
|
||||
|
||||
"Arrows walker" should "resolve abilities in a function" in {
|
||||
val res = parseBlocksV("""
|
||||
|func some():
|
||||
| y <- Smth.foo()
|
||||
| x <- Ab.f(z, y)
|
||||
|
|
||||
|alias T: u32
|
||||
|""".stripMargin)
|
||||
|
||||
res.isValid should be(false)
|
||||
val Invalid(errs) = res
|
||||
errs should have length (2)
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package aqua.parser
|
||||
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits._
|
||||
import cats.Id
|
||||
|
||||
class BlockSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
"blocks list" should "parse" in {
|
||||
Block.blocks[Id].parseAll("""func some(cb: -> u32):
|
||||
| cb()
|
||||
|
|
||||
|func other(cb: -> u32):
|
||||
| on 22:
|
||||
| cb()
|
||||
| cb()
|
||||
|
|
||||
|func third(cb: -> u32):
|
||||
| on 23:
|
||||
| cb()
|
||||
|
|
||||
|
|
||||
|
|
||||
|""".stripMargin).right.value.length should be(3)
|
||||
}
|
||||
|
||||
}
|
@ -16,7 +16,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
implicit def strToAb(str: String): Ability[Id] = Ability[Id](str)
|
||||
implicit def strToVar(str: String): Name[Id] = Name[Id](str)
|
||||
|
||||
/*
|
||||
def parseExpr(str: String) =
|
||||
FuncExpr.`funcop`[Id]("").parseAll(str).right.value
|
||||
|
||||
@ -151,7 +151,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
TODO: xor1
|
||||
|
@ -19,7 +19,7 @@ class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
implicit def scToBt(sc: ScalarType): BasicTypeToken[Id] = BasicTypeToken[Id](sc)
|
||||
implicit def strToAb(str: String): Ability[Id] = Ability[Id](str)
|
||||
implicit def strToVar(str: String): Name[Id] = Name[Id](str)
|
||||
|
||||
/*
|
||||
private val getTimeHead = FuncHead[Id](
|
||||
"getTime",
|
||||
List(
|
||||
@ -127,5 +127,5 @@ class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
HNil
|
||||
)
|
||||
)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user