Skip to content

Commit

Permalink
Add Proto version of package interfaces (#252)
Browse files Browse the repository at this point in the history
* Add Proto version of package interfaces

* Test interface parsing

* fix generation bugs, plumb support to Main, but not PackageMap

* fix bazel build
  • Loading branch information
johnynek authored May 16, 2019
1 parent 43e0adb commit 14ae6fc
Show file tree
Hide file tree
Showing 15 changed files with 551 additions and 112 deletions.
62 changes: 62 additions & 0 deletions cli/src/main/protobuf/bosatsu/TypedAst.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,65 @@ message Type {
}
}

enum Variance {
Phantom = 0;
Covariant = 1;
Contravariant = 2;
Invariant = 3;
}

message TypeParam {
TypeVar typeVar = 1;
Variance variance = 2;
}

message FnParam {
string name = 1;
Type typeOf = 2;
}

message ConstructorFn {
string name = 1;
repeated FnParam params = 2;
}

message DefinedType {
TypeConst typeConst = 1;
repeated TypeParam typeParams = 2;
repeated ConstructorFn constructors = 3;
}

message ConstructorPtr {
int32 definedTypePtr = 1; /* 1-based pointer into the list of types */
int32 constructorPtr = 2; /* 1-based pointer into the list of constructors for this type */
}

message Referant {
oneof referant {
Type value = 1; /* an exported value which has a given type */
int32 definedTypePtr = 2; /* 1-based pointer into the list of types */
ConstructorPtr constructor = 3; /* an exported constructor */
}
}

message ExportedName {
oneof kind {
string binding = 1;
string typeName = 2;
string constructorName = 3;
}
Referant referant = 4;
}

/*
* This is an interface of a package: all public types, and the type of all exported values
*/
message Interface {
string packageName = 1;
repeated DefinedType definedTypes = 2;
repeated ExportedName exports = 3;
}

message Interfaces {
repeated Interface interfaces = 1;
}
5 changes: 4 additions & 1 deletion cli/src/main/scala/org/bykn/bosatsu/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ scala_library(
scala_binary(
name = "bosatsu_main",
srcs = ["Main.scala"],
deps = [":bosatsu"] + common_deps,
deps = [
":bosatsu",
"//cli/src/main/protobuf/bosatsu",
] + common_deps,
runtime_deps = [],
main_class = "org.bykn.bosatsu.Main",
scalacopts = strict_scalacopts(),
Expand Down
41 changes: 28 additions & 13 deletions cli/src/main/scala/org/bykn/bosatsu/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,14 @@ object MainCommand {
case Failure(err) => Validated.invalidNel(ParseError.FileError(path, err))
}

def typeCheck(inputs: NonEmptyList[Path]): MainResult[(PackageMap.Inferred, List[(Path, PackageName)])] = {
def typeCheck(inputs: NonEmptyList[Path], ifacePaths: List[Path]): MainResult[(PackageMap.Inferred, List[(Path, PackageName)])] = {
val ins = parseInputs(inputs)

val ifaces = MainResult.fromTry(ifacePaths.traverse(ProtoConverter.readInterfaces(_)).map(_.flatten))

toResult(ins)
.flatMap { packs =>
.flatMap { p => ifaces.map((p, _)) }
.flatMap { case (packs, ifs) =>
val pathToName: List[(Path, PackageName)] = packs.map { case ((path, _), p) => (path, p.name) }.toList
val (dups, resPacks) = PackageMap.resolveThenInfer(Predef.withPredefA(("predef", LocationMap("")), packs.toList))
val checkD = checkDuplicatePackages(dups)(_._1.toString)
Expand All @@ -137,7 +140,7 @@ object MainCommand {

case class Evaluate(inputs: NonEmptyList[Path], mainPackage: PackageName) extends MainCommand {
def run() =
typeCheck(inputs).flatMap { case (packs, _) =>
typeCheck(inputs, Nil).flatMap { case (packs, _) =>
val ev = Evaluation(packs, Predef.jvmExternals)
ev.evaluateLast(mainPackage) match {
case None => MainResult.Error(1, List("found no main expression"))
Expand All @@ -147,9 +150,9 @@ object MainCommand {
}
}
}
case class ToJson(inputs: NonEmptyList[Path], signatures: List[Path], mainPackage: PackageName, output: Path) extends MainCommand {
case class ToJson(inputs: NonEmptyList[Path], ifaces: List[Path], mainPackage: PackageName, output: Path) extends MainCommand {
def run() =
typeCheck(inputs).flatMap { case (packs, _) =>
typeCheck(inputs, Nil).flatMap { case (packs, _) =>
val ev = Evaluation(packs, Predef.jvmExternals)
ev.evaluateLast(mainPackage) match {
case None => MainResult.Error(1, List("found no main expression"))
Expand All @@ -165,16 +168,27 @@ object MainCommand {
}
}
}
case class TypeCheck(inputs: NonEmptyList[Path], signatures: List[Path], output: Path) extends MainCommand {
case class TypeCheck(inputs: NonEmptyList[Path], ifaces: List[Path], output: Path, ifout: Option[Path]) extends MainCommand {
def run() =
typeCheck(inputs).flatMap { case (packs, _) =>
MainResult.fromTry(CodeGenWrite.writeDoc(output, Doc.text(s"checked ${packs.toMap.size} packages")))
typeCheck(inputs, ifaces).flatMap { case (packs, _) =>
val ifres = ifout match {
case None =>
MainResult.Success(())
case Some(p) =>
val ifs = packs.toMap.iterator.map { case (_, p) => Package.interfaceOf(p) }.toList
MainResult.fromTry(ProtoConverter.writeInterfaces(ifs, p))
}

def out = MainResult
.fromTry(CodeGenWrite.writeDoc(output, Doc.text(s"checked ${packs.toMap.size} packages")))
.map(_ => Nil)

ifres.flatMap(_ => out)
}
}
case class Compile(inputs: NonEmptyList[Path], compileRoot: Path) extends MainCommand {
def run() =
typeCheck(inputs).flatMap { case (packs, _) =>
typeCheck(inputs, Nil).flatMap { case (packs, _) =>
MainResult.fromTry(CodeGenWrite.write(compileRoot, packs, Predef.jvmExternals))
.map { _ => List(s"wrote ${packs.toMap.size} packages") }
}
Expand All @@ -188,7 +202,7 @@ object MainCommand {
case Some(ne) => MainResult.Success(ne)
}

files.flatMap(typeCheck(_)).flatMap { case (packs, nameMap) =>
files.flatMap(typeCheck(_, Nil)).flatMap { case (packs, nameMap) =>
val testSet = tests.toList.toSet
val testPackages: List[PackageName] =
(nameMap.iterator.collect { case (p, name) if testSet(p) => name } ++
Expand Down Expand Up @@ -281,16 +295,17 @@ object MainCommand {

val ins = Opts.options[Path]("input", help = "input files")
val deps = toList(Opts.options[Path]("test_deps", help = "test dependencies"))
val sigs = toList(Opts.options[Path]("signature", help = "signature files"))
val ifaces = toList(Opts.options[Path]("interface", help = "interface files"))

val mainP = Opts.option[PackageName]("main", help = "main package to evaluate")
val testP = toList(Opts.options[PackageName]("test_package", help = "package for which to run tests"))
val outputPath = Opts.option[Path]("output", help = "output path")
val interfaceOutputPath = Opts.option[Path]("interface_out", help = "interface output path")
val compileRoot = Opts.option[Path]("compile_root", help = "root directory to write java output")

val evalOpt = (ins, mainP).mapN(Evaluate(_, _))
val toJsonOpt = (ins, sigs, mainP, outputPath).mapN(ToJson(_, _, _, _))
val typeCheckOpt = (ins, sigs, outputPath).mapN(TypeCheck(_, _, _))
val toJsonOpt = (ins, ifaces, mainP, outputPath).mapN(ToJson(_, _, _, _))
val typeCheckOpt = (ins, ifaces, outputPath, interfaceOutputPath.orNone).mapN(TypeCheck(_, _, _, _))
val compileOpt = (ins, compileRoot).mapN(Compile(_, _))
val testOpt = (toList(ins), testP, deps).mapN(RunTests(_, _, _))

Expand Down
Loading

0 comments on commit 14ae6fc

Please sign in to comment.