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" name := "aqua-hll"
val commons = Seq( val commons = Seq(
baseAquaVersion := "0.2.0", baseAquaVersion := "0.2.1",
version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"), version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"),
scalaVersion := dottyVersion, scalaVersion := dottyVersion,
libraryDependencies ++= Seq( libraryDependencies ++= Seq(

View File

@ -5,6 +5,7 @@ import aqua.model.func.{ArgsCall, FuncCallable, FuncModel}
import aqua.types.{StructType, Type} import aqua.types.{StructType, Type}
import cats.Monoid import cats.Monoid
import cats.data.NonEmptyMap import cats.data.NonEmptyMap
import cats.kernel.Semigroup
import cats.syntax.functor.* import cats.syntax.functor.*
import cats.syntax.monoid.* import cats.syntax.monoid.*
import scribe.Logging import scribe.Logging
@ -150,37 +151,34 @@ object AquaContext extends Logging {
) )
def fromScriptModel(sm: ScriptModel, init: AquaContext)(implicit def fromScriptModel(sm: ScriptModel, init: AquaContext)(implicit
aqum: Monoid[AquaContext] aqum: Semigroup[AquaContext]
): AquaContext = ): AquaContext =
sm.models sm.models
.foldLeft((init, Monoid.empty[AquaContext])) { .foldLeft((init, blank)) {
case ((ctx, exportContext), c: ConstantModel) => case ((ctx, exportContext), c: ConstantModel) =>
val add = val add =
Monoid blank
.empty[AquaContext]
.copy(values = .copy(values =
if (c.allowOverrides && ctx.values.contains(c.name)) ctx.values if (c.allowOverrides && ctx.values.contains(c.name)) Map.empty
else ctx.values.updated(c.name, c.value.resolveWith(ctx.values)) else Map(c.name -> c.value.resolveWith(ctx.values))
) )
(ctx |+| add, exportContext |+| add) (ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), func: FuncModel) => case ((ctx, exportContext), func: FuncModel) =>
val fr = func.capture(ctx.allFuncs(), ctx.allValues()) val fr = func.capture(ctx.allFuncs(), ctx.allValues())
val add = val add =
Monoid.empty[AquaContext].copy(funcs = ctx.funcs.updated(func.name, fr)) blank.copy(funcs = Map(func.name -> fr))
(ctx |+| add, exportContext |+| add) (ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), t: TypeModel) => case ((ctx, exportContext), t: TypeModel) =>
val add = 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) (ctx |+| add, exportContext |+| add)
case ((ctx, exportContext), m: ServiceModel) => case ((ctx, exportContext), m: ServiceModel) =>
val add = val add =
Monoid blank
.empty[AquaContext]
.copy( .copy(
abilities = m.defaultId.fold(ctx.abilities)(id => abilities =
ctx.abilities.updated(m.name, fromServiceModel(m, id)) m.defaultId.fold(Map.empty)(id => Map(m.name -> fromServiceModel(m, id))),
), services = Map(m.name -> m)
services = ctx.services.updated(m.name, m)
) )
(ctx |+| add, exportContext |+| add) (ctx |+| add, exportContext |+| add)
case (ce, _) => ce 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(_)) nameOrAbList[F].map(Left(_)) | `star`.lift.map(Token.lift(_)).map(Right(_))
override def p[F[_]: LiftParser: Comonad]: Parser[ModuleExpr[F]] = override def p[F[_]: LiftParser: Comonad]: Parser[ModuleExpr[F]] =
(`module` *> ` ` *> Ability.ab[F] ~ (`module` *> ` ` *> Ability.dotted[F] ~
(` declares ` *> nameOrAbListOrAll[F]).?).map { (` declares ` *> nameOrAbListOrAll[F]).?).map {
case (name, None) => case (name, None) =>
ModuleExpr(name, None, Nil, Nil) ModuleExpr(name, None, Nil, Nil)

View File

@ -13,11 +13,16 @@ import cats.syntax.semigroup.*
import cats.instances.list.* import cats.instances.list.*
import cats.instances.option.* import cats.instances.option.*
import cats.free.Cofree import cats.free.Cofree
import cats.kernel.Semigroup
case class HeaderSem[S[_]]( case class HeaderSem[S[_]](
initCtx: AquaContext, 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 { object HeaderSem {
type Res[S[_]] = ValidatedNec[SemanticError[S], HeaderSem[S]] type Res[S[_]] = ValidatedNec[SemanticError[S], HeaderSem[S]]
@ -27,12 +32,12 @@ object HeaderSem {
acm: Monoid[AquaContext] acm: Monoid[AquaContext]
): Monoid[HeaderSem[S]] = ): Monoid[HeaderSem[S]] =
new 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] = override def combine(a: HeaderSem[S], b: HeaderSem[S]): HeaderSem[S] =
HeaderSem( HeaderSem(
a.initCtx |+| b.initCtx, 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( .getOrElse(
error( error(
n, 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( .getOrElse(
error( error(
n, 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), module = Some(name.value),
declares = shouldDeclare declares = shouldDeclare
), ),
ctx => (ctx, _) =>
// When file is handled, check that all the declarations exists // When file is handled, check that all the declarations exists
if (declareAll.nonEmpty) if (declareAll.nonEmpty)
validNec( validNec(
@ -144,25 +149,25 @@ object HeaderSem {
case f @ ImportExpr(_) => case f @ ImportExpr(_) =>
// Import everything from a file // 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(_, _) => case f @ ImportFromExpr(_, _) =>
// Import, map declarations // Import, map declarations
resolve(f) resolve(f)
.andThen(getFrom(f, _)) .andThen(getFrom(f, _))
.map(ctx => HeaderSem[S](ctx, validNec(_))) .map(ctx => HeaderSem[S](ctx, (c, _) => validNec(c)))
case f @ UseExpr(_, asModule) => case f @ UseExpr(_, asModule) =>
// Import, move into a module scope // Import, move into a module scope
resolve(f) resolve(f)
.andThen(toModule(_, f.token, asModule)) .andThen(toModule(_, f.token, asModule))
.map(fc => HeaderSem[S](fc, validNec(_))) .map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
case f @ UseFromExpr(_, _, asModule) => case f @ UseFromExpr(_, _, asModule) =>
// Import, cherry-pick declarations, move to a module scope // Import, cherry-pick declarations, move to a module scope
resolve(f) resolve(f)
.andThen(getFrom(f, _)) .andThen(getFrom(f, _))
.andThen(toModule(_, f.token, Some(asModule))) .andThen(toModule(_, f.token, Some(asModule)))
.map(fc => HeaderSem[S](fc, validNec(_))) .map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
case ExportExpr(pubs) => case ExportExpr(pubs) =>
// Save exports, finally handle them // Save exports, finally handle them
@ -170,12 +175,12 @@ object HeaderSem {
HeaderSem[S]( HeaderSem[S](
// Nothing there // Nothing there
acm.empty, acm.empty,
ctx => (ctx, initCtx) =>
pubs pubs
.map( .map(
_.fold( _.fold(
{ case (n, rn) => { case (n, rn) =>
ctx (initCtx |+| ctx)
.pick(n.value, rn.map(_.value), declared = false) .pick(n.value, rn.map(_.value), declared = false)
.map(validNec) .map(validNec)
.getOrElse( .getOrElse(
@ -183,7 +188,7 @@ object HeaderSem {
) )
}, },
{ case (n, rn) => { case (n, rn) =>
ctx (initCtx |+| ctx)
.pick(n.value, rn.map(_.value), declared = false) .pick(n.value, rn.map(_.value), declared = false)
.map(validNec) .map(validNec)
.getOrElse( .getOrElse(
@ -198,11 +203,11 @@ object HeaderSem {
) )
case HeadExpr(token) => case HeadExpr(token) =>
// Old file exports everything // Old file exports everything that it declares
validNec(HeaderSem[S](acm.empty, ctx => validNec(ctx.copy(exports = Some(ctx))))) validNec(HeaderSem[S](acm.empty, (ctx, _) => validNec(ctx.copy(exports = Some(ctx)))))
case f: FilenameExpr[S] => case f: FilenameExpr[S] =>
resolve(f).map(fc => HeaderSem[S](fc, validNec(_))) resolve(f).map(fc => HeaderSem[S](fc, (c, _) => validNec(c)))
} }
Cofree 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 s"Ability is found, but arrow is undefined, available: ${abCtx.funcs.keys.toList
.mkString(", ")}" .mkString(", ")}"
).as(Option.empty[ArrowType]) ).as(Option.empty[ArrowType])
)(a => State.pure(Some(a))) )(fn => State.pure(Some(fn.arrowType)))
case None => case None =>
report(ga.name, "Ability with this name is undefined").as(Option.empty[ArrowType]) 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" 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 { object Type {