Skip to content

Commit

Permalink
refactor Package and PackageMap some (#1318)
Browse files Browse the repository at this point in the history
* refactor Package and PackageMap some

* simplify

* move more code to Package

* fix typo in name
  • Loading branch information
johnynek authored Dec 14, 2024
1 parent 9a291e4 commit 48f0f59
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 90 deletions.
84 changes: 82 additions & 2 deletions core/src/main/scala/org/bykn/bosatsu/Package.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.bykn.bosatsu

import cats.{Functor, Order, Parallel}
import cats.{Functor, Order, Parallel, Applicative}
import cats.data.{Ior, ValidatedNel, Validated, NonEmptyList}
import cats.implicits._
import cats.syntax.all._
import cats.parse.{Parser0 => P0, Parser => P}
import org.typelevel.paiges.{Doc, Document}
import scala.util.hashing.MurmurHash3
Expand Down Expand Up @@ -49,6 +49,11 @@ final case class Package[A, B, C, +D](
newImports: List[Import[A1, B1]]
): Package[A1, B1, C, D] =
Package(name, newImports, exports, program)

def getExport[T](i: ImportedName[T]): Option[NonEmptyList[ExportedName[C]]] = {
val iname = i.originalName
NonEmptyList.fromList(exports.filter(_.name == iname))
}
}

object Package {
Expand All @@ -64,6 +69,9 @@ object Package {
type Parsed = Package[PackageName, Unit, Unit, List[Statement]]
type Resolved =
FixPackage[Unit, Unit, (List[Statement], ImportMap[PackageName, Unit])]
type ResolvedPackage =
Package[Resolved, Unit, Unit, (List[Statement], ImportMap[PackageName, Unit])]

type TypedProgram[T] = (
Program[TypeEnv[Kind.Arg], TypedExpr[T], Any],
ImportMap[Interface, NonEmptyList[Referant[Kind.Arg]]]
Expand Down Expand Up @@ -535,6 +543,78 @@ object Package {
val prog1 = prog.copy(lets = prog.lets.filter { case (b, _, _) => fn(b) })
pack.copy(program = (prog1, importMap))
}

def getImport[B](
inside: PackageName,
i: ImportedName[B]
): Either[PackageError, ImportedName[NonEmptyList[Referant[Kind.Arg]]]] = {
pack.getExport(i) match {
case Some(exps) =>
val bs = exps.map(_.tag)
Right(i.map(_ => bs))
case None =>
Left(
PackageError.UnknownImportName(
inside,
pack.name,
pack.program._1.lets.iterator.map { case (n, _, _) =>
(n: Identifier, ())
}.toMap,
i,
pack.exports
)
)
}
}
}

implicit class IfaceMethods(private val iface: Interface) extends AnyVal {
def getImportIface[A](
inside: PackageName,
i: ImportedName[A]
): Either[PackageError, ImportedName[NonEmptyList[Referant[Kind.Arg]]]] = {
iface.getExport(i) match {
case Some(exps) =>
val bs = exps.map(_.tag)
Right(i.map(_ => bs))
case None =>
Left(
PackageError.UnknownImportFromInterface(
inside,
iface.name,
iface.exports.map(_.name),
i,
iface.exports
)
)
}
}
}

implicit class ResolvedMethods(private val resolved: Resolved) extends AnyVal {
def importName[F[_], A](
fromPackage: PackageName,
item: ImportedName[Unit]
)(recurse: ResolvedPackage => F[Typed[A]])(implicit F: Applicative[F]): F[Either[PackageError, (Package.Interface, ImportedName[NonEmptyList[Referant[Kind.Arg]]])]] =
Package.unfix(resolved) match {
case Right(p) =>
/*
* Here we have a source we need to fully resolve
*/
recurse(p)
.map { packF =>
val packInterface = Package.interfaceOf(packF)
packF.getImport(fromPackage, item)
.map((packInterface, _))
}
case Left(iface) =>
/*
* this import is already an interface, we can stop here
*/
// this is very fast and does not need to be done in a thread
F.pure(iface.getImportIface(fromPackage, item)
.map((iface, _)))
}
}

def orderByName[A, B, C, D]: Order[Package[A, B, C, D]] =
Expand Down
106 changes: 18 additions & 88 deletions core/src/main/scala/org/bykn/bosatsu/PackageMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ object PackageMap {

type Inferred = Typed[Declaration]

/** This builds a DAG of actual packages where names have been replaced by the
* fully resolved packages
/** This builds a DAG of actual packages where on Import the PackageName have been replaced by the
* Either a Package.Interface (which gives exports only) or this same recursive structure.
*/
def resolvePackages[A, B, C](
map: PackageMap[PackageName, A, B, C],
Expand Down Expand Up @@ -328,7 +328,7 @@ object PackageMap {

// we know all the package names are unique here
def foldMap(
m: Map[PackageName, (A, Package.Parsed)]
m: SortedMap[PackageName, (A, Package.Parsed)]
): (List[PackageError], PackageMap.ParsedImp) = {
val initPm = PackageMap
.empty[
Expand All @@ -338,7 +338,8 @@ object PackageMap {
(List[Statement], ImportMap[PackageName, Unit])
]

m.iterator.foldLeft((List.empty[PackageError], initPm)) {
// since the map is sorted, this order is deteriministic
m.foldLeft((List.empty[PackageError], initPm)) {
case ((errs, pm), (_, (_, pack))) =>
val (lerrs, pp) = toProg(pack)
(lerrs.toList ::: errs, pm + pp)
Expand All @@ -350,14 +351,14 @@ object PackageMap {
// combine the import errors now:
val check: Ior[NonEmptyList[PackageError], Unit] =
errs match {
case Nil =>
Ior.right(())
case Nil => Ior.right(())
case h :: tail =>
Ior.left(NonEmptyList(h, tail))
}
// keep all the errors
val nuEr: Ior[NonEmptyList[PackageError], Unit] =
NonEmptyMap.fromMap(nonUnique) match {
case None => Ior.right(())
case Some(nenu) =>
val paths = nenu.map { case ((a, _), rest) =>
(a.show, rest.map(_._1.show))
Expand All @@ -367,8 +368,6 @@ object PackageMap {
PackageError.DuplicatedPackageError(paths)
)
)
case None =>
Ior.right(())
}

(nuEr, check, res.toIor).parMapN((_, _, r) => r)
Expand Down Expand Up @@ -418,96 +417,27 @@ object PackageMap {
(nameToRes(p), i)
}

def getImport[A, B](
packF: Package.Inferred,
exMap: Map[Identifier, NonEmptyList[ExportedName[A]]],
i: ImportedName[B]
): Ior[NonEmptyList[PackageError], ImportedName[NonEmptyList[A]]] =
exMap.get(i.originalName) match {
case None =>
Ior.left(
NonEmptyList.one(
PackageError.UnknownImportName(
nm,
packF.name,
packF.program._1.lets.iterator.map { case (n, _, _) =>
(n: Identifier, ())
}.toMap,
i,
exMap.iterator.flatMap(_._2.toList).toList
)
)
)
case Some(exps) =>
val bs = exps.map(_.tag)
Ior.right(i.map(_ => bs))
}

def getImportIface[A, B](
packF: Package.Interface,
exMap: Map[Identifier, NonEmptyList[ExportedName[A]]],
i: ImportedName[B]
): Ior[NonEmptyList[PackageError], ImportedName[NonEmptyList[A]]] =
exMap.get(i.originalName) match {
case None =>
Ior.left(
NonEmptyList.one(
PackageError.UnknownImportFromInterface(
nm,
packF.name,
packF.exports.map(_.name),
i,
exMap.iterator.flatMap(_._2.toList).toList
)
)
)
case Some(exps) =>
val bs = exps.map(_.tag)
Ior.right(i.map(_ => bs))
}

/*
* This resolves imports from PackageNames into fully typed Packages
*
* Note the names are not unique after this step because an imported
* type can have the same name as a constructor. After this step, each
* distinct object has its own entry in the list
*/
type IName = NonEmptyList[Referant[Kind.Arg]]

def stepImport(
fixpack: Package.Resolved,
item: ImportedName[Unit]
): FutVal[(Package.Interface, ImportedName[IName])] =
Package.unfix(fixpack) match {
case Right(p) =>
/*
* Here we have a source we need to fully resolve
*/
IorT(recurse(p))
.flatMap { case (_, packF) =>
val packInterface = Package.interfaceOf(packF)
val exMap = packF.exports.groupByNel(_.name)
val ior = getImport(packF, exMap, item)
.map((packInterface, _))
IorT.fromIor(ior)
}
case Left(iface) =>
/*
* this import is already an interface, we can stop here
*/
val exMap = iface.exports.groupByNel(_.name)
// this is very fast and does not need to be done in a thread
val ior =
getImportIface(iface, exMap, item)
.map((iface, _))
IorT.fromIor(ior)
}

val inferImports: FutVal[
ImportMap[Package.Interface, NonEmptyList[Referant[Kind.Arg]]]
] =
resolvedImports.parTraverse(stepImport(_, _))
] = {
// here we just need the interface, not the TypeEnv
val rec1 = recurse.andThen { res => IorT(res).map(_._2) }

resolvedImports.parTraverse { (fixpack: Package.Resolved, item: ImportedName[Unit]) =>
fixpack.importName(nm, item)(rec1(_))
.flatMap { either =>
IorT.fromEither(either.left.map(NonEmptyList.one(_)))
}
}
}

val inferBody =
inferImports
Expand Down

0 comments on commit 48f0f59

Please sign in to comment.