Skip to content

Commit

Permalink
Make bosatsu.tool package, move some items from MainModule (#1321)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnynek authored Dec 16, 2024
1 parent 2a61c63 commit e167129
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 100 deletions.
13 changes: 6 additions & 7 deletions cli/src/main/scala/org/bykn/bosatsu/PathModule.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.bykn.bosatsu

import cats.effect.{IO, Resource}
import org.typelevel.paiges.{Doc, Document}

import java.nio.file.{Path => JPath}

import cats.data.NonEmptyList
import cats.effect.ExitCode
import cats.effect.{IO, Resource}
import java.nio.file.{Path => JPath}
import org.typelevel.paiges.{Doc, Document}
import org.bykn.bosatsu.tool.{FileKind, GraphOutput, Output}

import cats.implicits.catsKernelOrderingForOrder
import cats.syntax.all._
Expand All @@ -24,7 +23,7 @@ object PathModule extends MainModule[IO, JPath](IOPlatformIO) { self =>
def withEC[A](fn: Par.EC => IO[A]): IO[A] =
parResource.use(fn)

def report(io: IO[Output]): IO[ExitCode] =
def report(io: IO[Output[JPath]]): IO[ExitCode] =
io.attempt.flatMap {
case Right(out) => reportOutput(out)
case Left(err) => reportException(err).as(ExitCode.Error)
Expand Down Expand Up @@ -54,7 +53,7 @@ object PathModule extends MainModule[IO, JPath](IOPlatformIO) { self =>
def writePackages[A](packages: List[Package.Typed[A]], path: JPath): IO[Unit] =
ProtoConverter.writePackages(packages, path)

def reportOutput(out: Output): IO[ExitCode] =
def reportOutput(out: Output[JPath]): IO[ExitCode] =
out match {
case Output.TestOutput(resMap, color) =>
val hasMissing = resMap.exists(_._2.isEmpty)
Expand Down
24 changes: 12 additions & 12 deletions cli/src/test/scala/org/bykn/bosatsu/PathModuleTest.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package org.bykn.bosatsu

import cats.effect.IO
import cats.data.NonEmptyList
import cats.effect.IO
import java.nio.file.{Path, Paths}
import org.bykn.bosatsu.tool.Output
import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.funsuite.AnyFunSuite
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks.forAll

import scala.jdk.CollectionConverters._
import scala.util.{Failure, Success, Try}
import org.scalatest.funsuite.AnyFunSuite

// allow us to unsafeRunSync
import cats.effect.unsafe.implicits.global
Expand Down Expand Up @@ -102,7 +102,7 @@ class PathModuleTest extends AnyFunSuite {
}
}

def run(args: String*): PathModule.Output =
def run(args: String*): Output[Path] =
PathModule.run(args.toList) match {
case Left(h) => fail(s"got help: $h on command: ${args.toList}")
case Right(io) =>
Expand All @@ -126,7 +126,7 @@ class PathModuleTest extends AnyFunSuite {
.toSeq: _*
)
out match {
case PathModule.Output.TestOutput(results, _) =>
case Output.TestOutput(results, _) =>
val res = results.collect {
case (pn, Some(t)) if pn.asString == "Queue" => t.value
}
Expand All @@ -142,7 +142,7 @@ class PathModuleTest extends AnyFunSuite {
.toSeq: _*
)
out match {
case PathModule.Output.TestOutput(results, _) =>
case Output.TestOutput(results, _) =>
val res = results.collect {
case (pn, Some(t)) if pn.asString == "Bar" => t.value
}
Expand All @@ -160,7 +160,7 @@ class PathModuleTest extends AnyFunSuite {
.toSeq: _*
)
out match {
case PathModule.Output.TranspileOut(_, _) =>
case Output.TranspileOut(_, _) =>
assert(true)
case other => fail(s"expected transpile output: $other")
}
Expand All @@ -174,7 +174,7 @@ class PathModuleTest extends AnyFunSuite {
.toSeq: _*
)
out match {
case PathModule.Output.JsonOutput(j @ Json.JObject(_), _) =>
case Output.JsonOutput(j @ Json.JObject(_), _) =>
assert(
j.toMap == Map(
"value" -> Json.JBool(true),
Expand All @@ -193,7 +193,7 @@ class PathModuleTest extends AnyFunSuite {
.toList :+ "[2, 4]"

run(cmd: _*) match {
case PathModule.Output.JsonOutput(Json.JNumberStr("8"), _) => succeed
case Output.JsonOutput(Json.JNumberStr("8"), _) => succeed
case other => fail(s"expected json object output: $other")
}
}
Expand All @@ -205,7 +205,7 @@ class PathModuleTest extends AnyFunSuite {
.toList :+ "[[2, 4], [3, 5]]"

run(cmd: _*) match {
case PathModule.Output.JsonOutput(
case Output.JsonOutput(
Json.JArray(Vector(Json.JNumberStr("8"), Json.JNumberStr("15"))),
_
) =>
Expand Down Expand Up @@ -271,7 +271,7 @@ class PathModuleTest extends AnyFunSuite {
.toSeq: _*
)
out match {
case PathModule.Output.TestOutput(res, _) =>
case Output.TestOutput(res, _) =>
val noTests = res.collect { case (pn, None) => pn }.toList
assert(noTests == Nil)
val failures = res.collect {
Expand All @@ -288,7 +288,7 @@ class PathModuleTest extends AnyFunSuite {
.split("\\s+")
.toSeq: _*
) match {
case PathModule.Output.JsonOutput(Json.JString("this is Foo"), _) =>
case Output.JsonOutput(Json.JString("this is Foo"), _) =>
succeed
case other => fail(s"unexpeced: $other")
}
Expand Down
79 changes: 12 additions & 67 deletions core/src/main/scala/org/bykn/bosatsu/MainModule.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package org.bykn.bosatsu

import cats.data.{Chain, Validated, ValidatedNel, NonEmptyList}
import cats.{Eval, Traverse}
import cats.Traverse
import com.monovore.decline.{Argument, Command, Help, Opts}
import cats.parse.{Parser0 => P0, Parser => P}
import org.typelevel.paiges.Doc
import scala.util.{Failure, Success, Try}
import org.bykn.bosatsu.Parser.argFromParser
import org.bykn.bosatsu.tool.{FileKind, GraphOutput, Output}

import codegen.Transpiler

Expand All @@ -31,67 +32,11 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
// Below here are concrete and should not use override
//////////////////////////////

final def run(args: List[String]): Either[Help, IO[Output]] =
final def run(args: List[String]): Either[Help, IO[Output[Path]]] =
MainCommand.command
.parse(args.toList)
.map(_.run.widen)

sealed abstract class FileKind(val name: String)
object FileKind {
case object Source extends FileKind("source")
case object Iface extends FileKind("interface")
case object Pack extends FileKind("package")
}

sealed abstract class GraphOutput
object GraphOutput {
case object Dot extends GraphOutput
case object Json extends GraphOutput

val jsonOrDot: Opts[GraphOutput] =
Opts
.option[String]("graph_format", "format of graph, either json or dot")
.mapValidated {
case "json" => Validated.valid(Json)
case "dot" => Validated.valid(Dot)
case other =>
Validated.invalidNel(s"\"$other\" invalid, expected json or dot")
}
.withDefault(Json)
}

sealed abstract class Output
object Output {
case class TestOutput(
tests: List[(PackageName, Option[Eval[Test]])],
colorize: Colorize
) extends Output
case class EvaluationResult(
value: Eval[Value],
tpe: rankn.Type,
doc: Eval[Doc]
) extends Output
case class JsonOutput(json: Json, output: Option[Path]) extends Output
case class CompileOut(
packList: List[Package.Typed[Any]],
ifout: Option[Path],
output: Option[Path]
) extends Output
case class TranspileOut(outs: List[(NonEmptyList[String], Doc)], base: Path)
extends Output

case class ShowOutput(
packages: List[Package.Typed[Any]],
ifaces: List[Package.Interface],
output: Option[Path]
) extends Output

case class DepsOutput(
depinfo: List[(Path, PackageName, FileKind, List[PackageName])],
output: Option[Path],
style: GraphOutput
) extends Output
}

sealed abstract class MainException extends Exception {
def command: MainCommand
Expand Down Expand Up @@ -158,7 +103,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
}

sealed abstract class MainCommand(val name: String) {
type Result <: Output
type Result <: Output[Path]
def run: IO[Result]
}

Expand Down Expand Up @@ -584,8 +529,8 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
case class Traverse(in: JsonInput) extends JsonMode
}

type PathGen = org.bykn.bosatsu.PathGen[IO, Path]
val PathGen = org.bykn.bosatsu.PathGen
type PathGen = org.bykn.bosatsu.tool.PathGen[IO, Path]
val PathGen = org.bykn.bosatsu.tool.PathGen

sealed abstract class Inputs
object Inputs {
Expand Down Expand Up @@ -820,7 +765,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
outDir: Path
) extends MainCommand("transpile") {

type Result = Output.TranspileOut
type Result = Output.TranspileOut[Path]

def run =
withEC { implicit ec =>
Expand Down Expand Up @@ -901,7 +846,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
errColor: Colorize
) extends MainCommand("json") {

type Result = Output.JsonOutput
type Result = Output.JsonOutput[Path]

private def showError[A](prefix: String, str: String, idx: Int): IO[A] = {
val errMsg0 = str.substring(idx + 1)
Expand Down Expand Up @@ -961,7 +906,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
io: IO[String],
extract: Json => IO[G[Json]],
inject: G[Json] => Json
): IO[Output.JsonOutput] =
): IO[Output.JsonOutput[Path]] =
v2j.valueFnToJsonFn(res.tpe) match {
case Left(unsup) => unsupported(unsup)
case Right((arity, fnGen)) =>
Expand Down Expand Up @@ -1048,7 +993,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
errColor: Colorize
) extends MainCommand("check") {

type Result = Output.CompileOut
type Result = Output.CompileOut[Path]

def run =
withEC { implicit ec =>
Expand Down Expand Up @@ -1112,7 +1057,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
errColor: Colorize
) extends MainCommand("show") {

type Result = Output.ShowOutput
type Result = Output.ShowOutput[Path]

def run = withEC { implicit ec =>
for {
Expand All @@ -1129,7 +1074,7 @@ abstract class MainModule[IO[_], Path](val platformIO: PlatformIO[IO, Path]) {
style: GraphOutput
) extends MainCommand("deps") {

type Result = Output.DepsOutput
type Result = Output.DepsOutput[Path]

def srcDeps(
paths: List[Path]
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/scala/org/bykn/bosatsu/MemoryMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cats.MonadError
import cats.data.Kleisli
import com.monovore.decline.Argument
import scala.collection.immutable.SortedMap
import org.bykn.bosatsu.tool.Output

import cats.syntax.all._

Expand All @@ -30,10 +31,10 @@ class MemoryMain[G[_], K: Ordering](
files: Iterable[(K, String)],
packages: Iterable[(K, List[Package.Typed[Unit]])] = Nil,
interfaces: Iterable[(K, List[Package.Interface])] = Nil
)(cmd: List[String]): G[Output] =
)(cmd: List[String]): G[Output[K]] =
run(cmd) match {
case Left(msg) =>
moduleIOMonad.raiseError[Output](
moduleIOMonad.raiseError[Output[K]](
new Exception(s"got the help message for: $cmd: $msg")
)
.run(SortedMap.empty[K, MemoryMain.FileContent])
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/scala/org/bykn/bosatsu/tool/FileKind.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.bykn.bosatsu.tool

sealed abstract class FileKind(val name: String)
object FileKind {
case object Source extends FileKind("source")
case object Iface extends FileKind("interface")
case object Pack extends FileKind("package")
}
21 changes: 21 additions & 0 deletions core/src/main/scala/org/bykn/bosatsu/tool/GraphOutput.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.bykn.bosatsu.tool

import cats.data.Validated
import com.monovore.decline.Opts

sealed abstract class GraphOutput
object GraphOutput {
case object Dot extends GraphOutput
case object Json extends GraphOutput

val jsonOrDot: Opts[GraphOutput] =
Opts
.option[String]("graph_format", "format of graph, either json or dot")
.mapValidated {
case "json" => Validated.valid(Json)
case "dot" => Validated.valid(Dot)
case other =>
Validated.invalidNel(s"\"$other\" invalid, expected json or dot")
}
.withDefault(Json)
}
44 changes: 44 additions & 0 deletions core/src/main/scala/org/bykn/bosatsu/tool/Output.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.bykn.bosatsu.tool

import cats.Eval
import cats.data.NonEmptyList
import org.bykn.bosatsu.{Json, Package, PackageName, Test, Value, rankn}
import org.typelevel.paiges.Doc
import org.bykn.bosatsu.LocationMap.Colorize

sealed abstract class Output[+Path]
object Output {
case class TestOutput(
tests: List[(PackageName, Option[Eval[Test]])],
colorize: Colorize
) extends Output[Nothing]

case class EvaluationResult(
value: Eval[Value],
tpe: rankn.Type,
doc: Eval[Doc]
) extends Output[Nothing]

case class JsonOutput[Path](json: Json, output: Option[Path]) extends Output[Path]

case class CompileOut[Path](
packList: List[Package.Typed[Any]],
ifout: Option[Path],
output: Option[Path]
) extends Output[Path]

case class TranspileOut[Path](outs: List[(NonEmptyList[String], Doc)], base: Path)
extends Output[Path]

case class ShowOutput[Path](
packages: List[Package.Typed[Any]],
ifaces: List[Package.Interface],
output: Option[Path]
) extends Output[Path]

case class DepsOutput[Path](
depinfo: List[(Path, PackageName, FileKind, List[PackageName])],
output: Option[Path],
style: GraphOutput
) extends Output[Path]
}
Loading

0 comments on commit e167129

Please sign in to comment.