Removed old contexts and expression parsers

This commit is contained in:
dmitry 2021-03-15 15:55:43 +03:00
parent 6b1f7dd0af
commit e3ad4f4ed1
27 changed files with 4 additions and 1700 deletions

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -1,5 +0,0 @@
package aqua.context.scope
sealed trait Mode
case object ParMode extends Mode
case object XorMode extends Mode

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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])
}

View File

@ -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)
}
}

View File

@ -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+`.?
}

View File

@ -1,5 +0,0 @@
package aqua.parser
trait Expression[F[_], L] {
def context: L
}

View File

@ -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))
}
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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
)
)
}
}*/
}