Imports bugfixes (#249)

This commit is contained in:
Dmitry Kurinskiy 2021-08-21 11:10:38 +03:00 committed by GitHub
parent b9af20339b
commit 3de8571be9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 190 additions and 24 deletions

View File

@ -1,3 +1,10 @@
module Ret
import Service from "service.aqua"
use "error.aqua"
export GetStr, tupleFunc, Service as S
service GetStr("multiret-test"):
retStr: string -> string
@ -10,6 +17,7 @@ const someStr = "some-str"
func tupleFunc() -> string, u8:
str <- GetStr.retStr(someStr)
n <- GetNum.retNum()
Err.Peer.is_connected("Connected?")
<- str, n
func multiReturnFunc(somethingToReturn: []u8, smthOption: ?string) -> []string, u8, string, []u8, ?string, u8:

View File

@ -1,3 +1,5 @@
module Err declares Peer, Op, include
service Peer("peer"):
is_connected: string -> bool

View File

@ -1,3 +1,5 @@
module Srv declares *
import "chatApp.aqua"
service Service("affinidi/chat"):

View File

@ -12,19 +12,20 @@ object Test extends IOApp.Simple {
implicit val aio: AquaIO[IO] = new AquaFilesIO[IO]
override def run: IO[Unit] =
AquaPathCompiler
.compileFilesTo[IO](
Path("./aqua-src"),
List(Path("./aqua")),
Path("./target"),
TypeScriptBackend,
TransformConfig()
)
.map {
case Validated.Invalid(errs) =>
errs.map(System.err.println): Unit
case Validated.Valid(res) =>
res.map(println): Unit
}
IO.println("Start ms: " + System.currentTimeMillis()) *>
AquaPathCompiler
.compileFilesTo[IO](
Path("./aqua-src"),
List(Path("./aqua")),
Path("./target"),
TypeScriptBackend,
TransformConfig()
)
.map {
case Validated.Invalid(errs) =>
errs.map(System.err.println): Unit
case Validated.Valid(res) =>
res.map(println): Unit
} <* IO.println("End ms : " + System.currentTimeMillis())
}

View File

@ -16,8 +16,16 @@ object AquaRes {
ctx.exports
.map(ex =>
AquaRes(
funcs = Chain.fromSeq(ex.funcs.values.toSeq).map(Transform.fn(_, conf)),
services = Chain.fromSeq(ex.services.values.toSeq).map(ServiceRes.fromModel(_))
funcs = Chain
.fromSeq(ex.funcs.map { case (fnName, fn) =>
fn.copy(funcName = fnName)
}.toSeq)
.map(Transform.fn(_, conf)),
services = Chain
.fromSeq(ex.services.map { case (srvName, srv) =>
srv.copy(name = srvName)
}.toSeq)
.map(ServiceRes.fromModel(_))
)
)
.getOrElse(blank)

View File

@ -14,7 +14,7 @@ case class UseExpr[F[_]](
object UseExpr extends HeaderExpr.Leaf {
override def p[F[_]: LiftParser: Comonad]: Parser[HeaderExpr[F]] =
(`use` *> Value
(`use` *> ` ` *> Value
.string[F] ~ (` as ` *> Ability.ab[F]).?).map { case (filename, asModule) =>
UseExpr(filename, asModule)
}

View File

@ -103,5 +103,5 @@ object Token {
P.repSep0(p, `,` <* ` \n+`.rep0)
def asOpt[T](p: P[T]): P[(T, Option[T])] =
p ~ (` as ` *> p).?
p ~ (` as `.backtrack *> p).?
}

View File

@ -8,7 +8,7 @@ import cats.Id
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class AbilitIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
class AbilityIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec._
"abilities" should "be parsed" in {

View File

@ -0,0 +1,46 @@
package aqua.parser.head
import aqua.AquaSpec
import aqua.parser.expr.AbilityIdExpr
import aqua.parser.lexer.{Literal, Token}
import aqua.parser.lift.LiftParser.Implicits.*
import aqua.types.LiteralType
import cats.Id
import cats.data.NonEmptyList
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class FromSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec.*
"from expression" should "be parsed" in {
FromExpr.nameOrAbAs[Id].parseAll("Ability").value should be(Right(toAb("Ability") -> None))
FromExpr.nameOrAbAs[Id].parseAll("Ability as Ab").value should be(
Right(toAb("Ability") -> Some(toAb("Ab")))
)
FromExpr.nameOrAbAs[Id].parseAll("function").value should be(
Left(toName("function") -> None)
)
FromExpr.nameOrAbAs[Id].parseAll("function as fn").value should be(
Left(toName("function") -> Some(toName("fn")))
)
}
"from list" should "be parsed" in {
Token.comma(FromExpr.nameOrAbAs[Id]).parseAll("Ability").value.head should be(
Right(toAb("Ability") -> None)
)
Token.comma(FromExpr.nameOrAbAs[Id]).parseAll("Ability as Ab").value.head should be(
Right(toAb("Ability") -> Some(toAb("Ab")))
)
FromExpr.importFrom[Id].parseAll("Ability as Ab from").value should be(
NonEmptyList.one(Right(toAb("Ability") -> Some(toAb("Ab"))))
)
FromExpr.importFrom[Id].parseAll("Ability from").value should be(
NonEmptyList.one(Right(toAb("Ability") -> None))
)
}
}

View File

@ -0,0 +1,45 @@
package aqua.parser.head
import aqua.AquaSpec
import aqua.parser.expr.AbilityIdExpr
import aqua.parser.lexer.{Literal, Token}
import aqua.parser.lift.LiftParser.Implicits.*
import aqua.types.LiteralType
import cats.Id
import cats.data.NonEmptyList
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class ImportFromSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec.*
"import from" should "be parsed" in {
FromExpr.nameOrAbAs[Id].parseAll("")
ImportFromExpr.p[Id].parseAll("import MyModule from \"file.aqua\"").value should be(
ImportFromExpr(
NonEmptyList.one(Right(toAb("MyModule") -> None)),
toStr("file.aqua")
)
)
HeadExpr
.ast[Id]
.parseAll(s"""import MyModule, func as fn from "file.aqua"
|""".stripMargin)
.value
.tail
.value
.headOption
.get
.head should be(
ImportFromExpr(
NonEmptyList.fromListUnsafe(
Right(toAb("MyModule") -> None) :: Left(toName("func") -> Some(toName("fn"))) :: Nil
),
toStr("file.aqua")
)
)
}
}

View File

@ -0,0 +1,40 @@
package aqua.parser.head
import aqua.AquaSpec
import aqua.parser.expr.AbilityIdExpr
import aqua.parser.lexer.{Literal, Token}
import aqua.types.LiteralType
import cats.Id
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import aqua.parser.lift.LiftParser.Implicits.*
class ModuleSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec.*
"module header" should "be parsed" in {
ModuleExpr.p[Id].parseAll("module MyModule").value should be(
ModuleExpr(
toAb("MyModule"),
None,
Nil,
Nil
)
)
HeadExpr
.ast[Id]
.parseAll(s"""module MyModule declares *
|""".stripMargin)
.value
.head should be(
ModuleExpr(
toAb("MyModule"),
Some(Token.lift[Id, Unit](())),
Nil,
Nil
)
)
}
}

View File

@ -66,13 +66,23 @@ object HeaderSem {
ctx
.pick(n.value, rn.map(_.value))
.map(validNec)
.getOrElse(error(n, s"Imported file has no ${n.value} declaration"))
.getOrElse(
error(
n,
s"Imported file declares [${ctx.declares.mkString(", ")}], no ${n.value} declared. Try adding `declares *` to that file."
)
)
},
{ case (n, rn) =>
ctx
.pick(n.value, rn.map(_.value))
.map(validNec)
.getOrElse(error(n, s"Imported file has no ${n.value} declaration"))
.getOrElse(
error(
n,
s"Imported file declares [${ctx.declares.mkString(", ")}], no ${n.value} declared. Try adding `declares *` to that file."
)
)
}
)
)
@ -86,7 +96,7 @@ object HeaderSem {
.fold[ResAC[S]](
error(
tkn,
"Used module has no `module` header. Please add `module` header or use ... as ModuleName, or switch to import"
s"Used module has no `module` header. Please add `module` header or use ... as ModuleName, or switch to import"
)
)(modName => validNec(acm.empty.copy(abilities = Map(modName -> ctx))))
@ -94,12 +104,13 @@ object HeaderSem {
val onExpr: PartialFunction[HeaderExpr[S], Res[S]] = {
// Module header, like `module A declares *`
case ModuleExpr(name, declareAll, declareNames, declareCustom) =>
val shouldDeclare = declareNames.map(_.value).toSet ++ declareCustom.map(_.value)
validNec(
HeaderSem[S](
// Save module header info
acm.empty.copy(
module = Some(name.value),
declares = declareNames.map(_.value).toSet ++ declareCustom.map(_.value)
declares = shouldDeclare
),
ctx =>
// When file is handled, check that all the declarations exists
@ -124,7 +135,10 @@ object HeaderSem {
)
)
}.combineAll
.map(_ => ctx)
.map(_ =>
// TODO: why module name and declares is lost? where is it lost?
ctx.copy(module = Some(name.value), declares = shouldDeclare)
)
)
)