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"): service GetStr("multiret-test"):
retStr: string -> string retStr: string -> string
@ -10,6 +17,7 @@ const someStr = "some-str"
func tupleFunc() -> string, u8: func tupleFunc() -> string, u8:
str <- GetStr.retStr(someStr) str <- GetStr.retStr(someStr)
n <- GetNum.retNum() n <- GetNum.retNum()
Err.Peer.is_connected("Connected?")
<- str, n <- str, n
func multiReturnFunc(somethingToReturn: []u8, smthOption: ?string) -> []string, u8, string, []u8, ?string, u8: 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"): service Peer("peer"):
is_connected: string -> bool is_connected: string -> bool

View File

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

View File

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

View File

@ -16,8 +16,16 @@ object AquaRes {
ctx.exports ctx.exports
.map(ex => .map(ex =>
AquaRes( AquaRes(
funcs = Chain.fromSeq(ex.funcs.values.toSeq).map(Transform.fn(_, conf)), funcs = Chain
services = Chain.fromSeq(ex.services.values.toSeq).map(ServiceRes.fromModel(_)) .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) .getOrElse(blank)

View File

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

View File

@ -103,5 +103,5 @@ object Token {
P.repSep0(p, `,` <* ` \n+`.rep0) P.repSep0(p, `,` <* ` \n+`.rep0)
def asOpt[T](p: P[T]): P[(T, Option[T])] = 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.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers import org.scalatest.matchers.should.Matchers
class AbilitIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec { class AbilityIdExprSpec extends AnyFlatSpec with Matchers with AquaSpec {
import AquaSpec._ import AquaSpec._
"abilities" should "be parsed" in { "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 ctx
.pick(n.value, rn.map(_.value)) .pick(n.value, rn.map(_.value))
.map(validNec) .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) => { case (n, rn) =>
ctx ctx
.pick(n.value, rn.map(_.value)) .pick(n.value, rn.map(_.value))
.map(validNec) .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]]( .fold[ResAC[S]](
error( error(
tkn, 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)))) )(modName => validNec(acm.empty.copy(abilities = Map(modName -> ctx))))
@ -94,12 +104,13 @@ object HeaderSem {
val onExpr: PartialFunction[HeaderExpr[S], Res[S]] = { val onExpr: PartialFunction[HeaderExpr[S], Res[S]] = {
// Module header, like `module A declares *` // Module header, like `module A declares *`
case ModuleExpr(name, declareAll, declareNames, declareCustom) => case ModuleExpr(name, declareAll, declareNames, declareCustom) =>
val shouldDeclare = declareNames.map(_.value).toSet ++ declareCustom.map(_.value)
validNec( validNec(
HeaderSem[S]( HeaderSem[S](
// Save module header info // Save module header info
acm.empty.copy( acm.empty.copy(
module = Some(name.value), module = Some(name.value),
declares = declareNames.map(_.value).toSet ++ declareCustom.map(_.value) declares = shouldDeclare
), ),
ctx => ctx =>
// When file is handled, check that all the declarations exists // When file is handled, check that all the declarations exists
@ -124,7 +135,10 @@ object HeaderSem {
) )
) )
}.combineAll }.combineAll
.map(_ => ctx) .map(_ =>
// TODO: why module name and declares is lost? where is it lost?
ctx.copy(module = Some(name.value), declares = shouldDeclare)
)
) )
) )