refactor: introduce decline to integrate command-line parsing with cats-effect

This commit is contained in:
Jonny
2025-02-28 18:00:18 +00:00
parent 1a72decf55
commit d56be9249a
2 changed files with 35 additions and 31 deletions

View File

@@ -9,7 +9,6 @@
//> using dep org.typelevel::cats-effect::3.5.7
//> using dep com.monovore::decline::2.5.0
//> using dep com.monovore::decline-effect::2.5.0
//> using dep com.github.scopt::scopt::4.1.0
//> using test.dep org.scalatest::scalatest::3.2.19
//> using dep org.typelevel::cats-effect-testing-scalatest::1.6.0

View File

@@ -3,38 +3,38 @@ package wacc
import scala.collection.mutable
import cats.data.Chain
import parsley.{Failure, Success}
import scopt.OParser
import java.io.File
import java.io.PrintStream
import cats.implicits.*
import assemblyIR as asm
import cats.effect.IO
import cats.effect.IOApp
import cats.effect.ExitCode
import com.monovore.decline._
import com.monovore.decline.effect._
import com.monovore.decline.Argument
import assemblyIR as asm
case class CliConfig(
file: File = new File(".")
)
val cliBuilder = OParser.builder[CliConfig]
val cliParser = {
import cliBuilder._
OParser.sequence(
programName("wacc-compiler"),
help('h', "help")
.text("Prints this help message"),
arg[File]("<file>")
.text("Input WACC source file")
.required()
.action((f, c) => c.copy(file = f))
.validate(f =>
if (!f.exists) failure("File does not exist")
else if (!f.isFile) failure("File must be a regular file")
else if (!f.getName.endsWith(".wacc"))
failure("File must have .wacc extension")
else success
)
)
given Argument[File] = Argument.from("file") { str =>
val file = File(str)
(
Option.when(file.exists())(file).toValidNel(s"File '${file.getAbsolutePath}' does not exist"),
Option
.when(file.isFile())(file)
.toValidNel(s"File '${file.getAbsolutePath}' must be a regular file"),
Option.when(file.getName.endsWith(".wacc"))(file).toValidNel("File must have .wacc extension")
).mapN((_, _, _) => file)
}
val cliCommand: Command[File] =
Command("wacc-compiler", "Compile WACC programs") {
Opts.argument[File]("file")
}
def frontend(
@@ -87,13 +87,18 @@ def compile(filename: String, outFile: Option[File] = None)(using
)
} yield exitCode
object Main extends IOApp.Simple {
override def run: IO[Unit] =
OParser.parse(cliParser, sys.env.getOrElse("WACC_ARGS", "").split(" "), CliConfig()).traverse_ {
config =>
object Main
extends CommandIOApp(
name = "wacc-compiler",
header = "the ultimate wacc compiler",
version = "1.0"
) {
def main: Opts[IO[ExitCode]] =
Opts.argument[File]("file").map { file =>
compile(
config.file.getAbsolutePath,
outFile = Some(File(".", config.file.getName.stripSuffix(".wacc") + ".s"))
)
file.getAbsolutePath,
outFile = Some(File(".", file.getName.stripSuffix(".wacc") + ".s"))
).map(ExitCode(_)) // turn the int into exit code for compatibility with commandioapp
// https://ben.kirw.in/decline/effect.html
}
}