mirror of
https://github.com/fluencelabs/aqua.git
synced 2025-03-15 11:40:50 +00:00
Parsing refactoring (#111)
* WIP, nothing work * delete ParExpr, ParSem, rewrite exprs, RootCompanion, WIP * list of tokens to tree * fix leaf ast * move expr * it works? * small changes * handle errors * some refactoring * WIP * WIP * merge * comments, cleaning up * split Companion and RootCompanion * clean up * couple tests * fix tests * ParPrefix? * Expr code reorganisation * ParExpr/ParSem returned * Test fixed Co-authored-by: dmitry <dmitry@fluence.one>
This commit is contained in:
parent
3d6cc02382
commit
720de27f14
@ -1,8 +1,23 @@
|
|||||||
service Test("123"):
|
service Peer("peer"):
|
||||||
doSomething: -> ()
|
is_connected: string -> bool
|
||||||
|
|
||||||
func b(me: string, a: bool, b: bool):
|
service Op("op"):
|
||||||
on me:
|
identity: -> ()
|
||||||
if a:
|
|
||||||
if b:
|
data User:
|
||||||
Test.doSomething()
|
peer_id: string
|
||||||
|
relay_id: string
|
||||||
|
name: string
|
||||||
|
|
||||||
|
service Test("test"):
|
||||||
|
getUserList: -> []User
|
||||||
|
doSomething: -> bool
|
||||||
|
|
||||||
|
func betterMessage(relay: string):
|
||||||
|
on relay:
|
||||||
|
Peer.is_connected("something")
|
||||||
|
par isOnline <- Peer.is_connected(relay)
|
||||||
|
par on "quray":
|
||||||
|
Peer.is_connected("qurara")
|
||||||
|
if isOnline:
|
||||||
|
Test.doSomething()
|
@ -1,6 +1,6 @@
|
|||||||
package aqua
|
package aqua
|
||||||
|
|
||||||
import aqua.parser.Ast
|
import aqua.parser.{Ast, BlockIndentError, FuncReturnError, LexerError}
|
||||||
import aqua.parser.lift.{FileSpan, LiftParser, Span}
|
import aqua.parser.lift.{FileSpan, LiftParser, Span}
|
||||||
import cats.data.ValidatedNec
|
import cats.data.ValidatedNec
|
||||||
|
|
||||||
@ -9,13 +9,21 @@ object Aqua {
|
|||||||
def parseString(input: String): ValidatedNec[AquaError, Ast[Span.F]] =
|
def parseString(input: String): ValidatedNec[AquaError, Ast[Span.F]] =
|
||||||
Ast
|
Ast
|
||||||
.fromString[Span.F](input)
|
.fromString[Span.F](input)
|
||||||
.leftMap(_.map(pe => SyntaxError(pe.failedAtOffset, pe.expected)))
|
.leftMap(_.map {
|
||||||
|
case BlockIndentError(indent, message) => CustomSyntaxError(indent._1, message)
|
||||||
|
case FuncReturnError(point, message) => CustomSyntaxError(point._1, message)
|
||||||
|
case LexerError(pe) => SyntaxError(pe.failedAtOffset, pe.expected)
|
||||||
|
})
|
||||||
|
|
||||||
def parseFileString(name: String, input: String): ValidatedNec[AquaError, Ast[FileSpan.F]] = {
|
def parseFileString(name: String, input: String): ValidatedNec[AquaError, Ast[FileSpan.F]] = {
|
||||||
implicit val fileLift: LiftParser[FileSpan.F] = FileSpan.fileSpanLiftParser(name, input)
|
implicit val fileLift: LiftParser[FileSpan.F] = FileSpan.fileSpanLiftParser(name, input)
|
||||||
Ast
|
Ast
|
||||||
.fromString[FileSpan.F](input)
|
.fromString[FileSpan.F](input)
|
||||||
.leftMap(_.map(pe => SyntaxError(pe.failedAtOffset, pe.expected)))
|
.leftMap(_.map {
|
||||||
|
case BlockIndentError(indent, message) => CustomSyntaxError(indent._1.span, message)
|
||||||
|
case FuncReturnError(point, message) => CustomSyntaxError(point._1.span, message)
|
||||||
|
case LexerError(pe) => SyntaxError(pe.failedAtOffset, pe.expected)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,23 @@ sealed trait AquaError {
|
|||||||
def showForConsole(script: String): String
|
def showForConsole(script: String): String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class CustomSyntaxError(span: Span, message: String) extends AquaError {
|
||||||
|
|
||||||
|
override def showForConsole(script: String): String =
|
||||||
|
span
|
||||||
|
.focus(Eval.later(LocationMap(script)), 2)
|
||||||
|
.map(
|
||||||
|
_.toConsoleStr(
|
||||||
|
message,
|
||||||
|
Console.RED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.getOrElse(
|
||||||
|
"(offset is beyond the script, syntax errors) Error: " + Console.RED + message
|
||||||
|
.mkString(", ")
|
||||||
|
) + Console.RESET + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
case class SyntaxError(offset: Int, expectations: NonEmptyList[Expectation]) extends AquaError {
|
case class SyntaxError(offset: Int, expectations: NonEmptyList[Expectation]) extends AquaError {
|
||||||
|
|
||||||
override def showForConsole(script: String): String =
|
override def showForConsole(script: String): String =
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package aqua.parser
|
package aqua.parser
|
||||||
|
|
||||||
import aqua.parser.expr._
|
import aqua.parser.expr._
|
||||||
import aqua.parser.head.{HeadExpr, HeaderExpr, ImportExpr}
|
import aqua.parser.head.{HeadExpr, HeaderExpr}
|
||||||
import aqua.parser.lexer.Token._
|
|
||||||
import aqua.parser.lift.LiftParser
|
import aqua.parser.lift.LiftParser
|
||||||
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
import cats.data.{Chain, Validated, ValidatedNec}
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
import cats.parse.{Parser => P, Parser0 => P0}
|
import cats.parse.{Parser0 => P0}
|
||||||
import cats.{Comonad, Eval}
|
import cats.{Comonad, Eval}
|
||||||
|
|
||||||
case class Ast[F[_]](head: Ast.Head[F], tree: Ast.Tree[F]) {
|
case class Ast[F[_]](head: Ast.Head[F], tree: Ast.Tree[F]) {
|
||||||
@ -19,29 +18,16 @@ object Ast {
|
|||||||
type Tree[F[_]] = Cofree[Chain, Expr[F]]
|
type Tree[F[_]] = Cofree[Chain, Expr[F]]
|
||||||
type Head[F[_]] = Cofree[Chain, HeaderExpr[F]]
|
type Head[F[_]] = Cofree[Chain, HeaderExpr[F]]
|
||||||
|
|
||||||
def treeExprs: List[Expr.Companion] =
|
def parser[F[_]: LiftParser: Comonad](): P0[ValidatedNec[ParserError[F], Ast[F]]] =
|
||||||
ServiceExpr :: AliasExpr :: DataStructExpr :: ConstantExpr :: FuncExpr :: Nil
|
(HeadExpr.ast[F].with1 ~ RootExpr.ast[F]()).map { case (head, bodyMaybe) =>
|
||||||
|
bodyMaybe.map(Ast(head, _))
|
||||||
|
}
|
||||||
|
|
||||||
def headExprs: List[HeaderExpr.Companion] =
|
def fromString[F[_]: LiftParser: Comonad](script: String): ValidatedNec[ParserError[F], Ast[F]] =
|
||||||
ImportExpr :: Nil
|
parser[F]()
|
||||||
|
.parseAll(script) match {
|
||||||
|
case Right(value) => value
|
||||||
|
case Left(e) => Validated.invalidNec(LexerError[F](e))
|
||||||
|
}
|
||||||
|
|
||||||
def parser[F[_]: LiftParser: Comonad](ps: Indent): P0[Ast[F]] =
|
|
||||||
((P.repSep0(P.oneOf(headExprs.map(_.ast[F])), ` \n+`) <* ` \n+`).? ~ P.repSep0(
|
|
||||||
P.oneOf(treeExprs.map(_.ast[F](ps))),
|
|
||||||
` \n+`
|
|
||||||
)).surroundedBy(` \n+`.?)
|
|
||||||
.map {
|
|
||||||
case (Some(head), tree) => Chain.fromSeq(head) -> Chain.fromSeq(tree)
|
|
||||||
case (_, tree) => Chain.empty[Head[F]] -> Chain.fromSeq(tree)
|
|
||||||
}
|
|
||||||
.map { case (hs, ls) =>
|
|
||||||
Ast(Cofree(HeadExpr(), Eval.now(hs)), Cofree(RootExpr(), Eval.now(ls)))
|
|
||||||
}
|
|
||||||
|
|
||||||
def fromString[F[_]: LiftParser: Comonad](script: String): ValidatedNec[P.Error, Ast[F]] =
|
|
||||||
Validated
|
|
||||||
.fromEither(
|
|
||||||
parser[F](Indent()).parseAll(script)
|
|
||||||
)
|
|
||||||
.leftMap(NonEmptyChain.one)
|
|
||||||
}
|
}
|
||||||
|
@ -3,58 +3,221 @@ package aqua.parser
|
|||||||
import aqua.parser.Ast.Tree
|
import aqua.parser.Ast.Tree
|
||||||
import aqua.parser.lexer.Token._
|
import aqua.parser.lexer.Token._
|
||||||
import aqua.parser.lift.LiftParser
|
import aqua.parser.lift.LiftParser
|
||||||
import cats.data.Chain
|
import aqua.parser.lift.LiftParser._
|
||||||
|
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
import cats.parse.{Parser => P}
|
import cats.parse.{Parser => P}
|
||||||
|
import cats.syntax.comonad._
|
||||||
import cats.{Comonad, Eval}
|
import cats.{Comonad, Eval}
|
||||||
|
import Chain.:==
|
||||||
|
|
||||||
trait Expr[F[_]]
|
abstract class Expr[F[_]](val companion: Expr.Companion) {
|
||||||
|
|
||||||
|
lazy val isBlock: Boolean = companion match {
|
||||||
|
case _: Expr.Block => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object Expr {
|
object Expr {
|
||||||
|
|
||||||
trait Companion {
|
trait Companion {
|
||||||
|
|
||||||
|
def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Ast.Tree[F]]]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Lexem extends Companion {
|
||||||
def p[F[_]: LiftParser: Comonad]: P[Expr[F]]
|
def p[F[_]: LiftParser: Comonad]: P[Expr[F]]
|
||||||
|
|
||||||
def ast[F[_]: LiftParser: Comonad](ps: Indent): P[Ast.Tree[F]]
|
def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] =
|
||||||
|
p.map(Cofree[Chain, Expr[F]](_, Eval.now(Chain.empty)))
|
||||||
}
|
}
|
||||||
|
|
||||||
def defer(companion: => Companion): Companion = new Companion {
|
trait Leaf extends Lexem {
|
||||||
override def p[F[_]: LiftParser: Comonad]: P[Expr[F]] = companion.p[F]
|
|
||||||
|
|
||||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): P[Tree[F]] = companion.ast[F](ps)
|
override def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Tree[F]]] =
|
||||||
|
p[F].map(e =>
|
||||||
|
Validated.validNec(
|
||||||
|
Cofree[Chain, Expr[F]](
|
||||||
|
e,
|
||||||
|
Eval.now(Chain.empty)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Leaf extends Companion {
|
def defer(companion: => Lexem): Lexem = new Lexem {
|
||||||
|
private lazy val c = companion
|
||||||
|
|
||||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): P[Ast.Tree[F]] =
|
override def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] = c.readLine[F]
|
||||||
p[F].map(Cofree[Chain, Expr[F]](_, Eval.now(Chain.empty)))
|
|
||||||
|
override def p[F[_]: LiftParser: Comonad]: P[Expr[F]] = c.p[F]
|
||||||
|
|
||||||
|
override def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Ast.Tree[F]]] =
|
||||||
|
c.ast[F]()
|
||||||
}
|
}
|
||||||
|
|
||||||
trait And extends Companion {
|
// expression that could have children
|
||||||
def validChildren: List[Companion]
|
// that will be parsed by `ast` method to a tree
|
||||||
|
trait Block extends Lexem {
|
||||||
|
|
||||||
|
override def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] = super.readLine[F] <* ` : `
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AndThen extends And {
|
trait Prefix extends Lexem {
|
||||||
|
def continueWith: List[Lexem]
|
||||||
|
|
||||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): P[Ast.Tree[F]] =
|
override def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] =
|
||||||
(p[F] ~ (` *` *> P
|
((super.readLine[F] <* ` `) ~ P.oneOf(continueWith.map(_.readLine.backtrack))).map {
|
||||||
.oneOf(validChildren.map(_.ast[F](ps)))
|
case (h, t) => h.copy(tail = Eval.now(Chain.one(t)))
|
||||||
.map(Chain.one))).map { case (expr, internal) =>
|
}
|
||||||
Cofree[Chain, Expr[F]](expr, Eval.now(internal))
|
|
||||||
|
override def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Tree[F]]] =
|
||||||
|
((super.readLine[F] <* ` `) ~ P.oneOf(continueWith.map(_.ast().backtrack))).map {
|
||||||
|
case (h, tm) => tm.map(t => h.copy(tail = Eval.now(Chain.one(t))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AndIndented extends And {
|
abstract class AndIndented extends Block {
|
||||||
|
def validChildren: List[Lexem]
|
||||||
|
|
||||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): P[Ast.Tree[F]] =
|
private def leaf[F[_]](expr: Expr[F]): Ast.Tree[F] =
|
||||||
(p[F] ~ (` : \n+` *> indented(
|
Cofree[Chain, Expr[F]](
|
||||||
s => {
|
expr,
|
||||||
val psI = ps.copy(indent = s)
|
Eval.now(Chain.empty)
|
||||||
P.oneOf(validChildren.map(_.ast[F](psI).backtrack))
|
)
|
||||||
},
|
|
||||||
ps.indent
|
private def last[F[_]](tree: Ast.Tree[F]): Expr[F] =
|
||||||
)).map(_.toList).map(Chain.fromSeq)).map { case (expr, internal) =>
|
tree.tailForced.lastOption.fold(tree.head)(last)
|
||||||
Cofree[Chain, Expr[F]](expr, Eval.now(internal))
|
|
||||||
}
|
private def setLeafs[F[_]](tree: Ast.Tree[F], children: Chain[Tree[F]]): Tree[F] =
|
||||||
|
tree.copy(tail = tree.tail.map {
|
||||||
|
case pref :== last =>
|
||||||
|
pref :+ setLeafs(last, children)
|
||||||
|
case _ =>
|
||||||
|
children
|
||||||
|
})
|
||||||
|
|
||||||
|
case class Acc[F[_]](
|
||||||
|
block: Option[(F[String], Tree[F])] = None,
|
||||||
|
window: Chain[(F[String], Tree[F])] = Chain.empty,
|
||||||
|
currentChildren: Chain[Ast.Tree[F]] = Chain.empty,
|
||||||
|
error: Chain[ParserError[F]] = Chain.empty
|
||||||
|
)
|
||||||
|
|
||||||
|
// converts list of expressions to a tree
|
||||||
|
def listToTree[F[_]: Comonad: LiftParser](
|
||||||
|
head: Tree[F],
|
||||||
|
exprs: Chain[(F[String], Ast.Tree[F])]
|
||||||
|
): ValidatedNec[ParserError[F], Ast.Tree[F]] = {
|
||||||
|
// if we don't have elements in a list, then head is a leaf
|
||||||
|
exprs.headOption
|
||||||
|
.fold[ValidatedNec[ParserError[F], Ast.Tree[F]]](Validated.validNec(head)) { lHead =>
|
||||||
|
// size of an indentation
|
||||||
|
val initialIndent = lHead._1.extract.length
|
||||||
|
// recursively creating a tree
|
||||||
|
// moving a window on a list depending on the nesting of the code
|
||||||
|
val acc = exprs.foldLeft(
|
||||||
|
Acc[F]()
|
||||||
|
) {
|
||||||
|
case (acc, (indent, currentExpr)) if acc.error.isEmpty =>
|
||||||
|
acc.block match {
|
||||||
|
case None =>
|
||||||
|
last(currentExpr) match {
|
||||||
|
// if next is block companion, start to gather all expressions under this block
|
||||||
|
case block if block.isBlock =>
|
||||||
|
acc.copy(block = Some(indent -> currentExpr))
|
||||||
|
// create leaf if token is on current level
|
||||||
|
case e =>
|
||||||
|
acc.copy(currentChildren = acc.currentChildren.append(leaf(e)))
|
||||||
|
}
|
||||||
|
// if we have root companion, gather all expressions that have indent > than current
|
||||||
|
case r @ Some((_, block)) =>
|
||||||
|
if (indent.extract.length > initialIndent) {
|
||||||
|
Acc[F](
|
||||||
|
r,
|
||||||
|
acc.window.append((indent, currentExpr)),
|
||||||
|
acc.currentChildren,
|
||||||
|
acc.error
|
||||||
|
)
|
||||||
|
} else if (indent.extract.length == initialIndent) {
|
||||||
|
// if root have no tokens in it - return an error
|
||||||
|
if (acc.window.isEmpty) {
|
||||||
|
Acc(error =
|
||||||
|
Chain.one(BlockIndentError(indent, "Block expression has no body"))
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// create a tree from gathered expressions and continue
|
||||||
|
listToTree[F](block, acc.window).fold(
|
||||||
|
e => acc.copy(error = e.toChain),
|
||||||
|
tree => {
|
||||||
|
val withTree = acc.currentChildren.append(tree)
|
||||||
|
last(currentExpr) match {
|
||||||
|
// if next expression is root companion, start to gather all tokens under this root
|
||||||
|
case block if block.isBlock =>
|
||||||
|
acc.copy(
|
||||||
|
block = Some(indent -> currentExpr),
|
||||||
|
currentChildren = withTree,
|
||||||
|
window = Chain.empty
|
||||||
|
)
|
||||||
|
// create leaf if token is on current level
|
||||||
|
case e =>
|
||||||
|
acc.copy(
|
||||||
|
block = None,
|
||||||
|
currentChildren = withTree.append(leaf(e)),
|
||||||
|
window = Chain.empty
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Acc[F](error =
|
||||||
|
Chain.one(
|
||||||
|
BlockIndentError(
|
||||||
|
indent,
|
||||||
|
"Wrong indentation. It must match the indentation of the previous expressions."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case (acc, _) =>
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize all `tails` in the accumulator
|
||||||
|
NonEmptyChain.fromChain(acc.error) match {
|
||||||
|
case None =>
|
||||||
|
acc.block match {
|
||||||
|
case Some((i, headExpr)) =>
|
||||||
|
if (acc.window.isEmpty) {
|
||||||
|
Validated.invalidNec(BlockIndentError(i, "Block expression has no body"))
|
||||||
|
} else {
|
||||||
|
// create a tree from the last expressions if the window is not empty
|
||||||
|
// this may happen if a function ended in a nested expression
|
||||||
|
val tree = listToTree[F](headExpr, acc.window)
|
||||||
|
tree.map(t => setLeafs(head, acc.currentChildren :+ t))
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
Validated.validNec(setLeafs(head, acc.currentChildren))
|
||||||
|
}
|
||||||
|
// pass through an error
|
||||||
|
case Some(err) => Validated.invalid(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Ast.Tree[F]]] =
|
||||||
|
(readLine[F] ~ (` \n+` *>
|
||||||
|
(P.repSep(
|
||||||
|
` `.lift ~ P.oneOf(validChildren.map(_.readLine[F].backtrack)),
|
||||||
|
` \n+`
|
||||||
|
) <* ` \n`.?)))
|
||||||
|
.map(t => listToTree(t._1, Chain.fromSeq(t._2.toList)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
package aqua.parser
|
|
||||||
|
|
||||||
case class Indent(indent: String = "")
|
|
9
parser/src/main/scala/aqua/parser/ParserError.scala
Normal file
9
parser/src/main/scala/aqua/parser/ParserError.scala
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package aqua.parser
|
||||||
|
|
||||||
|
import cats.parse.Parser
|
||||||
|
|
||||||
|
trait ParserError[F[_]]
|
||||||
|
|
||||||
|
case class LexerError[F[_]](err: Parser.Error) extends ParserError[F]
|
||||||
|
case class BlockIndentError[F[_]](indent: F[String], message: String) extends ParserError[F]
|
||||||
|
case class FuncReturnError[F[_]](point: F[Unit], message: String) extends ParserError[F]
|
@ -7,13 +7,13 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.{Parser => P}
|
import cats.parse.{Parser => P}
|
||||||
|
|
||||||
case class AbilityIdExpr[F[_]](ability: Ability[F], id: Value[F]) extends Expr[F]
|
case class AbilityIdExpr[F[_]](ability: Ability[F], id: Value[F]) extends Expr[F](AbilityIdExpr)
|
||||||
|
|
||||||
object AbilityIdExpr extends Expr.Leaf {
|
object AbilityIdExpr extends Expr.Leaf {
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: P[AbilityIdExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: P[AbilityIdExpr[F]] =
|
||||||
((Ability.ab[F] <* ` `) ~ Value.`value`).map {
|
((Ability.ab[F] <* ` `) ~ Value.`value`).map { case (ability, id) =>
|
||||||
case (ability, id) => AbilityIdExpr(ability, id)
|
AbilityIdExpr(ability, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,14 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F]) extends Expr[F]
|
case class AliasExpr[F[_]](name: CustomTypeToken[F], target: TypeToken[F])
|
||||||
|
extends Expr[F](AliasExpr)
|
||||||
|
|
||||||
object AliasExpr extends Expr.Leaf {
|
object AliasExpr extends Expr.Leaf {
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[AliasExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[AliasExpr[F]] =
|
||||||
((`alias` *> ` ` *> CustomTypeToken.ct[F] <* ` : `) ~ TypeToken.`typedef`[F]).map { case (name, target) =>
|
((`alias` *> ` ` *> CustomTypeToken.ct[F] <* ` : `) ~ TypeToken.`typedef`[F]).map {
|
||||||
AliasExpr(name, target)
|
case (name, target) =>
|
||||||
|
AliasExpr(name, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F]) extends Expr[F]
|
case class ArrowTypeExpr[F[_]](name: Name[F], `type`: ArrowTypeToken[F])
|
||||||
|
extends Expr[F](ArrowTypeExpr)
|
||||||
|
|
||||||
object ArrowTypeExpr extends Expr.Leaf {
|
object ArrowTypeExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import cats.parse.{Parser => P}
|
|||||||
case class AssignmentExpr[F[_]](
|
case class AssignmentExpr[F[_]](
|
||||||
variable: Name[F],
|
variable: Name[F],
|
||||||
value: Value[F]
|
value: Value[F]
|
||||||
) extends Expr[F]
|
) extends Expr[F](AssignmentExpr)
|
||||||
|
|
||||||
object AssignmentExpr extends Expr.Leaf {
|
object AssignmentExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ case class CallArrowExpr[F[_]](
|
|||||||
ability: Option[Ability[F]],
|
ability: Option[Ability[F]],
|
||||||
funcName: Name[F],
|
funcName: Name[F],
|
||||||
args: List[Value[F]]
|
args: List[Value[F]]
|
||||||
) extends Expr[F]
|
) extends Expr[F](CallArrowExpr)
|
||||||
|
|
||||||
object CallArrowExpr extends Expr.Leaf {
|
object CallArrowExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ case class ConstantExpr[F[_]](
|
|||||||
name: Name[F],
|
name: Name[F],
|
||||||
value: Value[F],
|
value: Value[F],
|
||||||
skipIfAlreadyDefined: Boolean
|
skipIfAlreadyDefined: Boolean
|
||||||
) extends Expr[F]
|
) extends Expr[F](ConstantExpr)
|
||||||
|
|
||||||
object ConstantExpr extends Expr.Leaf {
|
object ConstantExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -7,11 +7,11 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F]
|
case class DataStructExpr[F[_]](name: CustomTypeToken[F]) extends Expr[F](DataStructExpr)
|
||||||
|
|
||||||
object DataStructExpr extends Expr.AndIndented {
|
object DataStructExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] = List(FieldTypeExpr)
|
override def validChildren: List[Expr.Lexem] = FieldTypeExpr :: Nil
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[DataStructExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[DataStructExpr[F]] =
|
||||||
`data` *> ` ` *> CustomTypeToken.ct[F].map(DataStructExpr(_))
|
`data` *> ` ` *> CustomTypeToken.ct[F].map(DataStructExpr(_))
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package aqua.parser.expr
|
package aqua.parser.expr
|
||||||
|
|
||||||
import aqua.parser.Expr
|
import aqua.parser.Expr
|
||||||
|
import aqua.parser.lexer.Token._
|
||||||
import aqua.parser.lexer.{Name, Token, TypeToken}
|
import aqua.parser.lexer.{Name, Token, TypeToken}
|
||||||
import aqua.parser.lift.LiftParser
|
import aqua.parser.lift.LiftParser
|
||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
import Token._
|
|
||||||
|
|
||||||
case class DeclareStreamExpr[F[_]](name: Name[F], `type`: TypeToken[F]) extends Expr[F]
|
case class DeclareStreamExpr[F[_]](name: Name[F], `type`: TypeToken[F])
|
||||||
|
extends Expr[F](DeclareStreamExpr)
|
||||||
|
|
||||||
object DeclareStreamExpr extends Expr.Leaf {
|
object DeclareStreamExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -7,20 +7,11 @@ import aqua.parser.lift.LiftParser._
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class ElseOtherwiseExpr[F[_]](point: F[Unit]) extends Expr[F]
|
case class ElseOtherwiseExpr[F[_]](point: F[Unit]) extends Expr[F](ElseOtherwiseExpr)
|
||||||
|
|
||||||
object ElseOtherwiseExpr extends Expr.AndIndented {
|
object ElseOtherwiseExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] =
|
override def validChildren: List[Expr.Lexem] = ForExpr.validChildren
|
||||||
List(
|
|
||||||
Expr.defer(OnExpr),
|
|
||||||
ParExpr,
|
|
||||||
CallArrowExpr,
|
|
||||||
AbilityIdExpr,
|
|
||||||
Expr.defer(ForExpr),
|
|
||||||
Expr.defer(IfExpr),
|
|
||||||
Expr.defer(ElseOtherwiseExpr)
|
|
||||||
)
|
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[ElseOtherwiseExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[ElseOtherwiseExpr[F]] =
|
||||||
(`else` | `otherwise`).lift.map(ElseOtherwiseExpr(_))
|
(`else` | `otherwise`).lift.map(ElseOtherwiseExpr(_))
|
||||||
|
@ -7,7 +7,8 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F]) extends Expr[F]
|
case class FieldTypeExpr[F[_]](name: Name[F], `type`: DataTypeToken[F])
|
||||||
|
extends Expr[F](FieldTypeExpr)
|
||||||
|
|
||||||
object FieldTypeExpr extends Expr.Leaf {
|
object FieldTypeExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -13,22 +13,21 @@ case class ForExpr[F[_]](
|
|||||||
item: Name[F],
|
item: Name[F],
|
||||||
iterable: Value[F],
|
iterable: Value[F],
|
||||||
mode: Option[(F[ForExpr.Mode], ForExpr.Mode)]
|
mode: Option[(F[ForExpr.Mode], ForExpr.Mode)]
|
||||||
) extends Expr[F]
|
) extends Expr[F](ForExpr)
|
||||||
|
|
||||||
object ForExpr extends Expr.AndIndented {
|
object ForExpr extends Expr.AndIndented {
|
||||||
sealed trait Mode
|
sealed trait Mode
|
||||||
case object TryMode extends Mode
|
case object TryMode extends Mode
|
||||||
case object ParMode extends Mode
|
case object ParMode extends Mode
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] = List(
|
override def validChildren: List[Expr.Lexem] =
|
||||||
Expr.defer(OnExpr),
|
Expr.defer(OnExpr) ::
|
||||||
ParExpr,
|
Expr.defer(ForExpr) ::
|
||||||
Expr.defer(ForExpr),
|
CallArrowExpr ::
|
||||||
CallArrowExpr,
|
AbilityIdExpr ::
|
||||||
AbilityIdExpr,
|
Expr.defer(IfExpr) ::
|
||||||
Expr.defer(IfExpr),
|
Expr.defer(ElseOtherwiseExpr) ::
|
||||||
Expr.defer(ElseOtherwiseExpr)
|
Nil
|
||||||
)
|
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: P[ForExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: P[ForExpr[F]] =
|
||||||
((`for` *> ` ` *> Name.p[F] <* ` <- `) ~ Value
|
((`for` *> ` ` *> Name.p[F] <* ` <- `) ~ Value
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package aqua.parser.expr
|
package aqua.parser.expr
|
||||||
|
|
||||||
import aqua.parser.Ast.Tree
|
|
||||||
import aqua.parser.lexer.Token._
|
import aqua.parser.lexer.Token._
|
||||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
|
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
|
||||||
import aqua.parser.lift.LiftParser
|
import aqua.parser.lift.LiftParser
|
||||||
import aqua.parser.{Expr, Indent}
|
import aqua.parser.{Ast, Expr, FuncReturnError, ParserError}
|
||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
|
import cats.data.{Validated, ValidatedNec}
|
||||||
import cats.free.Cofree
|
import cats.free.Cofree
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
@ -14,21 +14,21 @@ case class FuncExpr[F[_]](
|
|||||||
args: List[Arg[F]],
|
args: List[Arg[F]],
|
||||||
ret: Option[DataTypeToken[F]],
|
ret: Option[DataTypeToken[F]],
|
||||||
retValue: Option[Value[F]]
|
retValue: Option[Value[F]]
|
||||||
) extends Expr[F]
|
) extends Expr[F](FuncExpr)
|
||||||
|
|
||||||
object FuncExpr extends Expr.AndIndented {
|
object FuncExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] = List(
|
override def validChildren: List[Expr.Lexem] =
|
||||||
OnExpr,
|
AbilityIdExpr ::
|
||||||
AbilityIdExpr,
|
ReturnExpr ::
|
||||||
ReturnExpr,
|
ForExpr ::
|
||||||
CallArrowExpr,
|
Expr.defer(OnExpr) ::
|
||||||
ParExpr,
|
CallArrowExpr ::
|
||||||
ForExpr,
|
IfExpr ::
|
||||||
IfExpr,
|
ElseOtherwiseExpr ::
|
||||||
ElseOtherwiseExpr,
|
ParExpr ::
|
||||||
DeclareStreamExpr
|
DeclareStreamExpr ::
|
||||||
)
|
Nil
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||||
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
||||||
@ -37,32 +37,45 @@ object FuncExpr extends Expr.AndIndented {
|
|||||||
FuncExpr(name, args, ret, None)
|
FuncExpr(name, args, ret, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): Parser[Tree[F]] =
|
override def ast[F[_]: LiftParser: Comonad](): Parser[ValidatedNec[ParserError[F], Ast.Tree[F]]] =
|
||||||
super.ast(ps).flatMap { tree =>
|
super
|
||||||
tree.head match {
|
.ast()
|
||||||
case funcExpr: FuncExpr[F] if funcExpr.ret.isDefined =>
|
.map(
|
||||||
tree.tail.value.lastOption.map(_.head) match {
|
_.andThen(tree =>
|
||||||
case Some(re: ReturnExpr[F]) =>
|
tree.head match {
|
||||||
Parser.pure(
|
case funcExpr: FuncExpr[F] =>
|
||||||
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
|
funcExpr.ret match {
|
||||||
)
|
case Some(ret) =>
|
||||||
case _ =>
|
tree.tail.value.lastOption.map(_.head) match {
|
||||||
Parser.failWith(
|
case Some(re: ReturnExpr[F]) =>
|
||||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
Validated
|
||||||
)
|
.validNec(Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail))
|
||||||
}
|
|
||||||
|
|
||||||
case _: FuncExpr[F] =>
|
case _ =>
|
||||||
tree.tail.value.lastOption.map(_.head) match {
|
Validated.invalidNec(
|
||||||
case Some(_: ReturnExpr[F]) =>
|
FuncReturnError[F](
|
||||||
Parser.failWith(
|
ret.unit,
|
||||||
"Trying to return a value from function that has no return type. Please add return type to function declaration, e.g. `func foo() -> RetType:`"
|
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||||
)
|
)
|
||||||
case _ =>
|
)
|
||||||
Parser.pure(tree)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case _ => Parser.pure(tree)
|
case None =>
|
||||||
}
|
tree.tail.value.lastOption.map(_.head) match {
|
||||||
}
|
case Some(re: ReturnExpr[F]) =>
|
||||||
|
Validated.invalidNec(
|
||||||
|
FuncReturnError[F](
|
||||||
|
re.value.unit,
|
||||||
|
"Trying to return a value from function that has no return type. Please add return type to function declaration, e.g. `func foo() -> RetType:`"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
Validated.validNec(tree)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case _ => Validated.validNec(tree)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -8,20 +8,18 @@ import aqua.types.LiteralType
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.{Parser => P}
|
import cats.parse.{Parser => P}
|
||||||
|
|
||||||
case class IfExpr[F[_]](left: Value[F], eqOp: EqOp[F], right: Value[F]) extends Expr[F]
|
case class IfExpr[F[_]](left: Value[F], eqOp: EqOp[F], right: Value[F]) extends Expr[F](IfExpr)
|
||||||
|
|
||||||
object IfExpr extends Expr.AndIndented {
|
object IfExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] =
|
override def validChildren: List[Expr.Lexem] =
|
||||||
List(
|
Expr.defer(OnExpr) ::
|
||||||
Expr.defer(OnExpr),
|
CallArrowExpr ::
|
||||||
ParExpr,
|
AbilityIdExpr ::
|
||||||
CallArrowExpr,
|
Expr.defer(ForExpr) ::
|
||||||
AbilityIdExpr,
|
Expr.defer(IfExpr) ::
|
||||||
Expr.defer(ForExpr),
|
Expr.defer(ElseOtherwiseExpr) ::
|
||||||
Expr.defer(IfExpr),
|
Nil
|
||||||
Expr.defer(ElseOtherwiseExpr)
|
|
||||||
)
|
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: P[IfExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: P[IfExpr[F]] =
|
||||||
(`if` *> ` ` *> Value.`value`[F] ~ (` ` *> EqOp.p[F] ~ (` ` *> Value.`value`[F])).?).map {
|
(`if` *> ` ` *> Value.`value`[F] ~ (` ` *> EqOp.p[F] ~ (` ` *> Value.`value`[F])).?).map {
|
||||||
|
@ -7,24 +7,24 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.{Parser => P}
|
import cats.parse.{Parser => P}
|
||||||
|
|
||||||
case class OnExpr[F[_]](peerId: Value[F], via: List[Value[F]]) extends Expr[F]
|
case class OnExpr[F[_]](peerId: Value[F], via: List[Value[F]]) extends Expr[F](OnExpr)
|
||||||
|
|
||||||
object OnExpr extends Expr.AndIndented {
|
object OnExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] =
|
override def validChildren: List[Expr.Lexem] =
|
||||||
List(
|
Expr.defer(OnExpr) ::
|
||||||
Expr.defer(OnExpr),
|
CallArrowExpr ::
|
||||||
ParExpr,
|
AbilityIdExpr ::
|
||||||
CallArrowExpr,
|
ParExpr ::
|
||||||
AbilityIdExpr,
|
Expr.defer(ForExpr) ::
|
||||||
Expr.defer(ForExpr),
|
Expr.defer(IfExpr) ::
|
||||||
Expr.defer(IfExpr),
|
Expr.defer(ElseOtherwiseExpr) ::
|
||||||
Expr.defer(ElseOtherwiseExpr)
|
Nil
|
||||||
)
|
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] = {
|
||||||
(`on` *> ` ` *> Value.`value`[F] ~ (` ` *> `via` *> ` ` *> Value.`value`[F]).rep0).map {
|
(`on` *> ` ` *> Value
|
||||||
case (peerId, via) =>
|
.`value`[F] ~ (` ` *> `via` *> ` ` *> Value.`value`[F]).rep0).map { case (peerId, via) =>
|
||||||
OnExpr(peerId, via)
|
OnExpr(peerId, via)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package aqua.parser.expr
|
package aqua.parser.expr
|
||||||
|
|
||||||
import aqua.parser.Expr
|
import aqua.parser.Expr
|
||||||
import aqua.parser.lexer.Token._
|
|
||||||
import aqua.parser.lift.LiftParser
|
|
||||||
import aqua.parser.lift.LiftParser._
|
|
||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F]
|
import aqua.parser.lexer.Token._
|
||||||
|
import aqua.parser.lift.LiftParser
|
||||||
|
import aqua.parser.lift.LiftParser._
|
||||||
|
|
||||||
object ParExpr extends Expr.AndThen {
|
case class ParExpr[F[_]](point: F[Unit]) extends Expr[F](ParExpr)
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] =
|
object ParExpr extends Expr.Prefix {
|
||||||
List(Expr.defer(OnExpr), CallArrowExpr, Expr.defer(ForExpr))
|
override def continueWith: List[Expr.Lexem] = CallArrowExpr :: OnExpr :: ForExpr :: Nil
|
||||||
|
|
||||||
|
override def p[F[_]: LiftParser: Comonad]: Parser[Expr[F]] = `par`.lift.map(ParExpr(_))
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[ParExpr[F]] =
|
|
||||||
`par`.lift.map(ParExpr(_))
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class ReturnExpr[F[_]](value: Value[F]) extends Expr[F]
|
case class ReturnExpr[F[_]](value: Value[F]) extends Expr[F](ReturnExpr)
|
||||||
|
|
||||||
object ReturnExpr extends Expr.Leaf {
|
object ReturnExpr extends Expr.Leaf {
|
||||||
|
|
||||||
|
@ -1,5 +1,35 @@
|
|||||||
package aqua.parser.expr
|
package aqua.parser.expr
|
||||||
|
|
||||||
import aqua.parser.Expr
|
import aqua.parser.Ast.Tree
|
||||||
|
import aqua.parser.lexer.Token.` \n+`
|
||||||
|
import aqua.parser.{Expr, ParserError}
|
||||||
|
import aqua.parser.lift.LiftParser
|
||||||
|
import cats.{Comonad, Eval}
|
||||||
|
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
||||||
|
import cats.free.Cofree
|
||||||
|
import cats.parse.{Parser => P}
|
||||||
|
|
||||||
case class RootExpr[F[_]]() extends Expr[F]
|
case class RootExpr[F[_]]() extends Expr[F](RootExpr)
|
||||||
|
|
||||||
|
object RootExpr extends Expr.Companion {
|
||||||
|
|
||||||
|
def validChildren: List[Expr.Lexem] =
|
||||||
|
ServiceExpr :: AliasExpr :: DataStructExpr :: ConstantExpr :: FuncExpr :: Nil
|
||||||
|
|
||||||
|
override def ast[F[_]: LiftParser: Comonad](): P[ValidatedNec[ParserError[F], Tree[F]]] =
|
||||||
|
P.repSep(
|
||||||
|
P.oneOf(RootExpr.validChildren.map(_.ast[F]())),
|
||||||
|
` \n+`
|
||||||
|
).surroundedBy(` \n+`.?)
|
||||||
|
.map(_.foldLeft[(Chain[ParserError[F]], Chain[Tree[F]])](Chain.empty -> Chain.empty) {
|
||||||
|
case ((errs, trees), Validated.Valid(tree)) => (errs, trees :+ tree)
|
||||||
|
case ((errs, trees), Validated.Invalid(err)) => (errs ++ err.toChain, trees)
|
||||||
|
})
|
||||||
|
.map { case (errs, trees) =>
|
||||||
|
NonEmptyChain
|
||||||
|
.fromChain(errs)
|
||||||
|
.fold[ValidatedNec[ParserError[F], Tree[F]]](
|
||||||
|
Validated.validNec(Cofree(RootExpr[F](), Eval.now(trees)))
|
||||||
|
)(Validated.invalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,11 +7,11 @@ import aqua.parser.lift.LiftParser
|
|||||||
import cats.Comonad
|
import cats.Comonad
|
||||||
import cats.parse.Parser
|
import cats.parse.Parser
|
||||||
|
|
||||||
case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Expr[F]
|
case class ServiceExpr[F[_]](name: Ability[F], id: Option[Value[F]]) extends Expr[F](ServiceExpr)
|
||||||
|
|
||||||
object ServiceExpr extends Expr.AndIndented {
|
object ServiceExpr extends Expr.AndIndented {
|
||||||
|
|
||||||
override def validChildren: List[Expr.Companion] = List(ArrowTypeExpr)
|
override def validChildren: List[Expr.Lexem] = ArrowTypeExpr :: Nil
|
||||||
|
|
||||||
override def p[F[_]: LiftParser: Comonad]: Parser[ServiceExpr[F]] =
|
override def p[F[_]: LiftParser: Comonad]: Parser[ServiceExpr[F]] =
|
||||||
(`service` *> ` ` *> Ability.ab[F] ~ Value.`value`[F].between(`(`, `)`).backtrack.?).map {
|
(`service` *> ` ` *> Ability.ab[F] ~ Value.`value`[F].between(`(`, `)`).backtrack.?).map {
|
||||||
|
@ -1,3 +1,27 @@
|
|||||||
package aqua.parser.head
|
package aqua.parser.head
|
||||||
|
|
||||||
|
import aqua.parser.Ast
|
||||||
|
import aqua.parser.lexer.Token.` \n+`
|
||||||
|
import aqua.parser.lift.LiftParser
|
||||||
|
import cats.{Comonad, Eval}
|
||||||
|
import cats.data.Chain
|
||||||
|
import cats.free.Cofree
|
||||||
|
import cats.parse.{Parser => P, Parser0 => P0}
|
||||||
|
|
||||||
case class HeadExpr[F[_]]() extends HeaderExpr[F]
|
case class HeadExpr[F[_]]() extends HeaderExpr[F]
|
||||||
|
|
||||||
|
object HeadExpr {
|
||||||
|
|
||||||
|
def headExprs: List[HeaderExpr.Companion] =
|
||||||
|
ImportExpr :: Nil
|
||||||
|
|
||||||
|
def ast[F[_]: LiftParser: Comonad]: P0[Ast.Head[F]] =
|
||||||
|
P.repSep0(P.oneOf(headExprs.map(_.ast[F])), ` \n+`)
|
||||||
|
.surroundedBy(` \n+`.?)
|
||||||
|
.?
|
||||||
|
.map {
|
||||||
|
case Some(exprs) => Chain.fromSeq(exprs)
|
||||||
|
case None => Chain.empty[Ast.Head[F]]
|
||||||
|
}
|
||||||
|
.map(exprs => Cofree(HeadExpr[F](), Eval.now(exprs)))
|
||||||
|
}
|
||||||
|
@ -67,15 +67,11 @@ object Token {
|
|||||||
val `=` : P[Unit] = P.string("=")
|
val `=` : P[Unit] = P.string("=")
|
||||||
val ` = ` : P[Unit] = P.string("=").surroundedBy(` `.?)
|
val ` = ` : P[Unit] = P.string("=").surroundedBy(` `.?)
|
||||||
val `?` : P[Unit] = P.string("?")
|
val `?` : P[Unit] = P.string("?")
|
||||||
val `<-` : P[Unit] = P.string("<-").backtrack
|
val `<-` : P[Unit] = P.string("<-")
|
||||||
|
|
||||||
def comma[T](p: P[T]): P[NonEmptyList[T]] =
|
def comma[T](p: P[T]): P[NonEmptyList[T]] =
|
||||||
P.repSep(p, `,` <* ` \n+`.rep0)
|
P.repSep(p, `,` <* ` \n+`.rep0)
|
||||||
|
|
||||||
def comma0[T](p: P[T]): P0[List[T]] =
|
def comma0[T](p: P[T]): P0[List[T]] =
|
||||||
P.repSep0(p, `,` <* ` \n+`.rep0)
|
P.repSep0(p, `,` <* ` \n+`.rep0)
|
||||||
|
|
||||||
def indented[T](p: String => P[T], baseIndent: String): P[NonEmptyList[T]] =
|
|
||||||
(if (baseIndent.nonEmpty) P.string(baseIndent) ~ ` ` else ` `).string
|
|
||||||
.flatMap(indent ⇒ p(indent).repSep((` \n+` *> P.string(indent)).backtrack))
|
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,11 @@
|
|||||||
package aqua
|
package aqua
|
||||||
|
|
||||||
import aqua.parser.expr.{
|
import aqua.parser.expr._
|
||||||
AbilityIdExpr,
|
import aqua.parser.lexer._
|
||||||
AliasExpr,
|
|
||||||
ArrowTypeExpr,
|
|
||||||
AssignmentExpr,
|
|
||||||
CallArrowExpr,
|
|
||||||
ConstantExpr,
|
|
||||||
DataStructExpr,
|
|
||||||
ElseOtherwiseExpr,
|
|
||||||
FieldTypeExpr,
|
|
||||||
ForExpr,
|
|
||||||
FuncExpr,
|
|
||||||
IfExpr,
|
|
||||||
OnExpr,
|
|
||||||
ParExpr,
|
|
||||||
ReturnExpr,
|
|
||||||
ServiceExpr
|
|
||||||
}
|
|
||||||
import aqua.parser.lexer.{
|
|
||||||
Ability,
|
|
||||||
Arg,
|
|
||||||
ArrayTypeToken,
|
|
||||||
ArrowTypeToken,
|
|
||||||
BasicTypeToken,
|
|
||||||
CustomTypeToken,
|
|
||||||
DataTypeToken,
|
|
||||||
EqOp,
|
|
||||||
IntoField,
|
|
||||||
Literal,
|
|
||||||
Name,
|
|
||||||
TypeToken,
|
|
||||||
VarLambda
|
|
||||||
}
|
|
||||||
import cats.Id
|
|
||||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||||
import aqua.types.LiteralType.{bool, number, string}
|
import aqua.types.LiteralType.{bool, number, string}
|
||||||
import aqua.types.{LiteralType, ScalarType}
|
import aqua.types.{LiteralType, ScalarType}
|
||||||
|
import cats.Id
|
||||||
import org.scalatest.EitherValues
|
import org.scalatest.EitherValues
|
||||||
|
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
@ -97,9 +66,6 @@ trait AquaSpec extends EitherValues {
|
|||||||
def parseOn(str: String): OnExpr[Id] =
|
def parseOn(str: String): OnExpr[Id] =
|
||||||
OnExpr.p[Id].parseAll(str).value
|
OnExpr.p[Id].parseAll(str).value
|
||||||
|
|
||||||
def parsePar(str: String): ParExpr[Id] =
|
|
||||||
ParExpr.p[Id].parseAll(str).value
|
|
||||||
|
|
||||||
def parseReturn(str: String): ReturnExpr[Id] =
|
def parseReturn(str: String): ReturnExpr[Id] =
|
||||||
ReturnExpr.p[Id].parseAll(str).value
|
ReturnExpr.p[Id].parseAll(str).value
|
||||||
|
|
||||||
|
@ -22,7 +22,21 @@ class CallArrowSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
|||||||
)
|
)
|
||||||
|
|
||||||
parseExpr("func(arg.doSomething)") should be(
|
parseExpr("func(arg.doSomething)") should be(
|
||||||
CallArrowExpr[Id](None, None, Name[Id]("func"), List(toVarLambda("arg", List("doSomething"))))
|
CallArrowExpr[Id](
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Name[Id]("func"),
|
||||||
|
List(toVarLambda("arg", List("doSomething")))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
parseExpr("func(arg.doSomething.and.doSomethingElse)") should be(
|
||||||
|
CallArrowExpr[Id](
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Name[Id]("func"),
|
||||||
|
List(toVarLambda("arg", List("doSomething", "and", "doSomethingElse")))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
parseExpr("func(arg.doSomething.and.doSomethingElse)") should be(
|
parseExpr("func(arg.doSomething.and.doSomethingElse)") should be(
|
||||||
|
@ -9,7 +9,7 @@ import org.scalatest.matchers.should.Matchers
|
|||||||
class ForExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
class ForExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||||
import AquaSpec._
|
import AquaSpec._
|
||||||
|
|
||||||
"on" should "be parsed" in {
|
"for expression" should "be parsed" in {
|
||||||
parseFor("for some <- \"a\"") should be(
|
parseFor("for some <- \"a\"") should be(
|
||||||
ForExpr[Id]("some", toStr("a"), None)
|
ForExpr[Id]("some", toStr("a"), None)
|
||||||
)
|
)
|
||||||
@ -33,5 +33,6 @@ class ForExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
|||||||
parseFor("for some <- false try") should be(
|
parseFor("for some <- false try") should be(
|
||||||
ForExpr[Id]("some", toBool(false), Some(ForExpr.TryMode -> ForExpr.TryMode))
|
ForExpr[Id]("some", toBool(false), Some(ForExpr.TryMode -> ForExpr.TryMode))
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
|||||||
| Peer "some id"
|
| Peer "some id"
|
||||||
| call(true)""".stripMargin
|
| call(true)""".stripMargin
|
||||||
|
|
||||||
val tree = FuncExpr.ast[Id](Indent()).parseAll(script).value
|
val tree = FuncExpr.ast[Id]().parseAll(script).value.toEither.value
|
||||||
val funcBody = checkHeadGetTail(tree, FuncExpr("a", Nil, None, None), 1).toList
|
val funcBody = checkHeadGetTail(tree, FuncExpr("a", Nil, None, None), 1).toList
|
||||||
|
|
||||||
val ifBody =
|
val ifBody =
|
||||||
@ -97,12 +97,35 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
|||||||
3
|
3
|
||||||
).toList
|
).toList
|
||||||
|
|
||||||
ifBody.head.head should be(CallArrowExpr(Some(toName("x")), Some(toAb("Ab")), "func", Nil))
|
ifBody.head.head should be(
|
||||||
|
CallArrowExpr(Some(toName("x")), Some(toAb("Ab")), "func", Nil)
|
||||||
|
)
|
||||||
ifBody(1).head should be(AbilityIdExpr(toAb("Peer"), toStr("some id")))
|
ifBody(1).head should be(AbilityIdExpr(toAb("Peer"), toStr("some id")))
|
||||||
ifBody(2).head should be(CallArrowExpr(None, None, "call", List(toBool(true))))
|
ifBody(2).head should be(CallArrowExpr(None, None, "call", List(toBool(true))))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"function with wrong indent" should "parse with error" in {
|
||||||
|
val script =
|
||||||
|
"""func tryGen() -> bool:
|
||||||
|
| on "deeper" via "deep":
|
||||||
|
| v <- Local.gt()
|
||||||
|
| <- v
|
||||||
|
|""".stripMargin
|
||||||
|
|
||||||
|
parser[Id]().parseAll(script).value.toEither shouldBe Symbol("left")
|
||||||
|
}
|
||||||
|
|
||||||
|
"function with root expression without children" should "parse with error" in {
|
||||||
|
val script =
|
||||||
|
"""func tryGen() -> bool:
|
||||||
|
| on "deeper" via "deep":
|
||||||
|
| <- v
|
||||||
|
|""".stripMargin
|
||||||
|
|
||||||
|
parser[Id]().parseAll(script).value.toEither shouldBe Symbol("left")
|
||||||
|
}
|
||||||
|
|
||||||
"multi function expression" should "parse" in {
|
"multi function expression" should "parse" in {
|
||||||
val script =
|
val script =
|
||||||
"""service Local("local"):
|
"""service Local("local"):
|
||||||
@ -120,7 +143,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
|||||||
| three <- Local.gt()
|
| three <- Local.gt()
|
||||||
| <- two""".stripMargin
|
| <- two""".stripMargin
|
||||||
|
|
||||||
val tree = parser[Id](Indent()).parseAll(script).value
|
val tree = parser[Id]().parseAll(script).value.toEither.value
|
||||||
|
|
||||||
val qTree = tree.tree.foldLeft(mutable.Queue.empty[Expr[Id]]) { case (acc, tag) =>
|
val qTree = tree.tree.foldLeft(mutable.Queue.empty[Expr[Id]]) { case (acc, tag) =>
|
||||||
acc.enqueue(tag)
|
acc.enqueue(tag)
|
||||||
|
@ -1,17 +1,34 @@
|
|||||||
package aqua.parser
|
package aqua.parser
|
||||||
|
|
||||||
import aqua.AquaSpec
|
import aqua.AquaSpec
|
||||||
import aqua.parser.expr.{OnExpr, ParExpr}
|
import aqua.parser.expr.{CallArrowExpr, ParExpr}
|
||||||
import cats.Id
|
|
||||||
import org.scalatest.flatspec.AnyFlatSpec
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
|
import cats.{Eval, Id}
|
||||||
|
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||||
|
import cats.data.Chain
|
||||||
|
import cats.free.Cofree
|
||||||
|
|
||||||
class ParExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
class ParExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||||
import AquaSpec._
|
|
||||||
|
|
||||||
"on" should "be parsed" in {
|
"par" should "be parsed" in {
|
||||||
parsePar("par") should be(
|
ParExpr.readLine[Id].parseAll("par x <- y()").value should be(
|
||||||
ParExpr[Id](())
|
Cofree[Chain, Expr[Id]](
|
||||||
|
ParExpr[Id](()),
|
||||||
|
Eval.now(
|
||||||
|
Chain(
|
||||||
|
Cofree[Chain, Expr[Id]](
|
||||||
|
CallArrowExpr(
|
||||||
|
Some(AquaSpec.toName("x")),
|
||||||
|
None,
|
||||||
|
AquaSpec.toName("y"),
|
||||||
|
Nil
|
||||||
|
),
|
||||||
|
Eval.now(Chain.empty)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package aqua.parser.lexer
|
package aqua.parser.lexer
|
||||||
|
|
||||||
import aqua.parser.lexer.Token._
|
import aqua.parser.lexer.Token._
|
||||||
import cats.data.NonEmptyList
|
|
||||||
import cats.parse.{Parser => P}
|
|
||||||
import org.scalatest.EitherValues
|
import org.scalatest.EitherValues
|
||||||
import org.scalatest.flatspec.AnyFlatSpec
|
import org.scalatest.flatspec.AnyFlatSpec
|
||||||
import org.scalatest.matchers.should.Matchers
|
import org.scalatest.matchers.should.Matchers
|
||||||
@ -46,35 +44,4 @@ class TokenSpec extends AnyFlatSpec with Matchers with EitherValues {
|
|||||||
|""".stripMargin).right.value should be(())
|
|""".stripMargin).right.value should be(())
|
||||||
}
|
}
|
||||||
|
|
||||||
"indented" should "parse 1 or more lines" in {
|
|
||||||
indented(_ => `.`, "").parseAll(" .\n .").right.value should be(NonEmptyList.of((), ()))
|
|
||||||
indented(_ => `.`, "").parseAll(" .\n .\n .").right.value should be(NonEmptyList.of((), (), ()))
|
|
||||||
indented(_ => `.`, "").parse(" .\n .\n .\n").right.value should be(
|
|
||||||
("\n", NonEmptyList.of((), (), ()))
|
|
||||||
)
|
|
||||||
indented(_ => `.`, "").parse(" .\n .\n .\n ").right.value should be(
|
|
||||||
("\n ", NonEmptyList.of((), (), ()))
|
|
||||||
)
|
|
||||||
indented(_ => `.`, "").parse(" .\n .\n .\n .").right.value should be(
|
|
||||||
("", NonEmptyList.of((), (), (), ()))
|
|
||||||
)
|
|
||||||
indented(_ => `.`, "").parseAll(" .").right.value should be(NonEmptyList.of(()))
|
|
||||||
|
|
||||||
indented(_ => `.`, " ").parse(" .\n .").right.value should be(("\n .", NonEmptyList.of(())))
|
|
||||||
indented(_ => `.`, " ").parse(" .\n ").right.value should be(("\n ", NonEmptyList.of(())))
|
|
||||||
}
|
|
||||||
|
|
||||||
"nested indented" should "not fail on empty lines" in {
|
|
||||||
sealed trait Tree
|
|
||||||
case object Leaf extends Tree
|
|
||||||
case class Node(branches: NonEmptyList[Tree]) extends Tree
|
|
||||||
|
|
||||||
lazy val p: P[NonEmptyList[Tree]] =
|
|
||||||
indented(
|
|
||||||
_ => P.string("newline") *> (` \n+` *> P.defer(p)).?.map(_.fold[Tree](Leaf)(Node)),
|
|
||||||
""
|
|
||||||
)
|
|
||||||
p.parseAll(" newline").right.value should be(NonEmptyList.of(Leaf))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ package aqua.semantics
|
|||||||
import aqua.model.Model
|
import aqua.model.Model
|
||||||
import aqua.parser.Expr
|
import aqua.parser.Expr
|
||||||
import aqua.parser.expr._
|
import aqua.parser.expr._
|
||||||
|
import aqua.semantics.expr._
|
||||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||||
import aqua.semantics.rules.names.NamesAlgebra
|
import aqua.semantics.rules.names.NamesAlgebra
|
||||||
import aqua.semantics.rules.types.TypesAlgebra
|
import aqua.semantics.rules.types.TypesAlgebra
|
||||||
import aqua.semantics.expr._
|
|
||||||
|
|
||||||
object ExprSem {
|
object ExprSem {
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package aqua.semantics.expr
|
package aqua.semantics.expr
|
||||||
|
|
||||||
import aqua.model.{Model, ValueModel}
|
|
||||||
import aqua.model.func.Call
|
import aqua.model.func.Call
|
||||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||||
|
import aqua.model.{Model, ValueModel}
|
||||||
import aqua.parser.expr.CallArrowExpr
|
import aqua.parser.expr.CallArrowExpr
|
||||||
import aqua.semantics.Prog
|
import aqua.semantics.Prog
|
||||||
import aqua.semantics.rules.ValuesAlgebra
|
import aqua.semantics.rules.ValuesAlgebra
|
||||||
@ -72,6 +72,7 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
|||||||
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
.map(Option(_))
|
.map(Option(_))
|
||||||
})
|
})
|
||||||
@ -85,6 +86,7 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
|||||||
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
.map(Option(_))
|
.map(Option(_))
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package aqua.semantics.expr
|
package aqua.semantics.expr
|
||||||
|
|
||||||
import aqua.model.Model
|
import aqua.model.Model
|
||||||
import aqua.model.func.body.{ForTag, FuncOp, NextTag, OpTag, ParTag, SeqTag, XorTag}
|
import aqua.model.func.body._
|
||||||
import aqua.parser.expr.ForExpr
|
import aqua.parser.expr.ForExpr
|
||||||
import aqua.semantics.Prog
|
import aqua.semantics.Prog
|
||||||
import aqua.semantics.rules.ValuesAlgebra
|
import aqua.semantics.rules.ValuesAlgebra
|
||||||
|
@ -34,7 +34,6 @@ class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
|||||||
),
|
),
|
||||||
op
|
op
|
||||||
)
|
)
|
||||||
|
|
||||||
case m => Model.error("On body is not an op, it's " + m)
|
case m => Model.error("On body is not an op, it's " + m)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,8 @@ class ParSem[F[_]](val expr: ParExpr[F]) extends AnyVal {
|
|||||||
|
|
||||||
def program[Alg[_]]: Prog[Alg, Model] =
|
def program[Alg[_]]: Prog[Alg, Model] =
|
||||||
Prog.after[Alg, Model] {
|
Prog.after[Alg, Model] {
|
||||||
case g: FuncOp => Free.pure[Alg, Model](FuncOp.wrap(ParTag, g))
|
case g: FuncOp =>
|
||||||
|
Free.pure[Alg, Model](FuncOp.wrap(ParTag, g))
|
||||||
case g => Free.pure[Alg, Model](g)
|
case g => Free.pure[Alg, Model](g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user