mirror of
https://github.com/fluencelabs/aqua.git
synced 2024-12-04 22:50:18 +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"):
|
||||
doSomething: -> ()
|
||||
service Peer("peer"):
|
||||
is_connected: string -> bool
|
||||
|
||||
func b(me: string, a: bool, b: bool):
|
||||
on me:
|
||||
if a:
|
||||
if b:
|
||||
Test.doSomething()
|
||||
service Op("op"):
|
||||
identity: -> ()
|
||||
|
||||
data User:
|
||||
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
|
||||
|
||||
import aqua.parser.Ast
|
||||
import aqua.parser.{Ast, BlockIndentError, FuncReturnError, LexerError}
|
||||
import aqua.parser.lift.{FileSpan, LiftParser, Span}
|
||||
import cats.data.ValidatedNec
|
||||
|
||||
@ -9,13 +9,21 @@ object Aqua {
|
||||
def parseString(input: String): ValidatedNec[AquaError, Ast[Span.F]] =
|
||||
Ast
|
||||
.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]] = {
|
||||
implicit val fileLift: LiftParser[FileSpan.F] = FileSpan.fileSpanLiftParser(name, input)
|
||||
Ast
|
||||
.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
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
override def showForConsole(script: String): String =
|
||||
|
@ -1,12 +1,11 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.parser.expr._
|
||||
import aqua.parser.head.{HeadExpr, HeaderExpr, ImportExpr}
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.head.{HeadExpr, HeaderExpr}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
|
||||
import cats.data.{Chain, Validated, ValidatedNec}
|
||||
import cats.free.Cofree
|
||||
import cats.parse.{Parser => P, Parser0 => P0}
|
||||
import cats.parse.{Parser0 => P0}
|
||||
import cats.{Comonad, Eval}
|
||||
|
||||
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 Head[F[_]] = Cofree[Chain, HeaderExpr[F]]
|
||||
|
||||
def treeExprs: List[Expr.Companion] =
|
||||
ServiceExpr :: AliasExpr :: DataStructExpr :: ConstantExpr :: FuncExpr :: Nil
|
||||
def parser[F[_]: LiftParser: Comonad](): P0[ValidatedNec[ParserError[F], Ast[F]]] =
|
||||
(HeadExpr.ast[F].with1 ~ RootExpr.ast[F]()).map { case (head, bodyMaybe) =>
|
||||
bodyMaybe.map(Ast(head, _))
|
||||
}
|
||||
|
||||
def headExprs: List[HeaderExpr.Companion] =
|
||||
ImportExpr :: Nil
|
||||
def fromString[F[_]: LiftParser: Comonad](script: String): ValidatedNec[ParserError[F], Ast[F]] =
|
||||
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.lexer.Token._
|
||||
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.parse.{Parser => P}
|
||||
import cats.syntax.comonad._
|
||||
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 {
|
||||
|
||||
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 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 {
|
||||
override def p[F[_]: LiftParser: Comonad]: P[Expr[F]] = companion.p[F]
|
||||
trait Leaf extends Lexem {
|
||||
|
||||
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]] =
|
||||
p[F].map(Cofree[Chain, Expr[F]](_, Eval.now(Chain.empty)))
|
||||
override def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] = c.readLine[F]
|
||||
|
||||
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 {
|
||||
def validChildren: List[Companion]
|
||||
// expression that could have children
|
||||
// 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]] =
|
||||
(p[F] ~ (` *` *> P
|
||||
.oneOf(validChildren.map(_.ast[F](ps)))
|
||||
.map(Chain.one))).map { case (expr, internal) =>
|
||||
Cofree[Chain, Expr[F]](expr, Eval.now(internal))
|
||||
override def readLine[F[_]: LiftParser: Comonad]: P[Ast.Tree[F]] =
|
||||
((super.readLine[F] <* ` `) ~ P.oneOf(continueWith.map(_.readLine.backtrack))).map {
|
||||
case (h, t) => h.copy(tail = Eval.now(Chain.one(t)))
|
||||
}
|
||||
|
||||
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]] =
|
||||
(p[F] ~ (` : \n+` *> indented(
|
||||
s => {
|
||||
val psI = ps.copy(indent = s)
|
||||
P.oneOf(validChildren.map(_.ast[F](psI).backtrack))
|
||||
},
|
||||
ps.indent
|
||||
)).map(_.toList).map(Chain.fromSeq)).map { case (expr, internal) =>
|
||||
Cofree[Chain, Expr[F]](expr, Eval.now(internal))
|
||||
}
|
||||
private def leaf[F[_]](expr: Expr[F]): Ast.Tree[F] =
|
||||
Cofree[Chain, Expr[F]](
|
||||
expr,
|
||||
Eval.now(Chain.empty)
|
||||
)
|
||||
|
||||
private def last[F[_]](tree: Ast.Tree[F]): Expr[F] =
|
||||
tree.tailForced.lastOption.fold(tree.head)(last)
|
||||
|
||||
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.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 {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[AbilityIdExpr[F]] =
|
||||
((Ability.ab[F] <* ` `) ~ Value.`value`).map {
|
||||
case (ability, id) => AbilityIdExpr(ability, id)
|
||||
((Ability.ab[F] <* ` `) ~ Value.`value`).map { case (ability, id) =>
|
||||
AbilityIdExpr(ability, id)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,12 +7,14 @@ import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[AliasExpr[F]] =
|
||||
((`alias` *> ` ` *> CustomTypeToken.ct[F] <* ` : `) ~ TypeToken.`typedef`[F]).map { case (name, target) =>
|
||||
AliasExpr(name, target)
|
||||
((`alias` *> ` ` *> CustomTypeToken.ct[F] <* ` : `) ~ TypeToken.`typedef`[F]).map {
|
||||
case (name, target) =>
|
||||
AliasExpr(name, target)
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
|
@ -10,7 +10,7 @@ import cats.parse.{Parser => P}
|
||||
case class AssignmentExpr[F[_]](
|
||||
variable: Name[F],
|
||||
value: Value[F]
|
||||
) extends Expr[F]
|
||||
) extends Expr[F](AssignmentExpr)
|
||||
|
||||
object AssignmentExpr extends Expr.Leaf {
|
||||
|
||||
|
@ -12,7 +12,7 @@ case class CallArrowExpr[F[_]](
|
||||
ability: Option[Ability[F]],
|
||||
funcName: Name[F],
|
||||
args: List[Value[F]]
|
||||
) extends Expr[F]
|
||||
) extends Expr[F](CallArrowExpr)
|
||||
|
||||
object CallArrowExpr extends Expr.Leaf {
|
||||
|
||||
|
@ -11,7 +11,7 @@ case class ConstantExpr[F[_]](
|
||||
name: Name[F],
|
||||
value: Value[F],
|
||||
skipIfAlreadyDefined: Boolean
|
||||
) extends Expr[F]
|
||||
) extends Expr[F](ConstantExpr)
|
||||
|
||||
object ConstantExpr extends Expr.Leaf {
|
||||
|
||||
|
@ -7,11 +7,11 @@ import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
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]] =
|
||||
`data` *> ` ` *> CustomTypeToken.ct[F].map(DataStructExpr(_))
|
||||
|
@ -1,13 +1,14 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Expr
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Name, Token, TypeToken}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
|
@ -7,20 +7,11 @@ import aqua.parser.lift.LiftParser._
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
override def validChildren: List[Expr.Companion] =
|
||||
List(
|
||||
Expr.defer(OnExpr),
|
||||
ParExpr,
|
||||
CallArrowExpr,
|
||||
AbilityIdExpr,
|
||||
Expr.defer(ForExpr),
|
||||
Expr.defer(IfExpr),
|
||||
Expr.defer(ElseOtherwiseExpr)
|
||||
)
|
||||
override def validChildren: List[Expr.Lexem] = ForExpr.validChildren
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[ElseOtherwiseExpr[F]] =
|
||||
(`else` | `otherwise`).lift.map(ElseOtherwiseExpr(_))
|
||||
|
@ -7,7 +7,8 @@ import aqua.parser.lift.LiftParser
|
||||
import cats.Comonad
|
||||
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 {
|
||||
|
||||
|
@ -13,22 +13,21 @@ case class ForExpr[F[_]](
|
||||
item: Name[F],
|
||||
iterable: Value[F],
|
||||
mode: Option[(F[ForExpr.Mode], ForExpr.Mode)]
|
||||
) extends Expr[F]
|
||||
) extends Expr[F](ForExpr)
|
||||
|
||||
object ForExpr extends Expr.AndIndented {
|
||||
sealed trait Mode
|
||||
case object TryMode extends Mode
|
||||
case object ParMode extends Mode
|
||||
|
||||
override def validChildren: List[Expr.Companion] = List(
|
||||
Expr.defer(OnExpr),
|
||||
ParExpr,
|
||||
Expr.defer(ForExpr),
|
||||
CallArrowExpr,
|
||||
AbilityIdExpr,
|
||||
Expr.defer(IfExpr),
|
||||
Expr.defer(ElseOtherwiseExpr)
|
||||
)
|
||||
override def validChildren: List[Expr.Lexem] =
|
||||
Expr.defer(OnExpr) ::
|
||||
Expr.defer(ForExpr) ::
|
||||
CallArrowExpr ::
|
||||
AbilityIdExpr ::
|
||||
Expr.defer(IfExpr) ::
|
||||
Expr.defer(ElseOtherwiseExpr) ::
|
||||
Nil
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[ForExpr[F]] =
|
||||
((`for` *> ` ` *> Name.p[F] <* ` <- `) ~ Value
|
||||
|
@ -1,11 +1,11 @@
|
||||
package aqua.parser.expr
|
||||
|
||||
import aqua.parser.Ast.Tree
|
||||
import aqua.parser.lexer.Token._
|
||||
import aqua.parser.lexer.{Arg, DataTypeToken, Name, Value}
|
||||
import aqua.parser.lift.LiftParser
|
||||
import aqua.parser.{Expr, Indent}
|
||||
import aqua.parser.{Ast, Expr, FuncReturnError, ParserError}
|
||||
import cats.Comonad
|
||||
import cats.data.{Validated, ValidatedNec}
|
||||
import cats.free.Cofree
|
||||
import cats.parse.Parser
|
||||
|
||||
@ -14,21 +14,21 @@ case class FuncExpr[F[_]](
|
||||
args: List[Arg[F]],
|
||||
ret: Option[DataTypeToken[F]],
|
||||
retValue: Option[Value[F]]
|
||||
) extends Expr[F]
|
||||
) extends Expr[F](FuncExpr)
|
||||
|
||||
object FuncExpr extends Expr.AndIndented {
|
||||
|
||||
override def validChildren: List[Expr.Companion] = List(
|
||||
OnExpr,
|
||||
AbilityIdExpr,
|
||||
ReturnExpr,
|
||||
CallArrowExpr,
|
||||
ParExpr,
|
||||
ForExpr,
|
||||
IfExpr,
|
||||
ElseOtherwiseExpr,
|
||||
DeclareStreamExpr
|
||||
)
|
||||
override def validChildren: List[Expr.Lexem] =
|
||||
AbilityIdExpr ::
|
||||
ReturnExpr ::
|
||||
ForExpr ::
|
||||
Expr.defer(OnExpr) ::
|
||||
CallArrowExpr ::
|
||||
IfExpr ::
|
||||
ElseOtherwiseExpr ::
|
||||
ParExpr ::
|
||||
DeclareStreamExpr ::
|
||||
Nil
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: Parser[FuncExpr[F]] =
|
||||
((`func` *> ` ` *> Name.p[F]) ~ comma0(Arg.p)
|
||||
@ -37,32 +37,45 @@ object FuncExpr extends Expr.AndIndented {
|
||||
FuncExpr(name, args, ret, None)
|
||||
}
|
||||
|
||||
override def ast[F[_]: LiftParser: Comonad](ps: Indent): Parser[Tree[F]] =
|
||||
super.ast(ps).flatMap { tree =>
|
||||
tree.head match {
|
||||
case funcExpr: FuncExpr[F] if funcExpr.ret.isDefined =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(re: ReturnExpr[F]) =>
|
||||
Parser.pure(
|
||||
Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail)
|
||||
)
|
||||
case _ =>
|
||||
Parser.failWith(
|
||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||
)
|
||||
}
|
||||
override def ast[F[_]: LiftParser: Comonad](): Parser[ValidatedNec[ParserError[F], Ast.Tree[F]]] =
|
||||
super
|
||||
.ast()
|
||||
.map(
|
||||
_.andThen(tree =>
|
||||
tree.head match {
|
||||
case funcExpr: FuncExpr[F] =>
|
||||
funcExpr.ret match {
|
||||
case Some(ret) =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(re: ReturnExpr[F]) =>
|
||||
Validated
|
||||
.validNec(Cofree(funcExpr.copy(retValue = Some(re.value)), tree.tail))
|
||||
|
||||
case _: FuncExpr[F] =>
|
||||
tree.tail.value.lastOption.map(_.head) match {
|
||||
case Some(_: ReturnExpr[F]) =>
|
||||
Parser.failWith(
|
||||
"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 _ =>
|
||||
Parser.pure(tree)
|
||||
}
|
||||
case _ =>
|
||||
Validated.invalidNec(
|
||||
FuncReturnError[F](
|
||||
ret.unit,
|
||||
"Return type is defined for function, but nothing returned. Use `<- value` as the last expression inside function body."
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
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.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 {
|
||||
|
||||
override def validChildren: List[Expr.Companion] =
|
||||
List(
|
||||
Expr.defer(OnExpr),
|
||||
ParExpr,
|
||||
CallArrowExpr,
|
||||
AbilityIdExpr,
|
||||
Expr.defer(ForExpr),
|
||||
Expr.defer(IfExpr),
|
||||
Expr.defer(ElseOtherwiseExpr)
|
||||
)
|
||||
override def validChildren: List[Expr.Lexem] =
|
||||
Expr.defer(OnExpr) ::
|
||||
CallArrowExpr ::
|
||||
AbilityIdExpr ::
|
||||
Expr.defer(ForExpr) ::
|
||||
Expr.defer(IfExpr) ::
|
||||
Expr.defer(ElseOtherwiseExpr) ::
|
||||
Nil
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[IfExpr[F]] =
|
||||
(`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.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 {
|
||||
|
||||
override def validChildren: List[Expr.Companion] =
|
||||
List(
|
||||
Expr.defer(OnExpr),
|
||||
ParExpr,
|
||||
CallArrowExpr,
|
||||
AbilityIdExpr,
|
||||
Expr.defer(ForExpr),
|
||||
Expr.defer(IfExpr),
|
||||
Expr.defer(ElseOtherwiseExpr)
|
||||
)
|
||||
override def validChildren: List[Expr.Lexem] =
|
||||
Expr.defer(OnExpr) ::
|
||||
CallArrowExpr ::
|
||||
AbilityIdExpr ::
|
||||
ParExpr ::
|
||||
Expr.defer(ForExpr) ::
|
||||
Expr.defer(IfExpr) ::
|
||||
Expr.defer(ElseOtherwiseExpr) ::
|
||||
Nil
|
||||
|
||||
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] =
|
||||
(`on` *> ` ` *> Value.`value`[F] ~ (` ` *> `via` *> ` ` *> Value.`value`[F]).rep0).map {
|
||||
case (peerId, via) =>
|
||||
OnExpr(peerId, via)
|
||||
override def p[F[_]: LiftParser: Comonad]: P[OnExpr[F]] = {
|
||||
(`on` *> ` ` *> Value
|
||||
.`value`[F] ~ (` ` *> `via` *> ` ` *> Value.`value`[F]).rep0).map { case (peerId, via) =>
|
||||
OnExpr(peerId, via)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
package 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.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] =
|
||||
List(Expr.defer(OnExpr), CallArrowExpr, Expr.defer(ForExpr))
|
||||
object ParExpr extends Expr.Prefix {
|
||||
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.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 {
|
||||
|
||||
|
@ -1,5 +1,35 @@
|
||||
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.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 {
|
||||
|
||||
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]] =
|
||||
(`service` *> ` ` *> Ability.ab[F] ~ Value.`value`[F].between(`(`, `)`).backtrack.?).map {
|
||||
|
@ -1,3 +1,27 @@
|
||||
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]
|
||||
|
||||
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("=").surroundedBy(` `.?)
|
||||
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]] =
|
||||
P.repSep(p, `,` <* ` \n+`.rep0)
|
||||
|
||||
def comma0[T](p: P[T]): P0[List[T]] =
|
||||
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
|
||||
|
||||
import aqua.parser.expr.{
|
||||
AbilityIdExpr,
|
||||
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.expr._
|
||||
import aqua.parser.lexer._
|
||||
import aqua.parser.lift.LiftParser.Implicits.idLiftParser
|
||||
import aqua.types.LiteralType.{bool, number, string}
|
||||
import aqua.types.{LiteralType, ScalarType}
|
||||
import cats.Id
|
||||
import org.scalatest.EitherValues
|
||||
|
||||
import scala.collection.mutable
|
||||
@ -97,9 +66,6 @@ trait AquaSpec extends EitherValues {
|
||||
def parseOn(str: String): OnExpr[Id] =
|
||||
OnExpr.p[Id].parseAll(str).value
|
||||
|
||||
def parsePar(str: String): ParExpr[Id] =
|
||||
ParExpr.p[Id].parseAll(str).value
|
||||
|
||||
def parseReturn(str: String): ReturnExpr[Id] =
|
||||
ReturnExpr.p[Id].parseAll(str).value
|
||||
|
||||
|
@ -22,7 +22,21 @@ class CallArrowSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
)
|
||||
|
||||
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(
|
||||
|
@ -9,7 +9,7 @@ import org.scalatest.matchers.should.Matchers
|
||||
class ForExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
import AquaSpec._
|
||||
|
||||
"on" should "be parsed" in {
|
||||
"for expression" should "be parsed" in {
|
||||
parseFor("for some <- \"a\"") should be(
|
||||
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(
|
||||
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"
|
||||
| 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 ifBody =
|
||||
@ -97,12 +97,35 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
3
|
||||
).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(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 {
|
||||
val script =
|
||||
"""service Local("local"):
|
||||
@ -120,7 +143,7 @@ class FuncExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
|
||||
| three <- Local.gt()
|
||||
| <- 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) =>
|
||||
acc.enqueue(tag)
|
||||
|
@ -1,17 +1,34 @@
|
||||
package aqua.parser
|
||||
|
||||
import aqua.AquaSpec
|
||||
import aqua.parser.expr.{OnExpr, ParExpr}
|
||||
import cats.Id
|
||||
import aqua.parser.expr.{CallArrowExpr, ParExpr}
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
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 {
|
||||
import AquaSpec._
|
||||
|
||||
"on" should "be parsed" in {
|
||||
parsePar("par") should be(
|
||||
ParExpr[Id](())
|
||||
"par" should "be parsed" in {
|
||||
ParExpr.readLine[Id].parseAll("par x <- y()").value should be(
|
||||
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
|
||||
|
||||
import aqua.parser.lexer.Token._
|
||||
import cats.data.NonEmptyList
|
||||
import cats.parse.{Parser => P}
|
||||
import org.scalatest.EitherValues
|
||||
import org.scalatest.flatspec.AnyFlatSpec
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
@ -46,35 +44,4 @@ 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(" .\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.parser.Expr
|
||||
import aqua.parser.expr._
|
||||
import aqua.semantics.expr._
|
||||
import aqua.semantics.rules.abilities.AbilitiesAlgebra
|
||||
import aqua.semantics.rules.names.NamesAlgebra
|
||||
import aqua.semantics.rules.types.TypesAlgebra
|
||||
import aqua.semantics.expr._
|
||||
|
||||
object ExprSem {
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
import aqua.model.{Model, ValueModel}
|
||||
import aqua.model.func.Call
|
||||
import aqua.model.func.body.{CallArrowTag, CallServiceTag, FuncOp}
|
||||
import aqua.model.{Model, ValueModel}
|
||||
import aqua.parser.expr.CallArrowExpr
|
||||
import aqua.semantics.Prog
|
||||
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))
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
.map(Option(_))
|
||||
})
|
||||
@ -85,6 +86,7 @@ class CallArrowSem[F[_]](val expr: CallArrowExpr[F]) extends AnyVal {
|
||||
Call(argsResolved, (variable.map(_.value), t).mapN(Call.Export))
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
.map(Option(_))
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
package aqua.semantics.expr
|
||||
|
||||
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.semantics.Prog
|
||||
import aqua.semantics.rules.ValuesAlgebra
|
||||
|
@ -34,7 +34,6 @@ class OnSem[F[_]](val expr: OnExpr[F]) extends AnyVal {
|
||||
),
|
||||
op
|
||||
)
|
||||
|
||||
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] =
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user