Skip to content

Commit

Permalink
Imports/exports fixes (#258)
Browse files Browse the repository at this point in the history
* Fix for export in headerless file

* Ability arrow resolution bugfix

* Trying to reproduce a bug

* Allow dots in module declaration
  • Loading branch information
alari authored Aug 31, 2021
1 parent bc46145 commit 3e7b11d
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 37 deletions.
16 changes: 16 additions & 0 deletions aqua-src/export.aqua
Original file line number Diff line number Diff line change
@@ -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()
3 changes: 3 additions & 0 deletions aqua-src/gen/OneMore.aqua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
service OneMore:
more_call()
consume(s: string)
23 changes: 23 additions & 0 deletions aqua-src/import.aqua
Original file line number Diff line number Diff line change
@@ -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
6 changes: 3 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -85,8 +85,8 @@ lazy val parser = crossProject(JVMPlatform, JSPlatform)
.settings(commons: _*)
.settings(
libraryDependencies ++= Seq(
"org.typelevel" %%% "cats-parse" % catsParseV,
"org.typelevel" %%% "cats-free" % catsV
"org.typelevel" %%% "cats-parse" % catsParseV,
"org.typelevel" %%% "cats-free" % catsV
)
)
.dependsOn(types)
Expand Down
26 changes: 12 additions & 14 deletions model/src/main/scala/aqua/model/AquaContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion parser/src/main/scala/aqua/parser/head/ModuleExpr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
39 changes: 22 additions & 17 deletions semantics/src/main/scala/aqua/semantics/header/HeaderSem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand All @@ -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))
)
}

Expand Down Expand Up @@ -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."
)
)
},
Expand All @@ -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."
)
)
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -144,46 +149,46 @@ 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
validNec(
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(
error(n, s"File has no ${n.value} declaration or import, cannot export")
)
},
{ case (n, rn) =>
ctx
(initCtx |+| ctx)
.pick(n.value, rn.map(_.value), declared = false)
.map(validNec)
.getOrElse(
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
Expand Down
4 changes: 3 additions & 1 deletion types/src/main/scala/aqua/types/Type.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down

0 comments on commit 3e7b11d

Please sign in to comment.