Imports/exports fixes (#258)

* Fix for export in headerless file

* Ability arrow resolution bugfix

* Trying to reproduce a bug

* Allow dots in module declaration
This commit is contained in:
Dmitry Kurinskiy 2021-08-31 13:05:26 +03:00 committed by GitHub
parent bc461457da
commit 3e7b11db10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 37 deletions

16
aqua-src/export.aqua Normal file
View File

@ -0,0 +1,16 @@
module Export.Test declares foobar, foo, bar
func bar() -> string:
<- " I am MyFooBar bar"
func foo() -> string:
<- "I am MyFooBar foo"
func foobar() -> []string:
res: *string
res <- foo()
res <- bar()
<- res
service ExpSrv:
baz()

View File

@ -0,0 +1,3 @@
service OneMore:
more_call()
consume(s: string)

23
aqua-src/import.aqua Normal file
View File

@ -0,0 +1,23 @@
-- import.aqua
module Import.Test
import foobar from "export.aqua"
use foo as f from "export.aqua" as Exp
use "export.aqua"
import "gen/OneMore.aqua"
import OneMore as OM from "gen/OneMore.aqua"
export foo_wrapper as wrap, foobar as barfoo
func foo_wrapper() -> string:
z <- Exp.f()
q <- Export.Test.bar()
OneMore "hello"
OneMore.more_call()
OM "ohmygod"
OM.more_call()
OM.consume(q)
<- z

View File

@ -17,7 +17,7 @@ val declineV = "2.1.0"
name := "aqua-hll"
val commons = Seq(
baseAquaVersion := "0.2.0",
baseAquaVersion := "0.2.1",
version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"),
scalaVersion := dottyVersion,
libraryDependencies ++= Seq(

View File

@ -5,6 +5,7 @@ import aqua.model.func.{ArgsCall, FuncCallable, FuncModel}
import aqua.types.{StructType, Type}
import cats.Monoid
import cats.data.NonEmptyMap
import cats.kernel.Semigroup
import cats.syntax.functor.*
import cats.syntax.monoid.*
import scribe.Logging
@ -150,37 +151,34 @@ object AquaContext extends Logging {
)
def fromScriptModel(sm: ScriptModel, init: AquaContext)(implicit
aqum: Monoid[AquaContext]
aqum: Semigroup[AquaContext]
): AquaContext =
sm.models
.foldLeft((init, Monoid.empty[AquaContext])) {
.foldLeft((init, blank)) {
case ((ctx, exportContext), c: ConstantModel) =>
val add =
Monoid
.empty[AquaContext]
blank
.copy(values =
if (c.allowOverrides && ctx.values.contains(c.name)) ctx.values
else ctx.values.updated(c.name, c.value.resolveWith(ctx.values))
if (c.allowOverrides && ctx.values.contains(c.name)) Map.empty
else Map(c.name -> c.value.resolveWith(ctx.values))
)
(ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), func: FuncModel) =>
val fr = func.capture(ctx.allFuncs(), ctx.allValues())
val add =
Monoid.empty[AquaContext].copy(funcs = ctx.funcs.updated(func.name, fr))
blank.copy(funcs = Map(func.name -> fr))
(ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), t: TypeModel) =>
val add =
Monoid.empty[AquaContext].copy(types = ctx.types.updated(t.name, t.`type`))
blank.copy(types = Map(t.name -> t.`type`))
(ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), m: ServiceModel) =>
val add =
Monoid
.empty[AquaContext]
blank
.copy(
abilities = m.defaultId.fold(ctx.abilities)(id =>
ctx.abilities.updated(m.name, fromServiceModel(m, id))
),
services = ctx.services.updated(m.name, m)
abilities =
m.defaultId.fold(Map.empty)(id => Map(m.name -> fromServiceModel(m, id))),
services = Map(m.name -> m)
)
(ctx |+| add, exportContext |+| add)
case (ce, _) => ce

View File

@ -40,7 +40,7 @@ object ModuleExpr extends HeaderExpr.Leaf {
nameOrAbList[F].map(Left(_)) | `star`.lift.map(Token.lift(_)).map(Right(_))
override def p[F[_]: LiftParser: Comonad]: Parser[ModuleExpr[F]] =
(`module` *> ` ` *> Ability.ab[F] ~
(`module` *> ` ` *> Ability.dotted[F] ~
(` declares ` *> nameOrAbListOrAll[F]).?).map {
case (name, None) =>
ModuleExpr(name, None, Nil, Nil)

View File

@ -13,11 +13,16 @@ import cats.syntax.semigroup.*
import cats.instances.list.*
import cats.instances.option.*
import cats.free.Cofree
import cats.kernel.Semigroup
case class HeaderSem[S[_]](
initCtx: AquaContext,
finCtx: AquaContext => ValidatedNec[SemanticError[S], AquaContext]
)
finInitCtx: (AquaContext, AquaContext) => ValidatedNec[SemanticError[S], AquaContext]
) {
def finCtx: AquaContext => ValidatedNec[SemanticError[S], AquaContext] =
finInitCtx(_, initCtx)
}
object HeaderSem {
type Res[S[_]] = ValidatedNec[SemanticError[S], HeaderSem[S]]
@ -27,12 +32,12 @@ object HeaderSem {
acm: Monoid[AquaContext]
): Monoid[HeaderSem[S]] =
new Monoid[HeaderSem[S]] {
override def empty: HeaderSem[S] = HeaderSem(acm.empty, validNec(_))
override def empty: HeaderSem[S] = HeaderSem(acm.empty, (c, _) => validNec(c))
override def combine(a: HeaderSem[S], b: HeaderSem[S]): HeaderSem[S] =
HeaderSem(
a.initCtx |+| b.initCtx,
a.finCtx.andThen(_.andThen(b.finCtx))
(c, i) => a.finInitCtx(c, i).andThen(b.finInitCtx(_, i))
)
}
@ -69,7 +74,7 @@ object HeaderSem {
.getOrElse(
error(
n,
s"Imported file declares [${ctx.declares.mkString(", ")}], no ${n.value} declared. Try adding `declares *` to that file."
s"Imported file `declares ${ctx.declares.mkString(", ")}`, no ${n.value} declared. Try adding `declares ${n.value}` to that file."
)
)
},
@ -80,7 +85,7 @@ object HeaderSem {
.getOrElse(
error(
n,
s"Imported file declares [${ctx.declares.mkString(", ")}], no ${n.value} declared. Try adding `declares *` to that file."
s"Imported file `declares ${ctx.declares.mkString(", ")}`, no ${n.value} declared. Try adding `declares ${n.value}` to that file."
)
)
}
@ -112,7 +117,7 @@ object HeaderSem {
module = Some(name.value),
declares = shouldDeclare
),
ctx =>
(ctx, _) =>
// When file is handled, check that all the declarations exists
if (declareAll.nonEmpty)
validNec(
@ -144,25 +149,25 @@ object HeaderSem {
case f @ ImportExpr(_) =>
// Import everything from a file
resolve(f).map(fc => HeaderSem[S](fc, validNec(_)))
resolve(f).map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
case f @ ImportFromExpr(_, _) =>
// Import, map declarations
resolve(f)
.andThen(getFrom(f, _))
.map(ctx => HeaderSem[S](ctx, validNec(_)))
.map(ctx => HeaderSem[S](ctx, (c, _) => validNec(c)))
case f @ UseExpr(_, asModule) =>
// Import, move into a module scope
resolve(f)
.andThen(toModule(_, f.token, asModule))
.map(fc => HeaderSem[S](fc, validNec(_)))
.map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
case f @ UseFromExpr(_, _, asModule) =>
// Import, cherry-pick declarations, move to a module scope
resolve(f)
.andThen(getFrom(f, _))
.andThen(toModule(_, f.token, Some(asModule)))
.map(fc => HeaderSem[S](fc, validNec(_)))
.map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
case ExportExpr(pubs) =>
// Save exports, finally handle them
@ -170,12 +175,12 @@ object HeaderSem {
HeaderSem[S](
// Nothing there
acm.empty,
ctx =>
(ctx, initCtx) =>
pubs
.map(
_.fold(
{ case (n, rn) =>
ctx
(initCtx |+| ctx)
.pick(n.value, rn.map(_.value), declared = false)
.map(validNec)
.getOrElse(
@ -183,7 +188,7 @@ object HeaderSem {
)
},
{ case (n, rn) =>
ctx
(initCtx |+| ctx)
.pick(n.value, rn.map(_.value), declared = false)
.map(validNec)
.getOrElse(
@ -198,11 +203,11 @@ object HeaderSem {
)
case HeadExpr(token) =>
// Old file exports everything
validNec(HeaderSem[S](acm.empty, ctx => validNec(ctx.copy(exports = Some(ctx)))))
// Old file exports everything that it declares
validNec(HeaderSem[S](acm.empty, (ctx, _) => validNec(ctx.copy(exports = Some(ctx)))))
case f: FilenameExpr[S] =>
resolve(f).map(fc => HeaderSem[S](fc, validNec(_)))
resolve(f).map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
}
Cofree

View File

@ -62,7 +62,7 @@ class AbilitiesInterpreter[F[_], X](implicit
s"Ability is found, but arrow is undefined, available: ${abCtx.funcs.keys.toList
.mkString(", ")}"
).as(Option.empty[ArrowType])
)(a => State.pure(Some(a)))
)(fn => State.pure(Some(fn.arrowType)))
case None =>
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType])
}

View File

@ -199,7 +199,9 @@ case class ArrowType(domain: ProductType, codomain: ProductType) extends Type {
s"$domain -> $codomain"
}
case class StreamType(element: Type) extends BoxType
case class StreamType(element: Type) extends BoxType {
override def toString: String = s"*$element"
}
object Type {