mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +00:00
Basic Names impl
This commit is contained in:
parent
d2676c8b14
commit
9cf2db90d8
@ -15,5 +15,5 @@ case class Aqua(
|
||||
object Aqua {
|
||||
import aqua.parser.lexer.Token._
|
||||
|
||||
val `parser`: P0[List[Block[Span]]] = P.repSep0(Block.`block`[Span], ` \n*`)
|
||||
val `parser`: P0[List[Block[Span.F]]] = P.repSep0(Block.`block`[Span.F], ` \n*`)
|
||||
}
|
||||
|
22
src/main/scala/aqua/model/Scope.scala
Normal file
22
src/main/scala/aqua/model/Scope.scala
Normal file
@ -0,0 +1,22 @@
|
||||
package aqua.model
|
||||
|
||||
import aqua.parser.DataType
|
||||
import aqua.parser.lexer.Value
|
||||
|
||||
trait Instr
|
||||
|
||||
// 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]]
|
||||
)
|
@ -44,6 +44,7 @@ object DefFunc {
|
||||
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: Functor]: P[DefFunc[F]] =
|
||||
((`funchead` <* ` : ` <* ` \n*`) ~ FuncOp.body).map {
|
||||
case (h, b) ⇒ DefFunc(h, b)
|
||||
|
@ -43,7 +43,7 @@ object Token {
|
||||
P.repSep0(p, `,` <* ` \n*`.rep0)
|
||||
|
||||
def indented[T](p: P[T]): P[NonEmptyList[T]] =
|
||||
` `.flatMap(indent ⇒ (p.map(NonEmptyList.one) <* ` \n*`) ~ (P.string(indent) *> p).repSep0(` \n*`)).map {
|
||||
case (nel, l) ⇒ nel ++ l
|
||||
` `.flatMap(indent ⇒ p.map(NonEmptyList.one) ~ (` \n*` *> (P.string(indent) *> p).repSep0(` \n*`)).?).map {
|
||||
case (nel, l) ⇒ nel ++ l.getOrElse(Nil)
|
||||
}
|
||||
}
|
||||
|
89
src/main/scala/aqua/parser/lift/Names.scala
Normal file
89
src/main/scala/aqua/parser/lift/Names.scala
Normal file
@ -0,0 +1,89 @@
|
||||
package aqua.parser.lift
|
||||
|
||||
import aqua.parser.{AbilityFuncCall, AbilityId, DataType, ExecOp, Extract, FuncCall, FuncOp, On, Par}
|
||||
import aqua.parser.lexer.{Value, VarLambda}
|
||||
import cats.Comonad
|
||||
import cats.data.NonEmptyList
|
||||
import cats.syntax.comonad._
|
||||
import cats.syntax.functor._
|
||||
|
||||
// TODO: add comonad to show where import/export is declared
|
||||
// Fully resolved Scope must have no expected abilities (all resolved)
|
||||
case class Names(
|
||||
// None means "inherit"
|
||||
peerId: Option[Value] = None,
|
||||
// Take vars, set vars
|
||||
// Data type is not yet known
|
||||
importData: Set[String] = Set.empty,
|
||||
exportData: Set[String] = Set.empty,
|
||||
// Abilities can be imported or set
|
||||
expectedAbilities: Set[String] = Set.empty,
|
||||
resolvedAbilities: Set[String] = Set.empty,
|
||||
// We don't know the types yet
|
||||
expectArrows: Set[String] = Set.empty,
|
||||
// Set when know
|
||||
mode: Names.Mode.Value = Names.Mode.Seq
|
||||
)
|
||||
|
||||
object Names {
|
||||
|
||||
object Mode extends Enumeration {
|
||||
val Seq, Par, Xor = Value;
|
||||
}
|
||||
|
||||
def funcOps[G[_]: Comonad](ops: NonEmptyList[G[FuncOp[G]]]): Names =
|
||||
ops.toList.map(_.extract).map(funcOp[G]).foldLeft(Names()) {
|
||||
case (acc, n) if n.mode == Mode.Seq =>
|
||||
acc.copy(
|
||||
exportData = acc.exportData ++ n.exportData,
|
||||
importData = acc.importData ++ (n.importData -- acc.exportData),
|
||||
resolvedAbilities =
|
||||
if (n.peerId == acc.peerId) acc.resolvedAbilities ++ n.resolvedAbilities else acc.resolvedAbilities,
|
||||
expectedAbilities = acc.expectedAbilities ++ (n.expectedAbilities -- acc.resolvedAbilities),
|
||||
expectArrows = acc.expectArrows ++ n.expectArrows
|
||||
)
|
||||
case (acc, n) if n.mode == Mode.Par =>
|
||||
acc.copy(
|
||||
exportData = acc.exportData ++ n.exportData,
|
||||
importData = acc.importData ++ n.importData,
|
||||
expectedAbilities = acc.expectedAbilities ++ n.expectedAbilities,
|
||||
expectArrows = acc.expectArrows ++ n.expectArrows
|
||||
)
|
||||
case (acc, n) if n.mode == Mode.Xor =>
|
||||
acc.copy(
|
||||
importData = acc.importData ++ n.importData,
|
||||
expectedAbilities = acc.expectedAbilities ++ n.expectedAbilities,
|
||||
expectArrows = acc.expectArrows ++ n.expectArrows
|
||||
)
|
||||
}
|
||||
|
||||
def funcOp[G[_]: Comonad](op: FuncOp[G]): Names =
|
||||
op match {
|
||||
case FuncCall(fname, fargs) =>
|
||||
Names(
|
||||
expectArrows = Set(fname.extract),
|
||||
importData = fargs
|
||||
.collect(_.extract match {
|
||||
case VarLambda(name, _) => name
|
||||
})
|
||||
.toSet
|
||||
)
|
||||
case AbilityFuncCall(ab, fc) =>
|
||||
val funcNames = funcOp(fc.extract)
|
||||
funcNames.copy(expectedAbilities = Set(ab.extract))
|
||||
case Extract(n, fn) =>
|
||||
val funcNames = funcOp(fn.extract)
|
||||
funcNames.copy(exportData = Set(n.extract))
|
||||
case AbilityId(ab, _) =>
|
||||
Names(resolvedAbilities = Set(ab.extract))
|
||||
case On(p, ops) =>
|
||||
val ns = funcOps(ops.map(_.widen[FuncOp[G]])).copy(peerId = Some(p.extract))
|
||||
p.extract match {
|
||||
case VarLambda(name, _) =>
|
||||
ns.copy(importData = ns.importData + name)
|
||||
case _ => ns
|
||||
}
|
||||
case Par(op) =>
|
||||
funcOp(op.extract).copy(mode = Mode.Par)
|
||||
}
|
||||
}
|
@ -2,27 +2,27 @@ package aqua.parser.lift
|
||||
|
||||
import cats.Comonad
|
||||
import cats.parse.{Parser ⇒ P}
|
||||
import cats.free.Free
|
||||
|
||||
import scala.language.implicitConversions
|
||||
|
||||
case class Span[T](startIndex: Int, endIndex: Int, value: T)
|
||||
case class Span(startIndex: Int, endIndex: Int)
|
||||
|
||||
object Span {
|
||||
type F[T] = (Span, T)
|
||||
|
||||
implicit object spanComonad extends Comonad[Span] {
|
||||
override def extract[A](x: Span[A]): A = x.value
|
||||
implicit object spanComonad extends Comonad[F] {
|
||||
override def extract[A](x: F[A]): A = x._2
|
||||
|
||||
override def coflatMap[A, B](fa: Span[A])(f: Span[A] ⇒ B): Span[B] = fa.copy(value = f(fa))
|
||||
override def coflatMap[A, B](fa: F[A])(f: F[A] ⇒ B): F[B] = fa.copy(_2 = f(fa))
|
||||
|
||||
override def map[A, B](fa: Span[A])(f: A ⇒ B): Span[B] = fa.copy(value = f(fa.value))
|
||||
override def map[A, B](fa: F[A])(f: A ⇒ B): F[B] = fa.copy(_2 = f(fa._2))
|
||||
}
|
||||
|
||||
implicit object spanLiftParser extends LiftParser[Span] {
|
||||
implicit object spanLiftParser extends LiftParser[F] {
|
||||
|
||||
override def lift[T](p: P[T]): P[Span[T]] =
|
||||
override def lift[T](p: P[T]): P[F[T]] =
|
||||
(P.index.with1 ~ p ~ P.index).map {
|
||||
case ((s, v), e) ⇒ Span(s, e, v)
|
||||
case ((s, v), e) ⇒ (Span(s, e), v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,21 @@ class FuncSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
)
|
||||
}
|
||||
|
||||
"function" should "parse single line fn" in {
|
||||
val func =
|
||||
"""func getTime(peer: PeerId, ret: i32 -> ()) -> string:
|
||||
| ret(43)""".stripMargin
|
||||
|
||||
DefFunc.`deffunc`.parseAll(func).right.value should be(
|
||||
DefFunc[Id](
|
||||
getTimeHead,
|
||||
NonEmptyList.of(
|
||||
FuncCall[Id]("ret", Literal("43", BasicType.number) :: Nil)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"function" should "parse getTime as a whole" in {
|
||||
val func =
|
||||
"""func getTime(peer: PeerId, ret: i32 -> ()) -> string:
|
||||
|
28
src/test/scala/aqua/parser/NamesSpec.scala
Normal file
28
src/test/scala/aqua/parser/NamesSpec.scala
Normal file
@ -0,0 +1,28 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.lift.Names
|
||||
import cats.Id
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
|
||||
class NamesSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
private val namesId = Names.funcOps[Id](_)
|
||||
private val funcOpsP = (v: String) => FuncOp.body[Id].parseAll(v).right.value
|
||||
private val namesP = (v: String) => namesId(funcOpsP(v))
|
||||
|
||||
"names" should "extract from funcops" in {
|
||||
namesP(" func()") should be(Names(expectArrows = Set("func")))
|
||||
namesP(" fn(32)") should be(Names(expectArrows = Set("fn")))
|
||||
namesP(" fn(s)") should be(Names(expectArrows = Set("fn"), importData = Set("s")))
|
||||
namesP(" x <- fn(s)") should be(Names(expectArrows = Set("fn"), importData = Set("s"), exportData = Set("x")))
|
||||
namesP(" x <- fn(s)\n y <- fn(z)") should be(
|
||||
Names(expectArrows = Set("fn"), importData = Set("s", "z"), exportData = Set("x", "y"))
|
||||
)
|
||||
namesP(" x <- fn(s)\n y <- fn(x)") should be(
|
||||
Names(expectArrows = Set("fn"), importData = Set("s"), exportData = Set("x", "y"))
|
||||
)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package aqua.parser.lexer
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.data.NonEmptyList
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@ -44,4 +45,9 @@ class TokenSpec extends AnyFlatSpec with Matchers with EitherValues {
|
||||
|""".stripMargin).right.value should be(())
|
||||
}
|
||||
|
||||
"indented" should "parse 1 or more lines" in {
|
||||
indented(`.`).parseAll(" .\n .").right.value should be(NonEmptyList.of((), ()))
|
||||
indented(`.`).parseAll(" .").right.value should be(NonEmptyList.of(()))
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user