feat: introduce cats-effect and io

This commit is contained in:
Jonny
2025-02-28 15:18:24 +00:00
parent 8b3e9b8380
commit 345c652a57
3 changed files with 53 additions and 56 deletions

View File

@@ -5,23 +5,18 @@
//> using dep com.github.j-mie6::parsley::5.0.0-M10 //> using dep com.github.j-mie6::parsley::5.0.0-M10
//> using dep com.github.j-mie6::parsley-cats::1.5.0 //> using dep com.github.j-mie6::parsley-cats::1.5.0
//> using dep com.lihaoyi::os-lib::0.11.4 //> using dep com.lihaoyi::os-lib::0.11.4
//> using dep org.typelevel::cats-core::2.13.0
//> 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 dep com.github.scopt::scopt::4.1.0
//> using test.dep org.scalatest::scalatest::3.2.19 //> using test.dep org.scalatest::scalatest::3.2.19
// these are all sensible defaults to catch annoying issues // sensible defaults for warnings and compiler checks
//> using options -deprecation -unchecked -feature //> using options -deprecation -unchecked -feature
//> using options -Wimplausible-patterns -Wunused:all //> using options -Wimplausible-patterns -Wunused:all
//> using options -Yexplicit-nulls -Wsafe-init -Xkind-projector:underscores //> using options -Yexplicit-nulls -Wsafe-init -Xkind-projector:underscores
// these will help ensure you have access to the latest parsley releases // repositories for pre-release versions if needed
// even before they land on maven proper, or snapshot versions, if necessary. //> using repositories sonatype-s01:releases
// just in case they cause problems, however, keep them turned off unless you //> using repositories sonatype-s01:snapshots
// specifically need them.
// using repositories sonatype-s01:releases
// using repositories sonatype-s01:snapshots
// these are flags used by Scala native: if you aren't using scala-native, then they do nothing
// lto-thin has decent linking times, and release-fast does not too much optimisation.
// using nativeLto thin
// using nativeGc commix
// using nativeMode release-fast

View File

@@ -6,8 +6,12 @@ import parsley.{Failure, Success}
import scopt.OParser import scopt.OParser
import java.io.File import java.io.File
import java.io.PrintStream import java.io.PrintStream
import cats.implicits._
import cats.effect.unsafe.implicits.global
import assemblyIR as asm import assemblyIR as asm
import cats.effect.IO
import cats.effect.IOApp
case class CliConfig( case class CliConfig(
file: File = new File(".") file: File = new File(".")
@@ -36,57 +40,54 @@ val cliParser = {
def frontend( def frontend(
contents: String contents: String
)(using stdout: PrintStream): Either[microWacc.Program, Int] = { )(using stdout: PrintStream): IO[microWacc.Program] = {
parser.parse(contents) match { IO(parser.parse(contents)).flatMap {
case Failure(msg) => IO.raiseError(new RuntimeException(msg))
case Success(prog) => case Success(prog) =>
given errors: mutable.Builder[Error, List[Error]] = List.newBuilder given errors: mutable.Builder[Error, List[Error]] = List.newBuilder
given errorContent: String = contents
val (names, funcs) = renamer.rename(prog) val (names, funcs) = renamer.rename(prog)
given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, funcs, errors) given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, funcs, errors)
val typedProg = typeChecker.check(prog) val typedProg = typeChecker.check(prog)
if (errors.result.nonEmpty) {
given errorContent: String = contents if (errors.result.isEmpty) IO.pure(typedProg)
Right( else {
errors.result errors.result.foreach(printError)
.map { error => IO.raiseError(new RuntimeException("Compilation failed with code: " + errors.result.view.map {
printError(error)
error match {
case _: Error.InternalError => 201 case _: Error.InternalError => 201
case _ => 200 case _ => 200
}.max))
} }
} }
.max()
)
} else Left(typedProg)
case Failure(msg) =>
stdout.println(msg)
Right(100)
}
} }
val s = "enter an integer to echo" val s = "enter an integer to echo"
def backend(typedProg: microWacc.Program): Chain[asm.AsmLine] = def backend(typedProg: microWacc.Program): Chain[asm.AsmLine] =
asmGenerator.generateAsm(typedProg) asmGenerator.generateAsm(typedProg)
def compile(filename: String, outFile: Option[File] = None)(using def compile(filename: String, outFile: Option[File] = None)(using
stdout: PrintStream = Console.out stdout: PrintStream = Console.out
): Int = ): IO[Int] =
frontend(os.read(os.Path(filename))) match { for {
case Left(typedProg) => contents <- IO(os.read(os.Path(filename)))
val asmFile = outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s")) typedProg <- frontend(contents)
val asm = backend(typedProg) _ <- IO {
writer.writeTo(asm, PrintStream(asmFile)) writer.writeTo(
0 backend(typedProg),
case Right(exitCode) => exitCode PrintStream(outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s")))
)
} }
} yield 0
def main(args: Array[String]): Unit = object Main extends IOApp.Simple {
OParser.parse(cliParser, args, CliConfig()) match { override def run: IO[Unit] =
case Some(config) => OParser.parse(cliParser, sys.env.getOrElse("WACC_ARGS", "").split(" "), CliConfig()).traverse_ { config =>
System.exit(
compile( compile(
config.file.getAbsolutePath, config.file.getAbsolutePath,
outFile = Some(File(".", config.file.getName.stripSuffix(".wacc") + ".s")) outFile = Some(File(".", config.file.getName.stripSuffix(".wacc") + ".s"))
) )
) }
case None =>
} }

View File

@@ -7,6 +7,7 @@ import java.io.File
import sys.process._ import sys.process._
import java.io.PrintStream import java.io.PrintStream
import scala.io.Source import scala.io.Source
import cats.effect.unsafe.implicits.global
class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll { class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll {
val files = val files =
@@ -29,7 +30,7 @@ class ParallelExamplesSpec extends AnyFlatSpec with BeforeAndAfterAll {
given stdout: PrintStream = PrintStream(File(baseFilename + ".out")) given stdout: PrintStream = PrintStream(File(baseFilename + ".out"))
s"$filename" should "be compiled with correct result" in { s"$filename" should "be compiled with correct result" in {
val result = compile(filename) val result = compile(filename).unsafeRunSync()
assert(expectedResult.contains(result)) assert(expectedResult.contains(result))
} }