mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Names -> InOutAcc refactoring
This commit is contained in:
parent
4fa3d99123
commit
ae7ece2cb2
18
build.sbt
18
build.sbt
@ -6,19 +6,15 @@ val catsV = "2.4.2"
|
||||
lazy val root = project
|
||||
.in(file("."))
|
||||
.settings(
|
||||
name := "aqua-hll",
|
||||
version := "0.1.0",
|
||||
|
||||
scalaVersion := dottyVersion,
|
||||
|
||||
name := "aqua-hll",
|
||||
version := "0.1.0",
|
||||
scalaVersion := dottyVersion,
|
||||
mainClass in (Compile, run) := Some("aqua.Main"),
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"org.typelevel" %% "cats-effect" % "3.0.0-RC2",
|
||||
"org.typelevel" %% "cats-parse" % "0.3.1",
|
||||
"org.typelevel" %% "cats-free" % catsV
|
||||
"org.typelevel" %% "cats-parse" % "0.3.1",
|
||||
"org.typelevel" %% "cats-free" % catsV
|
||||
),
|
||||
|
||||
libraryDependencies += "org.scalactic" %% "scalactic" % "3.2.2" % Test,
|
||||
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.2" % Test
|
||||
libraryDependencies += "org.scalactic" %% "scalactic" % "3.2.5" % Test,
|
||||
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.5" % Test
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
package aqua
|
||||
|
||||
import aqua.parser.{ArrowType, Block, DataType, Type}
|
||||
import aqua.model.Names
|
||||
import aqua.parser.Block
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
import cats.parse.{Parser => P, Parser0 => P0}
|
||||
import aqua.parser.lift.Span
|
||||
import cats.syntax.validated._
|
||||
|
||||
object Aqua {
|
||||
import aqua.parser.lexer.Token._
|
||||
|
@ -1,9 +1,7 @@
|
||||
package aqua
|
||||
|
||||
import cats.effect.{IO, IOApp}
|
||||
import cats.syntax.show._
|
||||
import aqua.ir._
|
||||
import cats.data.{Kleisli, Validated}
|
||||
import cats.data.Validated
|
||||
|
||||
import scala.io.Source
|
||||
|
||||
|
@ -1,268 +0,0 @@
|
||||
package aqua
|
||||
|
||||
import aqua.parser.lexer.{Value, VarLambda}
|
||||
import aqua.parser._
|
||||
import cats.data.Validated.Valid
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
// Fully resolved Scope must have no expected abilities (all resolved)
|
||||
case class Names[F[_]](
|
||||
// None means "inherit"
|
||||
peerId: Option[F[Value]] = None,
|
||||
// Take vars, set vars
|
||||
// Data type is not yet known
|
||||
importData: Names.Acc[F, Value] = Names.Acc.empty[F, Value],
|
||||
exportData: Names.Acc[F, String] = Names.Acc.empty[F, String],
|
||||
// Abilities can be imported or set
|
||||
unresolvedAbilities: Names.Acc[F, String] = Names.Acc.empty[F, String],
|
||||
resolvedAbilities: Names.Acc[F, String] = Names.Acc.empty[F, String],
|
||||
// Abilities can be defined and expected
|
||||
expectedAbilities: Names.Acc[F, String] = Names.Acc.empty[F, String],
|
||||
definedAbilities: Names.Acc[F, DefService[F]] = Names.Acc.empty[F, DefService[F]],
|
||||
// Types can be defined and expected
|
||||
expectedTypes: Names.Acc[F, CustomType] = Names.Acc.empty[F, CustomType],
|
||||
definedTypes: Names.Acc[F, Either[Type, DefType[F]]] = Names.Acc.empty[F, Either[Type, DefType[F]]],
|
||||
// We don't know the types yet
|
||||
expectedArrows: Names.Acc[F, String] = Names.Acc.empty[F, String],
|
||||
definedFuncs: Names.Acc[F, DefFunc[F]] = Names.Acc.empty[F, DefFunc[F]],
|
||||
localArrows: Names.Acc[F, ArrowType] = Names.Acc.empty[F, ArrowType],
|
||||
// Set when know
|
||||
mode: Option[F[Names.CustomMode]] = None
|
||||
)
|
||||
|
||||
object Names {
|
||||
|
||||
case class Acc[F[_], T](data: Map[String, NonEmptyList[F[T]]]) {
|
||||
|
||||
def add(other: Acc[F, T], subtract: Set[String] = Set.empty): Acc[F, T] =
|
||||
copy(data = (other.data -- subtract).foldLeft(data) {
|
||||
case (accD, (k, v)) =>
|
||||
accD.updatedWith(k)(dv => Option(dv.fold(v)(_ ++ v.toList)))
|
||||
})
|
||||
|
||||
def keys = data.keySet
|
||||
|
||||
def sub(n: String) = copy(data = data - n)
|
||||
|
||||
def toErrors(toMsg: (String, F[T]) => String)(implicit F: Functor[F]): List[F[String]] =
|
||||
data.flatMap {
|
||||
case (n, vs) => vs.toList.map(ft => ft.as(toMsg(n, ft)))
|
||||
}.toList
|
||||
|
||||
def erase: Acc[F, T] = Acc.empty
|
||||
|
||||
def addOne(n: String, v: F[T]) = add(Acc.one(n, v))
|
||||
|
||||
def takeKeys(keys: Set[String]) = copy(data = data.view.filterKeys(keys).toMap)
|
||||
}
|
||||
|
||||
object Acc {
|
||||
def empty[F[_], T]: Acc[F, T] = Acc(Map.empty[String, NonEmptyList[F[T]]])
|
||||
|
||||
def str[F[_]: Comonad](v: F[String]): Acc[F, String] = one(v.extract, v)
|
||||
|
||||
def one[F[_], T](n: String, v: F[T]): Acc[F, T] = Acc(Map(n -> NonEmptyList.one(v)))
|
||||
}
|
||||
|
||||
sealed trait CustomMode
|
||||
case object ParMode extends CustomMode
|
||||
case object XorMode extends CustomMode
|
||||
|
||||
private def combineSeq[G[_]: Comonad](a: Names[G], b: Names[G]): Names[G] =
|
||||
a.copy(
|
||||
exportData = a.exportData add b.exportData,
|
||||
importData = a.importData.add(b.importData, a.exportData.keys),
|
||||
resolvedAbilities =
|
||||
if (b.peerId == a.peerId) a.resolvedAbilities add b.resolvedAbilities else a.resolvedAbilities,
|
||||
unresolvedAbilities = a.unresolvedAbilities.add(b.unresolvedAbilities, a.resolvedAbilities.keys),
|
||||
expectedArrows = a.expectedArrows.add(b.expectedArrows, a.definedFuncs.keys),
|
||||
definedFuncs = a.definedFuncs add b.definedFuncs,
|
||||
expectedTypes = a.expectedTypes.add(b.expectedTypes, a.definedTypes.keys),
|
||||
definedTypes = a.definedTypes add b.definedTypes,
|
||||
expectedAbilities = a.expectedAbilities.add(b.expectedAbilities, a.definedAbilities.keys),
|
||||
definedAbilities = a.definedAbilities add b.definedAbilities
|
||||
)
|
||||
|
||||
def funcOps[G[_]: Comonad](ops: NonEmptyList[G[FuncOp[G]]]): Names[G] =
|
||||
ops.map(funcOp[G]).foldLeft[Names[G]](Names[G]()) {
|
||||
case (acc, n) if n.mode.isEmpty =>
|
||||
combineSeq(acc, n)
|
||||
case (acc, n) if n.mode.exists(_.extract == ParMode) =>
|
||||
acc.copy(
|
||||
exportData = acc.exportData add n.exportData,
|
||||
importData = acc.importData add n.importData,
|
||||
unresolvedAbilities = acc.unresolvedAbilities add n.unresolvedAbilities,
|
||||
expectedArrows = acc.expectedArrows add n.expectedArrows,
|
||||
expectedTypes = acc.expectedTypes add n.expectedTypes,
|
||||
expectedAbilities = acc.expectedAbilities add n.expectedAbilities
|
||||
)
|
||||
case (acc, n) if n.mode.exists(_.extract == XorMode) =>
|
||||
acc.copy(
|
||||
importData = acc.importData add n.importData,
|
||||
unresolvedAbilities = acc.unresolvedAbilities add n.unresolvedAbilities,
|
||||
expectedArrows = acc.expectedArrows add n.expectedArrows,
|
||||
expectedTypes = acc.expectedTypes add n.expectedTypes,
|
||||
expectedAbilities = acc.expectedAbilities add n.expectedAbilities
|
||||
)
|
||||
}
|
||||
|
||||
private def valuesToNames[G[_]: Comonad](args: List[G[Value]]): Acc[G, Value] =
|
||||
args
|
||||
.collect(arg =>
|
||||
arg.extract match {
|
||||
case VarLambda(name, _) => Acc.one[G, Value](name, arg)
|
||||
}
|
||||
)
|
||||
.foldLeft(Acc.empty[G, Value])(_ add _)
|
||||
|
||||
def funcOp[G[_]: Comonad](op: G[FuncOp[G]]): Names[G] =
|
||||
op.extract match {
|
||||
case FuncCall(fname, fargs) =>
|
||||
Names[G](
|
||||
expectedArrows = Acc.str(fname),
|
||||
importData = valuesToNames(fargs)
|
||||
)
|
||||
case AbilityFuncCall(ab, fc) =>
|
||||
val funcNames = funcOp(fc.widen[FuncOp[G]])
|
||||
funcNames.copy(unresolvedAbilities = Acc.one(ab.extract, ab), expectedArrows = Acc.empty)
|
||||
case Extract(n, fn) =>
|
||||
val funcNames = funcOp(fn.widen[FuncOp[G]])
|
||||
funcNames.copy(exportData = Acc.str(n))
|
||||
case AbilityId(ab, id) =>
|
||||
Names[G](
|
||||
resolvedAbilities = Acc.str(ab),
|
||||
expectedAbilities = Acc.str(ab),
|
||||
importData = valuesToNames(id :: Nil)
|
||||
)
|
||||
case On(p, ops) =>
|
||||
val ns = funcOps(ops.map(_.widen[FuncOp[G]])).copy(peerId = Some(p))
|
||||
p.extract match {
|
||||
case VarLambda(name, _) =>
|
||||
ns.copy(importData = ns.importData add Acc.one(name, p))
|
||||
case _ => ns
|
||||
}
|
||||
case Par(op) =>
|
||||
funcOp(op.widen[FuncOp[G]]).copy(mode = Some(op.as(ParMode)))
|
||||
}
|
||||
|
||||
def typeAcc[G[_]: Comonad](t: G[Type]): Acc[G, CustomType] =
|
||||
t.extract match {
|
||||
case ct: CustomType =>
|
||||
Acc.one(ct.name, t.as(ct))
|
||||
case at: ArrayType =>
|
||||
typeAcc(t.as(at.data))
|
||||
case at: ArrowType =>
|
||||
(t.as[Type](at.res) :: at.args.map(t.as[Type](_)))
|
||||
.map[Acc[G, CustomType]](v => typeAcc[G](v))
|
||||
.foldLeft[Acc[G, CustomType]](Acc.empty[G, CustomType])(_ add _)
|
||||
case _: BasicType =>
|
||||
Acc.empty
|
||||
}
|
||||
|
||||
def funcHeadNames[G[_]: Comonad](head: FuncHead[G], body: Names[G]): Names[G] =
|
||||
head.args.foldLeft(
|
||||
body.copy(
|
||||
// We clear the mode, as functions are always defined in a sequence
|
||||
mode = None,
|
||||
// Function may have result type, but it's not names
|
||||
exportData = body.exportData.erase,
|
||||
// Until we have a notion for exporting abilities, they're cleaned
|
||||
resolvedAbilities = body.resolvedAbilities.erase,
|
||||
// Expected arrows are not reduced by this func's name, hence recursive functions are forbidden
|
||||
expectedTypes = head.args.map(_._3).map(typeAcc(_)).foldLeft(body.expectedTypes)(_ add _),
|
||||
// Even if peer is defined, it's defined inside
|
||||
peerId = None
|
||||
)
|
||||
) {
|
||||
case (names, (k, _, ft)) =>
|
||||
ft.extract match {
|
||||
case cd: CustomType =>
|
||||
names.copy(
|
||||
importData = names.importData sub k,
|
||||
expectedTypes = names.expectedTypes.addOne(cd.name, ft.as(cd))
|
||||
)
|
||||
case cd: ArrayType =>
|
||||
names.copy(
|
||||
importData = names.importData sub k,
|
||||
expectedTypes = names.expectedTypes add typeAcc[G](ft.as(cd.data))
|
||||
)
|
||||
case at: ArrowType =>
|
||||
names.copy(
|
||||
expectedArrows = names.expectedArrows sub k,
|
||||
localArrows = names.localArrows.addOne(k, ft.as(at))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
def funcNames[G[_]: Comonad](func: DefFunc[G]): Names[G] =
|
||||
funcHeadNames(func.head, funcOps(func.body))
|
||||
|
||||
def blockNames[G[_]: Comonad](block: Block[G]): Names[G] =
|
||||
block match {
|
||||
case func: DefFunc[G] =>
|
||||
funcNames(func).copy(
|
||||
localArrows = Acc.empty,
|
||||
definedFuncs = Acc.one(func.head.name.extract, func.head.name.as(func))
|
||||
)
|
||||
case deft: DefType[G] =>
|
||||
Names[G](
|
||||
definedTypes = Acc.one(deft.name.extract, deft.name.as(Right(deft))),
|
||||
expectedTypes = deft.fields.toNel.map {
|
||||
case (_, (_, tv)) =>
|
||||
typeAcc(tv.widen[Type])
|
||||
}.foldLeft(Acc.empty[G, CustomType])(_ add _)
|
||||
)
|
||||
case alias: DefAlias[G] =>
|
||||
Names[G](
|
||||
definedTypes = Acc.one[G, Either[Type, DefType[G]]](alias.alias.extract.name, alias.target.map(t => Left(t))),
|
||||
expectedTypes = typeAcc(alias.target)
|
||||
)
|
||||
case _ =>
|
||||
// Until we care about types, there's no imports/exports
|
||||
Names[G]()
|
||||
}
|
||||
|
||||
def foldVerify[G[_]: Comonad](input: List[Names[G]]): ValidatedNel[G[String], Names[G]] =
|
||||
input.foldLeft[ValidatedNel[G[String], Names[G]]](Valid(Names[G]())) {
|
||||
case (accE, ns) =>
|
||||
accE
|
||||
.andThen(acc =>
|
||||
Validated.fromEither[NonEmptyList[G[String]], Names[G]](
|
||||
NonEmptyList
|
||||
.fromList(
|
||||
ns.definedAbilities
|
||||
.takeKeys(acc.definedAbilities.keys)
|
||||
.toErrors((v, _) => s"Duplicate ability definition `$v`") :::
|
||||
ns.definedTypes
|
||||
.takeKeys(acc.definedTypes.keys)
|
||||
.toErrors((v, _) => s"Duplicate type definition `$v`") :::
|
||||
ns.definedFuncs
|
||||
.takeKeys(acc.definedFuncs.keys)
|
||||
.toErrors((v, _) => s"Duplicate func definition `$v`")
|
||||
)
|
||||
.toLeft(acc)
|
||||
)
|
||||
)
|
||||
.map(acc =>
|
||||
// TODO reject duplicate definitions
|
||||
combineSeq[G](acc, ns)
|
||||
)
|
||||
.andThen { acc =>
|
||||
Validated.fromEither[NonEmptyList[G[String]], Names[G]](
|
||||
NonEmptyList
|
||||
.fromList(
|
||||
acc.importData.toErrors((v, _) => s"Unknown variable `${v}`") :::
|
||||
acc.expectedArrows.toErrors((a, _) => s"Unknown arrow `${a}`") :::
|
||||
acc.unresolvedAbilities.toErrors((a, _) => s"Unresolved ability `${a}`") :::
|
||||
acc.expectedAbilities.toErrors((a, _) => s"Undefined ability `${a}`") :::
|
||||
acc.expectedTypes.toErrors((t, _) => s"Undefined type `$t`")
|
||||
)
|
||||
.toLeft(acc)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
56
src/main/scala/aqua/model/Acc.scala
Normal file
56
src/main/scala/aqua/model/Acc.scala
Normal file
@ -0,0 +1,56 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser.lexer.{ArrayType, ArrowType, BasicType, CustomType, Token, Type, Value, VarLambda}
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class Acc[F[_], T <: Token[F]](data: Map[String, NonEmptyList[T]]) {
|
||||
|
||||
def add(other: Acc[F, T], subtract: Set[String] = Set.empty): Acc[F, 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[F, T] = copy(data = data - n)
|
||||
|
||||
def erase: Acc[F, T] = Acc.empty
|
||||
|
||||
def addOne(n: String, v: T): Acc[F, T] = add(Acc.one(n, v))
|
||||
|
||||
def takeKeys(keys: Set[String]): Acc[F, T] = copy(data = data.view.filterKeys(keys).toMap)
|
||||
|
||||
def toErrors(toMsg: (String, T) => String)(implicit F: Functor[F]): List[F[String]] =
|
||||
data.flatMap {
|
||||
case (k, vs) => vs.toList.map(v => v.as(toMsg(k, v)))
|
||||
}.toList
|
||||
}
|
||||
|
||||
object Acc {
|
||||
def empty[F[_], T <: Token[F]]: Acc[F, T] = Acc(Map.empty[String, NonEmptyList[T]])
|
||||
|
||||
def one[F[_], T <: Token[F]](n: String, v: T): Acc[F, T] = Acc(Map(n -> NonEmptyList.one(v)))
|
||||
|
||||
def fromValues[F[_]: Comonad](args: List[Value[F]]): Acc[F, Value[F]] =
|
||||
args.collect {
|
||||
case arg @ VarLambda(name, _) => Acc.one[F, Value[F]](name.extract, arg)
|
||||
}.foldLeft(Acc.empty[F, Value[F]])(_ add _)
|
||||
|
||||
def fromType[F[_]: Comonad](t: Type[F]): Acc[F, CustomType[F]] =
|
||||
t match {
|
||||
case ct: CustomType[F] =>
|
||||
Acc.one(ct.name.extract, ct)
|
||||
case at: ArrayType[F] =>
|
||||
fromType(at.data)
|
||||
case at: ArrowType[F] =>
|
||||
(at.res :: at.args.widen[Type[F]])
|
||||
.map[Acc[F, CustomType[F]]](v => fromType[F](v))
|
||||
.foldLeft[Acc[F, CustomType[F]]](Acc.empty[F, CustomType[F]])(_ add _)
|
||||
case _: BasicType[F] =>
|
||||
Acc.empty
|
||||
}
|
||||
}
|
295
src/main/scala/aqua/model/InOutAcc.scala
Normal file
295
src/main/scala/aqua/model/InOutAcc.scala
Normal file
@ -0,0 +1,295 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser.{
|
||||
AbilityFuncCall,
|
||||
AbilityId,
|
||||
AbilityResolve,
|
||||
ArrowMarker,
|
||||
Block,
|
||||
DefAlias,
|
||||
DefFunc,
|
||||
DefService,
|
||||
DefType,
|
||||
Extract,
|
||||
FuncArrow,
|
||||
FuncCall,
|
||||
FuncOp,
|
||||
LocalArrow,
|
||||
On,
|
||||
Par,
|
||||
TypeAlias,
|
||||
TypeDef,
|
||||
TypeMarker
|
||||
}
|
||||
import aqua.parser.lexer.{Ability, ArrowName, ArrowType, CustomType, DataType, Token, Value, Var}
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class InOutAcc[F[_], In <: Token[F], Out <: Token[F]](
|
||||
in: Acc[F, In],
|
||||
out: Acc[F, Out],
|
||||
scope: Scope[F]
|
||||
) {
|
||||
def par(f: F[Unit])(implicit F: Comonad[F]): InOutAcc[F, In, Out] = copy(scope = scope.par(f))
|
||||
def xor(f: F[Unit])(implicit F: Comonad[F]): InOutAcc[F, In, Out] = copy(scope = scope.xor(f))
|
||||
def on(v: Value[F]): InOutAcc[F, In, Out] = copy(scope = scope.on(v))
|
||||
def unsetMode: InOutAcc[F, In, Out] = copy(scope = scope.unsetMode)
|
||||
|
||||
def unsetPeer: InOutAcc[F, In, Out] = copy(scope = scope.unsetPeer)
|
||||
def unsetScope: InOutAcc[F, In, Out] = unsetMode.unsetPeer
|
||||
|
||||
def combine(other: InOutAcc[F, In, Out])(implicit F: Comonad[F]): InOutAcc[F, In, Out] =
|
||||
scope.mode.map(_.extract) match {
|
||||
case None => combineSeq(other)
|
||||
case Some(XorMode) => combineXor(other)
|
||||
case Some(ParMode) => combinePar(other)
|
||||
}
|
||||
|
||||
def combineSeq(other: InOutAcc[F, In, Out]): InOutAcc[F, In, Out] =
|
||||
copy(in = in.add(other.in, out.keys), out = out add other.out)
|
||||
|
||||
def combinePar(other: InOutAcc[F, In, Out]): InOutAcc[F, In, Out] =
|
||||
copy(in = in add other.in, out = out add other.out)
|
||||
|
||||
def combineXor(other: InOutAcc[F, In, Out]): InOutAcc[F, In, Out] =
|
||||
copy(in = in add other.in)
|
||||
|
||||
def addIn(addition: Acc[F, In]): InOutAcc[F, In, Out] =
|
||||
copy(in = in add addition)
|
||||
|
||||
def subIn(rem: String): InOutAcc[F, In, Out] =
|
||||
copy(in = in sub rem)
|
||||
|
||||
def addOut(addition: Acc[F, Out]): InOutAcc[F, In, Out] =
|
||||
copy(out = out add addition)
|
||||
|
||||
def collectOut(pf: PartialFunction[Out, Out]): InOutAcc[F, In, Out] =
|
||||
copy(out = out.copy(data = out.data.map {
|
||||
case (k, v) => k -> v.toList.collect(pf)
|
||||
}.collect {
|
||||
case (k, h :: tail) => k -> NonEmptyList[Out](h, tail)
|
||||
}))
|
||||
|
||||
def subOut(rem: String): InOutAcc[F, In, Out] =
|
||||
copy(out = out sub rem)
|
||||
|
||||
def eraseOut: InOutAcc[F, In, Out] = copy(out = out.erase)
|
||||
def eraseIn: InOutAcc[F, In, Out] = copy(in = in.erase)
|
||||
|
||||
def validateDuplicates(toMsg: (String, Out) => String, next: InOutAcc[F, In, Out])(implicit
|
||||
F: Functor[F]
|
||||
): List[F[String]] =
|
||||
next.out.takeKeys(out.keys).toErrors(toMsg)
|
||||
|
||||
def validateUnresolved(toMsg: (String, In) => String)(implicit F: Functor[F]): List[F[String]] =
|
||||
in.toErrors(toMsg)
|
||||
}
|
||||
|
||||
object InOutAcc {
|
||||
|
||||
def empty[F[_], In <: Token[F], Out <: Token[F]]: InOutAcc[F, In, Out] =
|
||||
InOutAcc(Acc.empty[F, In], Acc.empty[F, Out], Scope())
|
||||
|
||||
trait Visitor[IOA[_[_]]] {
|
||||
def funcOp[F[_]: Comonad](op: FuncOp[F]): IOA[F]
|
||||
|
||||
def func[F[_]: Comonad](func: DefFunc[F]): IOA[F]
|
||||
|
||||
def block[F[_]: Comonad](block: Block[F]): IOA[F]
|
||||
}
|
||||
|
||||
type Data[F[_]] = InOutAcc[F, Value[F], Var[F]]
|
||||
|
||||
object Data extends Visitor[Data] {
|
||||
|
||||
def funcOp[F[_]: Comonad](op: FuncOp[F]): Data[F] =
|
||||
op match {
|
||||
case FuncCall(_, fargs) =>
|
||||
(empty: Data[F]) addIn Acc.fromValues(fargs)
|
||||
case AbilityFuncCall(_, fc) =>
|
||||
funcOp(fc)
|
||||
case Extract(n, fc) =>
|
||||
funcOp(fc) addOut Acc.one(n.name.extract, n)
|
||||
case AbilityId(_, id) =>
|
||||
(empty: Data[F]) addIn Acc.fromValues(id :: Nil)
|
||||
|
||||
case On(p, ops) =>
|
||||
ops
|
||||
.widen[FuncOp[F]]
|
||||
.map(funcOp[F](_).on(p))
|
||||
.foldLeft(
|
||||
(empty: Data[F]).on(p) addIn Acc.fromValues(p :: Nil)
|
||||
)(_ combine _)
|
||||
case Par(f, op) =>
|
||||
funcOp(op).par(f)
|
||||
case _ =>
|
||||
empty: Data[F]
|
||||
}
|
||||
|
||||
override def func[F[_]: Comonad](func: DefFunc[F]): Data[F] =
|
||||
func.head.args.foldLeft(
|
||||
func.body.map(funcOp[F]).reduceLeft(_ combine _).unsetScope
|
||||
) {
|
||||
case (acc, (k, _, _: DataType[F])) =>
|
||||
acc.subIn(k)
|
||||
case (acc, _) => acc
|
||||
|
||||
}
|
||||
|
||||
override def block[F[_]: Comonad](block: Block[F]): Data[F] =
|
||||
block match {
|
||||
case fn: DefFunc[F] =>
|
||||
func(fn)
|
||||
case _ =>
|
||||
empty: Data[F]
|
||||
}
|
||||
}
|
||||
|
||||
type Abilities[F[_]] = InOutAcc[F, Ability[F], DefService[F]]
|
||||
|
||||
object Abilities extends Visitor[Abilities] {
|
||||
|
||||
def funcOp[F[_]: Comonad](op: FuncOp[F]): Abilities[F] =
|
||||
op match {
|
||||
case ar: AbilityResolve[F] =>
|
||||
(empty: Abilities[F]) addIn Acc.one(ar.ability.name.extract, ar.ability)
|
||||
case Par(p, op) =>
|
||||
funcOp(op).par(p)
|
||||
case On(p, ops) =>
|
||||
ops
|
||||
.widen[FuncOp[F]]
|
||||
.map(funcOp[F](_).on(p))
|
||||
.reduceLeft(_ combine _)
|
||||
case _ =>
|
||||
empty: Abilities[F]
|
||||
}
|
||||
|
||||
// No notion for abilities in funcdef yet
|
||||
override def func[F[_]: Comonad](func: DefFunc[F]): Abilities[F] =
|
||||
func.body.map(funcOp[F]).reduceLeft(_ combine _).unsetScope.eraseOut
|
||||
|
||||
override def block[F[_]: Comonad](block: Block[F]): Abilities[F] =
|
||||
block match {
|
||||
case fn: DefFunc[F] =>
|
||||
func(fn)
|
||||
case defService: DefService[F] =>
|
||||
(empty: Abilities[F])
|
||||
.addOut(Acc.one(defService.name.name.extract, defService))
|
||||
case _ =>
|
||||
empty: Abilities[F]
|
||||
}
|
||||
}
|
||||
|
||||
type Types[F[_]] = InOutAcc[F, CustomType[F], TypeMarker[F]]
|
||||
|
||||
object Types extends Visitor[Types] {
|
||||
|
||||
override def funcOp[F[_]: Comonad](op: FuncOp[F]): Types[F] =
|
||||
op match {
|
||||
case _ => empty: Types[F]
|
||||
}
|
||||
|
||||
override def func[F[_]: Comonad](func: DefFunc[F]): Types[F] =
|
||||
func.head.args.foldLeft(
|
||||
func.body.map(funcOp[F]).reduceLeft[Types[F]](_ combine _).unsetScope
|
||||
) {
|
||||
case (acc, (_, _, ft)) =>
|
||||
acc.addIn(Acc.fromType(ft))
|
||||
}
|
||||
|
||||
override def block[F[_]: Comonad](block: Block[F]): Types[F] =
|
||||
block match {
|
||||
case fn: DefFunc[F] =>
|
||||
func(fn)
|
||||
case deft: DefType[F] =>
|
||||
deft.fields.toNel.map {
|
||||
case (_, (_, tv)) =>
|
||||
Acc.fromType[F](tv)
|
||||
}.foldLeft((empty: Types[F]).addOut(Acc.one(deft.name.name.extract, TypeDef(deft))))(_ addIn _)
|
||||
case defs: DefService[F] =>
|
||||
defs.funcs.toNel.map(_._2).map(Acc.fromType(_)).foldLeft(empty: Types[F])(_ addIn _)
|
||||
case a: DefAlias[F] =>
|
||||
(empty: Types[F])
|
||||
.addOut(Acc.one(a.alias.name.extract, TypeAlias(a.target)))
|
||||
.addIn(Acc.fromType(a.target))
|
||||
}
|
||||
}
|
||||
|
||||
type AbilitiesResolve[F[_]] = InOutAcc[F, Ability[F], AbilityResolve[F]]
|
||||
|
||||
object AbilitiesResolve extends Visitor[AbilitiesResolve] {
|
||||
|
||||
override def funcOp[F[_]: Comonad](op: FuncOp[F]): AbilitiesResolve[F] =
|
||||
op match {
|
||||
case ar: AbilityResolve[F] =>
|
||||
(empty: AbilitiesResolve[F]) addOut Acc.one(ar.ability.name.extract, ar)
|
||||
case AbilityFuncCall(ab, _) =>
|
||||
(empty: AbilitiesResolve[F]) addIn Acc.one(ab.name.extract, ab)
|
||||
case Extract(_, op) =>
|
||||
funcOp[F](op)
|
||||
case Par(p, op) =>
|
||||
funcOp(op).par(p)
|
||||
case On(p, ops) =>
|
||||
ops
|
||||
.widen[FuncOp[F]]
|
||||
.map(funcOp[F](_).on(p))
|
||||
.reduceLeft(_ combine _)
|
||||
.eraseOut
|
||||
case _ =>
|
||||
empty: AbilitiesResolve[F]
|
||||
}
|
||||
|
||||
// Until we have a notion for exporting abilities, they're cleaned
|
||||
override def func[F[_]: Comonad](func: DefFunc[F]): AbilitiesResolve[F] =
|
||||
func.body.map(funcOp[F]).reduceLeft(_ combine _).unsetScope.eraseOut
|
||||
|
||||
override def block[F[_]: Comonad](block: Block[F]): AbilitiesResolve[F] =
|
||||
block match {
|
||||
case fn: DefFunc[F] =>
|
||||
func(fn)
|
||||
case _ => empty: AbilitiesResolve[F]
|
||||
}
|
||||
}
|
||||
|
||||
type Arrows[F[_]] = InOutAcc[F, ArrowName[F], ArrowMarker[F]]
|
||||
|
||||
object Arrows extends Visitor[Arrows] {
|
||||
|
||||
override def funcOp[F[_]: Comonad](op: FuncOp[F]): Arrows[F] =
|
||||
op match {
|
||||
case FuncCall(fname, _) =>
|
||||
(empty: Arrows[F]) addIn Acc.one(fname.extract, ArrowName(fname))
|
||||
case Par(p, op) =>
|
||||
funcOp(op).par(p)
|
||||
case On(p, ops) =>
|
||||
ops
|
||||
.widen[FuncOp[F]]
|
||||
.map(funcOp[F](_).on(p))
|
||||
.reduceLeft(_ combine _)
|
||||
case _ =>
|
||||
empty: Arrows[F]
|
||||
}
|
||||
|
||||
override def func[F[_]: Comonad](func: DefFunc[F]): Arrows[F] =
|
||||
func.head.args.foldLeft(
|
||||
func.body.map(funcOp[F]).reduceLeft[Arrows[F]](_ combine _).unsetScope
|
||||
) {
|
||||
case (acc, (k, _, ft: ArrowType[F])) =>
|
||||
acc.subIn(k).addOut(Acc.one(k, LocalArrow(ft)))
|
||||
|
||||
case (acc, _) => acc
|
||||
}
|
||||
|
||||
override def block[F[_]: Comonad](block: Block[F]): Arrows[F] =
|
||||
block match {
|
||||
case fn: DefFunc[F] =>
|
||||
func(fn).eraseOut
|
||||
.addOut(Acc.one(fn.head.name.name.extract, FuncArrow(fn)))
|
||||
|
||||
case _ =>
|
||||
empty: Arrows[F]
|
||||
}
|
||||
}
|
||||
}
|
5
src/main/scala/aqua/model/Mode.scala
Normal file
5
src/main/scala/aqua/model/Mode.scala
Normal file
@ -0,0 +1,5 @@
|
||||
package aqua.model
|
||||
|
||||
sealed trait Mode
|
||||
case object ParMode extends Mode
|
||||
case object XorMode extends Mode
|
75
src/main/scala/aqua/model/Names.scala
Normal file
75
src/main/scala/aqua/model/Names.scala
Normal file
@ -0,0 +1,75 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser._
|
||||
import aqua.parser.lexer._
|
||||
import cats.Comonad
|
||||
import cats.data.Validated.Valid
|
||||
import cats.data.{NonEmptyList, Validated, ValidatedNel}
|
||||
|
||||
// Fully resolved Scope must have no expected abilities (all resolved)
|
||||
case class Names[F[_]](
|
||||
// Take vars, set vars
|
||||
// Data type is not yet known
|
||||
data: InOutAcc.Data[F] = InOutAcc.empty[F, Value[F], Var[F]],
|
||||
// Abilities can be imported or set
|
||||
abilitiesResolve: InOutAcc.AbilitiesResolve[F] = InOutAcc.empty[F, Ability[F], AbilityResolve[F]],
|
||||
// Abilities can be defined and expected
|
||||
abilities: InOutAcc.Abilities[F] = InOutAcc.empty[F, Ability[F], DefService[F]],
|
||||
// Types can be defined and expected
|
||||
types: InOutAcc.Types[F] = InOutAcc.empty[F, CustomType[F], TypeMarker[F]],
|
||||
// We don't know the types yet
|
||||
arrows: InOutAcc.Arrows[F] = InOutAcc.empty[F, ArrowName[F], ArrowMarker[F]]
|
||||
)
|
||||
|
||||
object Names {
|
||||
|
||||
def combine[F[_]: Comonad](a: Names[F], b: Names[F]): Names[F] =
|
||||
Names[F](
|
||||
data = a.data combine b.data,
|
||||
abilitiesResolve = a.abilitiesResolve combine b.abilitiesResolve,
|
||||
abilities = a.abilities combine b.abilities,
|
||||
types = a.types combine b.types,
|
||||
arrows = a.arrows combine b.arrows
|
||||
)
|
||||
|
||||
def blockNames[F[_]: Comonad](block: Block[F]): Names[F] =
|
||||
Names[F](
|
||||
data = InOutAcc.Data.block(block),
|
||||
abilitiesResolve = InOutAcc.AbilitiesResolve.block(block),
|
||||
abilities = InOutAcc.Abilities.block(block),
|
||||
types = InOutAcc.Types.block(block),
|
||||
arrows = InOutAcc.Arrows.block(block)
|
||||
)
|
||||
|
||||
def foldVerify[F[_]: Comonad](input: List[Names[F]]): ValidatedNel[F[String], Names[F]] =
|
||||
input.foldLeft[ValidatedNel[F[String], Names[F]]](Valid(Names[F]())) {
|
||||
case (accE, ns) =>
|
||||
accE
|
||||
.andThen(acc =>
|
||||
Validated.fromEither[NonEmptyList[F[String]], Names[F]](
|
||||
NonEmptyList
|
||||
.fromList(
|
||||
acc.abilities.validateDuplicates((v, _) => s"Duplicate ability definition `$v`", ns.abilities) :::
|
||||
acc.types.validateDuplicates((v, _) => s"Duplicate type definition `$v`", ns.types) :::
|
||||
acc.arrows.validateDuplicates((v, _) => s"Duplicate func definition `$v`", ns.arrows)
|
||||
)
|
||||
.toLeft(acc)
|
||||
)
|
||||
)
|
||||
.map(combine(_, ns))
|
||||
.andThen { acc =>
|
||||
Validated.fromEither[NonEmptyList[F[String]], Names[F]](
|
||||
NonEmptyList
|
||||
.fromList(
|
||||
acc.data.validateUnresolved((v, _) => s"Unknown variable `${v}`") :::
|
||||
acc.arrows.validateUnresolved((a, _) => s"Unknown arrow `${a}`") :::
|
||||
acc.abilitiesResolve.validateUnresolved((a, _) => s"Unresolved ability `${a}`") :::
|
||||
acc.abilities.validateUnresolved((a, _) => s"Undefined ability `${a}`") :::
|
||||
acc.types.validateUnresolved((t, _) => s"Undefined type `$t`")
|
||||
)
|
||||
.toLeft(acc)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +1,17 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser.DataType
|
||||
import aqua.parser.lexer.Value
|
||||
import cats.Functor
|
||||
import cats.syntax.functor._
|
||||
|
||||
trait Instr
|
||||
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)))
|
||||
|
||||
// Fully resolved Scope must have no expected abilities (all resolved)
|
||||
case class Scope(
|
||||
// None means "inherit"
|
||||
peerId: Option[Value],
|
||||
// Take vars, set vars
|
||||
importData: Map[String, DataType],
|
||||
exportData: Map[String, DataType],
|
||||
// Abilities can be imported or set
|
||||
expectedAbilities: Set[String],
|
||||
resolvedAbilities: Set[String],
|
||||
// We don't know the types yet
|
||||
expectArrows: Set[String],
|
||||
// resolved subtrees, or unresolved shit
|
||||
body: List[Either[Scope, Instr]]
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
14
src/main/scala/aqua/parser/ArrowMarker.scala
Normal file
14
src/main/scala/aqua/parser/ArrowMarker.scala
Normal file
@ -0,0 +1,14 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.{ArrowType, Token}
|
||||
import cats.Functor
|
||||
|
||||
sealed trait ArrowMarker[F[_]] extends Token[F]
|
||||
|
||||
case class LocalArrow[F[_]](arr: ArrowType[F]) extends ArrowMarker[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = arr.as(v)
|
||||
}
|
||||
|
||||
case class FuncArrow[F[_]](funcDef: DefFunc[F]) extends ArrowMarker[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = funcDef.as(v)
|
||||
}
|
@ -1,33 +1,45 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.DataType.{`customtypedef`, `datatypedef`}
|
||||
import aqua.parser.lexer.DataType.`datatypedef`
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.Type.{`arrowdef`, `typedef`}
|
||||
import aqua.parser.lexer.Type.{`arrowdef`, `typedef`}
|
||||
import aqua.parser.lexer.{Ability, AquaArrowType, ArrowName, ArrowType, CustomType, DataType, Token, Type}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Comonad
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.data.{NonEmptyList, NonEmptyMap}
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
sealed trait Block[F[_]]
|
||||
case class DefType[F[_]](name: F[String], fields: NonEmptyMap[String, (F[String], F[DataType])]) extends Block[F]
|
||||
case class DefService[F[_]](name: F[String], funcs: NonEmptyMap[String, ArrowType]) extends Block[F]
|
||||
sealed trait Block[F[_]] extends Token[F]
|
||||
|
||||
case class FuncHead[F[_]](name: F[String], args: List[(String, F[String], F[Type])], ret: Option[F[DataType]]) {
|
||||
|
||||
def toArrowDef(implicit F: Comonad[F]): F[AquaArrowType] =
|
||||
name.as(AquaArrowType(args.map(_._3.extract), ret.map(_.extract)))
|
||||
case class DefType[F[_]](name: CustomType[F], fields: NonEmptyMap[String, (F[String], DataType[F])]) extends Block[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
case class DefFunc[F[_]](head: FuncHead[F], body: NonEmptyList[F[FuncOp[F]]]) extends Block[F]
|
||||
case class DefAlias[F[_]](alias: F[CustomType], target: F[Type]) extends Block[F]
|
||||
case class DefService[F[_]](name: Ability[F], funcs: NonEmptyMap[String, ArrowType[F]]) extends Block[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
case class FuncHead[F[_]](name: ArrowName[F], args: List[(String, F[String], Type[F])], ret: Option[DataType[F]]) {
|
||||
|
||||
def toArrowDef(implicit F: Comonad[F]): F[AquaArrowType[F]] =
|
||||
name.as(AquaArrowType(args.map(_._3), ret))
|
||||
}
|
||||
|
||||
case class DefFunc[F[_]](head: FuncHead[F], body: NonEmptyList[FuncOp[F]]) extends Block[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = head.name.as(v)
|
||||
}
|
||||
|
||||
case class DefAlias[F[_]](alias: CustomType[F], target: Type[F]) extends Block[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = alias.as(v)
|
||||
}
|
||||
|
||||
object DefType {
|
||||
def `dname`[F[_]: LiftParser]: P[F[String]] = `data` *> ` ` *> Name.lift <* ` `.? <* `:` <* ` \n*`
|
||||
def `dname`[F[_]: LiftParser]: P[CustomType[F]] = `data` *> ` ` *> CustomType.ct[F] <* ` `.? <* `:` <* ` \n*`
|
||||
|
||||
def `dataname`[F[_]: LiftParser]: P[(F[String], F[DataType])] = (`name`.lift <* ` : `) ~ `datatypedef`.lift
|
||||
def `dataname`[F[_]: LiftParser]: P[(F[String], DataType[F])] =
|
||||
(`name`.lift <* ` : `) ~ `datatypedef`
|
||||
|
||||
def `deftype`[F[_]: LiftParser: Comonad]: P[DefType[F]] =
|
||||
(`dname` ~ indented(`dataname`)).map {
|
||||
@ -37,16 +49,16 @@ object DefType {
|
||||
|
||||
object DefFunc {
|
||||
|
||||
val `funcdef`: P[(String, ArrowType)] =
|
||||
def `funcdef`[F[_]: LiftParser]: P[(String, ArrowType[F])] =
|
||||
(`name` <* ` : `) ~ `arrowdef`
|
||||
|
||||
def `funcname`[F[_]: LiftParser]: P[F[String]] = ` `.?.with1 *> `func` *> ` ` *> name.lift <* ` `.?
|
||||
def `funcname`[F[_]: LiftParser]: P[ArrowName[F]] = ` `.?.with1 *> `func` *> ` ` *> ArrowName.an <* ` `.?
|
||||
|
||||
def `funcargs`[F[_]: LiftParser: Comonad]: P[List[(String, F[String], F[Type])]] =
|
||||
`(` *> comma0((`name`.lift <* ` : `) ~ `typedef`.lift).map(_.map(kv => (kv._1.extract, kv._1, kv._2))) <* `)`
|
||||
def `funcargs`[F[_]: LiftParser: Comonad]: P[List[(String, F[String], Type[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`.lift).?)).map {
|
||||
(`funcname` ~ (`funcargs` ~ (`->` *> `datatypedef`).?)).map {
|
||||
case (n, (a, r)) ⇒ FuncHead(n, a, r)
|
||||
}
|
||||
|
||||
@ -61,7 +73,7 @@ object DefFunc {
|
||||
object DefService {
|
||||
import DefFunc.`funcdef`
|
||||
|
||||
def `servicename`[F[_]: LiftParser]: P[F[String]] = `service` *> ` ` *> Name.lift <* ` `.? <* `:` <* ` \n*`
|
||||
def `servicename`[F[_]: LiftParser]: P[Ability[F]] = `service` *> ` ` *> Ability.ab[F] <* ` `.? <* `:` <* ` \n*`
|
||||
|
||||
// TODO switch to funchead?
|
||||
def `defservice`[F[_]: LiftParser]: P[DefService[F]] =
|
||||
@ -73,7 +85,7 @@ object DefService {
|
||||
object DefAlias {
|
||||
|
||||
def `defalias`[F[_]: LiftParser]: P[DefAlias[F]] =
|
||||
((`alias` *> ` ` *> `customtypedef`.lift <* ` : `) ~ `typedef`.lift).map {
|
||||
((`alias` *> ` ` *> CustomType.ct[F] <* ` : `) ~ `typedef`).map {
|
||||
case (ct, t) => DefAlias(ct, t)
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +1,99 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.Value
|
||||
import aqua.parser.lexer.{Ability, Token, Value, Var}
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Parser ⇒ P}
|
||||
import cats.parse.{Parser => P}
|
||||
import aqua.parser.lexer.Value.`value`
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.syntax.functor._
|
||||
|
||||
sealed trait FuncOp[F[_]]
|
||||
sealed trait FuncOp[F[_]] extends Token[F]
|
||||
sealed trait InstrOp[F[_]] extends FuncOp[F]
|
||||
|
||||
sealed trait ExecOp[F[_]] extends InstrOp[F]
|
||||
sealed trait CallOp[F[_]] extends ExecOp[F]
|
||||
|
||||
case class FuncCall[F[_]](name: F[String], args: List[F[Value]]) extends CallOp[F]
|
||||
case class AbilityFuncCall[F[_]](ability: F[String], call: F[FuncCall[F]]) extends CallOp[F]
|
||||
case class Extract[F[_]](v: F[String], from: F[CallOp[F]]) extends ExecOp[F]
|
||||
case class FuncCall[F[_]](name: F[String], args: List[Value[F]]) extends CallOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
case class On[F[_]](peer: F[Value], ops: NonEmptyList[F[ExecOp[F]]]) extends InstrOp[F]
|
||||
case class AbilityFuncCall[F[_]](ability: Ability[F], call: FuncCall[F]) extends CallOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = ability.as(v)
|
||||
}
|
||||
|
||||
case class Par[F[_]](op: F[InstrOp[F]]) extends FuncOp[F]
|
||||
case class Extract[F[_]](vr: Var[F], from: CallOp[F]) extends ExecOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = vr.as(v)
|
||||
}
|
||||
|
||||
case class On[F[_]](peer: Value[F], ops: NonEmptyList[ExecOp[F]]) extends InstrOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = peer.as(v)
|
||||
}
|
||||
|
||||
case class Par[F[_]](f: F[Unit], op: InstrOp[F]) extends FuncOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = f.as(v)
|
||||
}
|
||||
|
||||
// TODO: can't be in Par, can be in On
|
||||
sealed trait AbilityResolve[F[_]] extends ExecOp[F]
|
||||
case class AbilityId[F[_]](ability: F[String], id: F[Value]) extends AbilityResolve[F]
|
||||
sealed trait AbilityResolve[F[_]] extends ExecOp[F] {
|
||||
def ability: Ability[F]
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = ability.as(v)
|
||||
}
|
||||
case class AbilityId[F[_]](ability: Ability[F], id: Value[F]) extends AbilityResolve[F]
|
||||
|
||||
object FuncOp {
|
||||
|
||||
def funcCall[F[_]: LiftParser]: P[F[FuncCall[F]]] =
|
||||
(`name`.lift ~ P.repSep0(`value`.lift, `,`).between(`(`, `)`)).map {
|
||||
def funcCall[F[_]: LiftParser: Comonad]: P[FuncCall[F]] =
|
||||
(`name`.lift ~ P.repSep0(`value`, `,`).between(`(`, `)`)).map {
|
||||
case (fnName, args) ⇒ FuncCall(fnName, args)
|
||||
}.lift
|
||||
}
|
||||
|
||||
def abilityFuncCall[F[_]: LiftParser]: P[F[AbilityFuncCall[F]]] =
|
||||
((`Name`.lift <* `.`) ~ funcCall).map {
|
||||
def abilityFuncCall[F[_]: LiftParser: Comonad]: P[AbilityFuncCall[F]] =
|
||||
((Ability.ab[F] <* `.`) ~ funcCall).map {
|
||||
case (abName, fc) ⇒ AbilityFuncCall(abName, fc)
|
||||
}.lift
|
||||
}
|
||||
|
||||
def callOp[F[_]: LiftParser: Functor]: P[F[CallOp[F]]] =
|
||||
P.oneOf(funcCall[F].map(_.widen[CallOp[F]]) :: abilityFuncCall[F].map(_.widen[CallOp[F]]) :: Nil)
|
||||
def callOp[F[_]: LiftParser: Comonad]: P[CallOp[F]] =
|
||||
P.oneOf(funcCall[F] :: abilityFuncCall[F] :: Nil)
|
||||
|
||||
def extract[F[_]: LiftParser: Functor]: P[F[Extract[F]]] =
|
||||
((`name`.lift <* `<-`) ~ callOp[F]).map {
|
||||
def extract[F[_]: LiftParser: Comonad]: P[Extract[F]] =
|
||||
((Var.v <* `<-`) ~ callOp[F]).map {
|
||||
case (v, f) ⇒ Extract(v, f)
|
||||
}.lift
|
||||
}
|
||||
|
||||
def abilityResolve[F[_]: LiftParser: Functor]: P[F[AbilityResolve[F]]] =
|
||||
((`Name`.lift <* ` `) ~ `value`.lift).map {
|
||||
def abilityResolve[F[_]: LiftParser: Comonad]: P[AbilityResolve[F]] =
|
||||
((Ability.ab <* ` `) ~ `value`).map {
|
||||
case (n, v) ⇒ AbilityId(n, v)
|
||||
}.widen[AbilityResolve[F]].lift
|
||||
}.widen[AbilityResolve[F]]
|
||||
|
||||
// TODO can't be in Par, can be in On
|
||||
def execOp[F[_]: LiftParser: Functor]: P[F[ExecOp[F]]] =
|
||||
def execOp[F[_]: LiftParser: Comonad]: P[ExecOp[F]] =
|
||||
P.oneOf(
|
||||
callOp.map(_.widen[ExecOp[F]]).backtrack
|
||||
:: abilityResolve.map(_.widen[ExecOp[F]]).backtrack
|
||||
:: extract.map(_.widen[ExecOp[F]]) :: Nil
|
||||
callOp.backtrack
|
||||
:: abilityResolve.backtrack
|
||||
:: extract :: Nil
|
||||
)
|
||||
|
||||
def startOn[F[_]: LiftParser]: P[F[Value]] = `on` *> ` ` *> `value`.lift <* ` `.? <* `:` <* ` \n*`
|
||||
def startOn[F[_]: LiftParser: Comonad]: P[Value[F]] = `on` *> ` ` *> `value` <* ` `.? <* `:` <* ` \n*`
|
||||
|
||||
def execOn[F[_]: LiftParser: Functor]: P[F[On[F]]] =
|
||||
def execOn[F[_]: LiftParser: Comonad]: P[On[F]] =
|
||||
(startOn ~ indented(execOp[F])).map {
|
||||
case (v, i) ⇒ On(v, i)
|
||||
}.lift
|
||||
}
|
||||
|
||||
def instrOp[F[_]: LiftParser: Functor]: P[F[InstrOp[F]]] =
|
||||
def instrOp[F[_]: LiftParser: Comonad]: P[InstrOp[F]] =
|
||||
P.oneOf(
|
||||
execOn.map(_.widen[InstrOp[F]]).backtrack
|
||||
:: execOp.map(_.widen[InstrOp[F]]) :: Nil
|
||||
execOn.backtrack
|
||||
:: execOp :: Nil
|
||||
)
|
||||
|
||||
def parOp[F[_]: LiftParser: Functor]: P[F[Par[F]]] =
|
||||
(`par` *> ` ` *> instrOp[F].map(Par(_))).lift
|
||||
def parOp[F[_]: LiftParser: Comonad]: P[Par[F]] =
|
||||
((`par`.lift <* ` `) ~ instrOp[F]).map(pi => Par(pi._1, pi._2))
|
||||
|
||||
def `funcop`[F[_]: LiftParser: Functor]: P[F[FuncOp[F]]] =
|
||||
P.oneOf(parOp.map(_.widen[FuncOp[F]]).backtrack :: instrOp.map(_.widen[FuncOp[F]]) :: Nil)
|
||||
def `funcop`[F[_]: LiftParser: Comonad]: P[FuncOp[F]] =
|
||||
P.oneOf(parOp.backtrack :: instrOp :: Nil)
|
||||
|
||||
def body[F[_]: LiftParser: Functor]: P[NonEmptyList[F[FuncOp[F]]]] = indented(`funcop`)
|
||||
def body[F[_]: LiftParser: Comonad]: P[NonEmptyList[FuncOp[F]]] = indented(`funcop`)
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.parse.{Parser ⇒ P}
|
||||
|
||||
sealed trait Type
|
||||
sealed trait DataType extends Type
|
||||
case class ArrayType(data: DataType) extends DataType
|
||||
case class CustomType(name: String) extends DataType
|
||||
case class BasicType(name: String) extends DataType
|
||||
|
||||
object BasicType {
|
||||
private val floatS = "f32" :: "f64" :: Nil
|
||||
private val signedS = "s32" :: "s64" :: floatS
|
||||
private val numberS = "i32" :: "i64" :: signedS
|
||||
private val boolS = "bool" :: Nil
|
||||
private val stringS = "string" :: Nil
|
||||
private val allS = numberS ++ boolS ++ stringS
|
||||
|
||||
val float = floatS.map(BasicType(_))
|
||||
val signed = signedS.map(BasicType(_))
|
||||
val number = numberS.map(BasicType(_))
|
||||
val bool = boolS.map(BasicType(_))
|
||||
val string = stringS.map(BasicType(_))
|
||||
|
||||
val `basictypedef`: P[BasicType] =
|
||||
P.oneOf(
|
||||
("()" :: BasicType.allS).map(n ⇒ P.string(n).as(BasicType(n)))
|
||||
)
|
||||
}
|
||||
sealed trait ArrowDef
|
||||
case class ArrowType(args: List[DataType], res: DataType) extends Type with ArrowDef
|
||||
|
||||
case class AquaArrowType(args: List[Type], res: Option[DataType]) extends ArrowDef
|
||||
|
||||
object DataType {
|
||||
val `customtypedef`: P[CustomType] = `Name`.map(CustomType)
|
||||
|
||||
lazy val `arraytypedef`: P[ArrayType] = (P.string("[]") *> `datatypedef`).map(ArrayType)
|
||||
|
||||
val `datatypedef`: P[DataType] =
|
||||
P.oneOf(P.defer(`arraytypedef`) :: BasicType.`basictypedef` :: `customtypedef` :: Nil)
|
||||
}
|
||||
|
||||
object Type {
|
||||
|
||||
val `arrowdef`: P[ArrowType] =
|
||||
(comma0(DataType.`datatypedef`).with1 ~ (`->` *> DataType.`datatypedef`)).map {
|
||||
case (args, res) ⇒ ArrowType(args, res)
|
||||
}
|
||||
|
||||
val `typedef`: P[Type] = P.oneOf(`arrowdef`.backtrack :: DataType.`datatypedef` :: Nil)
|
||||
|
||||
}
|
14
src/main/scala/aqua/parser/TypeMarker.scala
Normal file
14
src/main/scala/aqua/parser/TypeMarker.scala
Normal file
@ -0,0 +1,14 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.{Token, Type}
|
||||
import cats.Functor
|
||||
|
||||
sealed trait TypeMarker[F[_]] extends Token[F]
|
||||
|
||||
case class TypeAlias[F[_]](forType: Type[F]) extends TypeMarker[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = forType.as(v)
|
||||
}
|
||||
|
||||
case class TypeDef[F[_]](forDef: DefType[F]) extends TypeMarker[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = forDef.as(v)
|
||||
}
|
18
src/main/scala/aqua/parser/lexer/Ability.scala
Normal file
18
src/main/scala/aqua/parser/lexer/Ability.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class Ability[F[_]](name: F[String]) extends Token[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
object Ability {
|
||||
|
||||
def ab[F[_]: LiftParser]: P[Ability[F]] =
|
||||
`Name`.lift.map(Ability(_))
|
||||
}
|
18
src/main/scala/aqua/parser/lexer/ArrowName.scala
Normal file
18
src/main/scala/aqua/parser/lexer/ArrowName.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token.`name`
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.syntax.functor._
|
||||
import cats.parse.{Parser => P}
|
||||
|
||||
case class ArrowName[F[_]](name: F[String]) extends Token[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
object ArrowName {
|
||||
|
||||
def an[F[_]: LiftParser]: P[ArrowName[F]] =
|
||||
`name`.lift.map(ArrowName(_))
|
||||
}
|
30
src/main/scala/aqua/parser/lexer/LambdaOp.scala
Normal file
30
src/main/scala/aqua/parser/lexer/LambdaOp.scala
Normal file
@ -0,0 +1,30 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.functor._
|
||||
|
||||
sealed trait LambdaOp[F[_]] extends Token[F]
|
||||
|
||||
case class IntoField[F[_]](name: F[String]) extends LambdaOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
|
||||
}
|
||||
|
||||
case class IntoArray[F[_]](f: F[Unit]) extends LambdaOp[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = f.as(v)
|
||||
}
|
||||
|
||||
object LambdaOp {
|
||||
private def parseField[F[_]: LiftParser]: P[LambdaOp[F]] = (`.` *> `name`).lift.map(IntoField(_))
|
||||
private def parseArr[F[_]: LiftParser]: P[LambdaOp[F]] = `*`.lift.map(IntoArray(_))
|
||||
private def parseOp[F[_]: LiftParser]: P[LambdaOp[F]] = P.oneOf(parseField.backtrack :: parseArr :: Nil)
|
||||
|
||||
def ops[F[_]: LiftParser]: P[NonEmptyList[LambdaOp[F]]] =
|
||||
parseOp.rep
|
||||
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import cats.Functor
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Accumulator0, Parser ⇒ P, Parser0 ⇒ P0}
|
||||
import cats.parse.{Accumulator0, Parser => P, Parser0 => P0}
|
||||
|
||||
trait Token[F[_]] {
|
||||
def as[T](v: T)(implicit F: Functor[F]): F[T]
|
||||
|
||||
def unit(implicit F: Functor[F]): F[Unit] = as(())
|
||||
}
|
||||
|
||||
object Token {
|
||||
private val fSpaces = Set(' ', '\t')
|
||||
@ -31,6 +38,7 @@ object Token {
|
||||
val `,` : P[Unit] = P.char(',') <* ` `.?
|
||||
val `.` : P[Unit] = P.char('.')
|
||||
val `"` : P[Unit] = P.char('"')
|
||||
val `*` : P[Unit] = P.char('*')
|
||||
val `(` : P[Unit] = ` `.?.with1 *> P.char('(') <* ` `.?
|
||||
val `)` : P[Unit] = ` `.?.with1 *> P.char(')') <* ` `.?
|
||||
val `->` : P[Unit] = ` `.?.with1 *> P.string("->") <* ` `.?
|
||||
|
75
src/main/scala/aqua/parser/lexer/Type.scala
Normal file
75
src/main/scala/aqua/parser/lexer/Type.scala
Normal file
@ -0,0 +1,75 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.functor._
|
||||
|
||||
sealed trait Type[F[_]] extends Token[F]
|
||||
sealed trait DataType[F[_]] extends Type[F]
|
||||
|
||||
case class ArrayType[F[_]](data: DataType[F]) extends DataType[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = data.as(v)
|
||||
}
|
||||
|
||||
case class CustomType[F[_]](name: F[String]) extends DataType[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
object CustomType {
|
||||
def ct[F[_]: LiftParser]: P[CustomType[F]] = `Name`.lift.map(CustomType(_))
|
||||
}
|
||||
|
||||
case class BasicType[F[_]](name: F[BasicType.Value]) extends DataType[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
object BasicType {
|
||||
case class Value(v: String) extends AnyVal
|
||||
private val floatS = "f32" :: "f64" :: Nil
|
||||
private val signedS = "s32" :: "s64" :: floatS
|
||||
private val numberS = "i32" :: "i64" :: signedS
|
||||
private val boolS = "bool" :: Nil
|
||||
private val stringS = "string" :: Nil
|
||||
private val allS = numberS ++ boolS ++ stringS
|
||||
|
||||
val float = floatS.map(Value)
|
||||
val signed = signedS.map(Value)
|
||||
val number = numberS.map(Value)
|
||||
val bool = boolS.map(Value)
|
||||
val string = stringS.map(Value)
|
||||
|
||||
def `basictypedef`[F[_]: LiftParser]: P[BasicType[F]] =
|
||||
P.oneOf(
|
||||
("()" :: BasicType.allS).map(n ⇒ P.string(n).as(Value(n)))
|
||||
)
|
||||
.lift
|
||||
.map(BasicType(_))
|
||||
}
|
||||
sealed trait ArrowDef
|
||||
|
||||
case class ArrowType[F[_]](args: List[DataType[F]], res: DataType[F]) extends Type[F] with ArrowDef {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = (args.headOption getOrElse res).as(v)
|
||||
}
|
||||
|
||||
case class AquaArrowType[F[_]](args: List[Type[F]], res: Option[DataType[F]]) extends ArrowDef
|
||||
|
||||
object DataType {
|
||||
def `arraytypedef`[F[_]: LiftParser]: P[ArrayType[F]] = (P.string("[]") *> `datatypedef`[F]).map(ArrayType(_))
|
||||
|
||||
def `datatypedef`[F[_]: LiftParser]: P[DataType[F]] =
|
||||
P.oneOf(P.defer(`arraytypedef`[F]) :: BasicType.`basictypedef`[F] :: CustomType.ct[F] :: Nil)
|
||||
}
|
||||
|
||||
object Type {
|
||||
|
||||
def `arrowdef`[F[_]: LiftParser]: P[ArrowType[F]] =
|
||||
(comma0(DataType.`datatypedef`).with1 ~ (`->` *> DataType.`datatypedef`)).map {
|
||||
case (args, res) ⇒ ArrowType(args, res)
|
||||
}
|
||||
|
||||
def `typedef`[F[_]: LiftParser]: P[Type[F]] = P.oneOf(`arrowdef`.backtrack :: DataType.`datatypedef` :: Nil)
|
||||
|
||||
}
|
@ -1,38 +1,56 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.BasicType
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.parse.{Numbers, Parser ⇒ P}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.{Comonad, Functor}
|
||||
import cats.parse.{Numbers, Parser => P}
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.comonad._
|
||||
|
||||
sealed trait Value
|
||||
case class VarLambda(name: String, lambda: Option[String] = None) extends Value
|
||||
case class Literal(value: String, ts: List[BasicType]) extends Value
|
||||
sealed trait Value[F[_]] extends Token[F]
|
||||
|
||||
case class VarLambda[F[_]](name: F[String], lambda: List[LambdaOp[F]] = Nil) extends Value[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
case class Literal[F[_]](value: F[String], ts: List[BasicType.Value]) extends Value[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = value.as(v)
|
||||
}
|
||||
|
||||
object Value {
|
||||
val notLambdaSymbols = Set(' ', ',', '\n', ')', ':')
|
||||
|
||||
val varLambda: P[VarLambda] = (`name` ~ (`.` *> P.charsWhile(c ⇒ !notLambdaSymbols(c))).?).map {
|
||||
case (n, l) ⇒ VarLambda(n, l)
|
||||
}
|
||||
def varLambda[F[_]: LiftParser]: P[VarLambda[F]] =
|
||||
(`name`.lift ~ LambdaOp.ops[F].?).map {
|
||||
case (n, l) ⇒ VarLambda(n, l.fold[List[LambdaOp[F]]](Nil)(_.toList))
|
||||
}
|
||||
|
||||
val bool: P[Literal] = P.oneOf(("true" :: "false" :: Nil).map(t ⇒ P.string(t).as(Literal(t, BasicType.bool))))
|
||||
def bool[F[_]: LiftParser: Functor]: P[Literal[F]] =
|
||||
P.oneOf(
|
||||
("true" :: "false" :: Nil)
|
||||
.map(t ⇒ P.string(t).lift.map(fu => Literal(fu.as(t), BasicType.bool)))
|
||||
)
|
||||
|
||||
val num: P[Literal] = (P.char('-').?.with1 ~ Numbers.nonNegativeIntString).map {
|
||||
case (Some(_), n) ⇒ Literal(s"-$n", BasicType.signed)
|
||||
case (None, n) ⇒ Literal(n, BasicType.number)
|
||||
}
|
||||
def num[F[_]: LiftParser: Comonad]: P[Literal[F]] =
|
||||
(P.char('-').?.with1 ~ Numbers.nonNegativeIntString).lift.map(fu =>
|
||||
fu.extract match {
|
||||
case (Some(_), n) ⇒ Literal(fu.as(s"-$n"), BasicType.signed)
|
||||
case (None, n) ⇒ Literal(fu.as(n), BasicType.number)
|
||||
}
|
||||
)
|
||||
|
||||
val float: P[Literal] =
|
||||
(P.char('-').?.with1 ~ (Numbers.nonNegativeIntString <* P.char('.')) ~ Numbers.nonNegativeIntString).string
|
||||
def float[F[_]: LiftParser]: P[Literal[F]] =
|
||||
(P.char('-').?.with1 ~ (Numbers.nonNegativeIntString <* P.char('.')) ~ Numbers.nonNegativeIntString).string.lift
|
||||
.map(Literal(_, BasicType.float))
|
||||
|
||||
// TODO make more sophisticated escaping/unescaping
|
||||
val string: P[Literal] =
|
||||
(`"` *> P.charsWhile0(_ != '"') <* `"`).string
|
||||
def string[F[_]: LiftParser]: P[Literal[F]] =
|
||||
(`"` *> P.charsWhile0(_ != '"') <* `"`).string.lift
|
||||
.map(Literal(_, BasicType.string))
|
||||
|
||||
val literal: P[Literal] = P.oneOf(bool :: float.backtrack :: num :: string :: Nil)
|
||||
def literal[F[_]: LiftParser: Comonad]: P[Literal[F]] = P.oneOf(bool :: float.backtrack :: num :: string :: Nil)
|
||||
|
||||
val `value`: P[Value] = P.oneOf(literal.backtrack :: varLambda :: Nil)
|
||||
def `value`[F[_]: LiftParser: Comonad]: P[Value[F]] = P.oneOf(literal.backtrack :: varLambda :: Nil)
|
||||
|
||||
}
|
||||
|
18
src/main/scala/aqua/parser/lexer/Var.scala
Normal file
18
src/main/scala/aqua/parser/lexer/Var.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.lift.LiftParser._
|
||||
import cats.Functor
|
||||
import cats.parse.{Parser => P}
|
||||
import cats.syntax.functor._
|
||||
|
||||
case class Var[F[_]](name: F[String]) extends Token[F] {
|
||||
override def as[T](v: T)(implicit F: Functor[F]): F[T] = name.as(v)
|
||||
}
|
||||
|
||||
object Var {
|
||||
|
||||
def v[F[_]: LiftParser]: P[Var[F]] =
|
||||
`name`.lift.map(Var(_))
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package aqua
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser.{BasicType, DefFunc, FuncOp}
|
||||
import aqua.parser.lexer.{Literal, Value, VarLambda}
|
||||
import aqua.parser.lexer.{Value, VarLambda}
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.parser.{DefFunc, FuncOp}
|
||||
import cats.Id
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
@ -1,6 +1,6 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.{Literal, VarLambda}
|
||||
import aqua.parser.lexer.{BasicType, Literal, VarLambda}
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
|
@ -1,6 +1,6 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lexer.{Literal, VarLambda}
|
||||
import aqua.parser.lexer.{ArrowType, BasicType, CustomType, Literal, VarLambda}
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
|
20
src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala
Normal file
20
src/test/scala/aqua/parser/lexer/LambdaOpSpec.scala
Normal file
@ -0,0 +1,20 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import cats.Id
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
class LambdaOpSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|
||||
"lambda ops" should "parse" in {
|
||||
val opsP = (s: String) => LambdaOp.ops[Id].parseAll(s).right.value
|
||||
|
||||
opsP(".field") should be(NonEmptyList.of(IntoField("field")))
|
||||
opsP(".field.sub") should be(NonEmptyList.of(IntoField("field"), IntoField("sub")))
|
||||
opsP(".field*.sub") should be(NonEmptyList.of(IntoField("field"), IntoArray, IntoField("sub")))
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package aqua.parser
|
||||
package aqua.parser.lexer
|
||||
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
@ -1,6 +1,5 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.BasicType
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
|
Loading…
Reference in New Issue
Block a user