Module and Use expressions (#245)

* Module and Use expressions

* UseFromExpr

* ImportFromExpr

* PubExpr

* Export, declares

* Collecting all the needed info WIP

* Got all the needed data

* Tests fixed

* HeaderSem

* HeaderSem wip

* Everything except `export`/`declares` should be working

* Compile bug fixed

* Fix readme: cli/assembly

* Handle declares, exports

* Compile only exports in AquaRes

* Call services imported from modules

* Import consts, types, services from modules

* Resolve arrows from modules

* Bugfix
This commit is contained in:
Dmitry Kurinskiy
2021-08-20 18:03:47 +03:00
committed by GitHub
parent 296c64836d
commit b9af20339b
44 changed files with 728 additions and 163 deletions

View File

@ -1,8 +1,10 @@
package aqua.linker
case class AquaModule[I, E, T](id: I, dependsOn: Map[I, E], body: T) {
case class AquaModule[I, E, T](id: I, imports: Map[String, I], dependsOn: Map[I, E], body: T) {
def map[TT](f: T => TT): AquaModule[I, E, TT] = copy(body = f(body))
def mapWithId[TT](f: (I, T) => TT): AquaModule[I, E, TT] = copy(body = f(id, body))
def mapErr[EE](f: E => EE): AquaModule[I, EE, T] =
copy(dependsOn = dependsOn.view.mapValues(f).toMap)
}

View File

@ -2,7 +2,7 @@ package aqua.linker
import cats.data.{NonEmptyChain, Validated, ValidatedNec}
import cats.kernel.{Monoid, Semigroup}
import cats.syntax.monoid._
import cats.syntax.semigroup._
import scribe.Logging
import scala.annotation.tailrec
@ -50,9 +50,10 @@ object Linker extends Logging {
}
}
def link[I, E, T: Monoid](
def link[I, E, T: Semigroup](
modules: Modules[I, E, T => T],
cycleError: List[AquaModule[I, E, T => T]] => E
cycleError: List[AquaModule[I, E, T => T]] => E,
empty: I => T
): ValidatedNec[E, Map[I, T]] =
if (modules.dependsOn.nonEmpty) Validated.invalid(modules.dependsOn.values.reduce(_ ++ _))
else {
@ -60,7 +61,7 @@ object Linker extends Logging {
Validated.fromEither(
result
.map(_.view.filterKeys(modules.exports).mapValues(_.apply(Monoid[T].empty)).toMap)
.map(_.collect { case (i, f) if modules.exports(i) => i -> f(empty(i)) })
.left
.map(NonEmptyChain.one)
)

View File

@ -28,6 +28,9 @@ case class Modules[I, E, T](
def map[TT](f: T => TT): Modules[I, E, TT] =
copy(loaded = loaded.view.mapValues(_.map(f)).toMap)
def mapModuleToBody[TT](f: AquaModule[I, E, T] => TT): Modules[I, E, TT] =
copy(loaded = loaded.view.mapValues(v => v.map(_ => f(v))).toMap)
def mapErr[EE](f: E => EE): Modules[I, EE, T] =
copy(
loaded = loaded.view.mapValues(_.mapErr(f)).toMap,

View File

@ -15,6 +15,7 @@ class LinkerSpec extends AnyFlatSpec with Matchers {
.add(
AquaModule[String, String, String => String](
"mod1",
Map.empty,
Map("mod2" -> "unresolved mod2 in mod1"),
_ ++ " | mod1"
),
@ -24,17 +25,19 @@ class LinkerSpec extends AnyFlatSpec with Matchers {
Linker.link[String, String, String](
withMod1,
cycle => cycle.map(_.id).mkString(" -> ")
cycle => cycle.map(_.id).mkString(" -> "),
_ => ""
) should be(Validated.invalidNec("unresolved mod2 in mod1"))
val withMod2 =
withMod1.add(AquaModule("mod2", Map.empty, _ ++ " | mod2"))
withMod1.add(AquaModule("mod2", Map.empty, Map.empty, _ ++ " | mod2"))
withMod2.isResolved should be(true)
Linker.link[String, String, String](
withMod2,
cycle => cycle.map(_.id + "?").mkString(" -> ")
cycle => cycle.map(_.id + "?").mkString(" -> "),
_ => ""
) should be(Validated.validNec(Map("mod1" -> " | mod2 | mod1")))
}