feat: introduction of logger to eliminate printstreams

This commit is contained in:
Jonny
2025-03-01 01:19:50 +00:00
parent d214723f35
commit 667fbf4949
4 changed files with 43 additions and 26 deletions

View File

@@ -9,6 +9,8 @@
//> using dep org.typelevel::cats-effect::3.5.7 //> using dep org.typelevel::cats-effect::3.5.7
//> using dep com.monovore::decline::2.5.0 //> using dep com.monovore::decline::2.5.0
//> using dep com.monovore::decline-effect::2.5.0 //> using dep com.monovore::decline-effect::2.5.0
//> using dep org.typelevel::log4cats-slf4j::2.7.0
//> using dep org.slf4j:slf4j-simple:2.0.17
//> using test.dep org.scalatest::scalatest::3.2.19 //> using test.dep org.scalatest::scalatest::3.2.19
//> using dep org.typelevel::cats-effect-testing-scalatest::1.6.0 //> using dep org.typelevel::cats-effect-testing-scalatest::1.6.0

View File

@@ -4,7 +4,6 @@ import scala.collection.mutable
import cats.data.Chain import cats.data.Chain
import parsley.{Failure, Success} import parsley.{Failure, Success}
import java.io.File import java.io.File
import java.io.PrintStream
import cats.implicits.* import cats.implicits.*
import cats.effect.IO import cats.effect.IO
@@ -14,6 +13,9 @@ import com.monovore.decline._
import com.monovore.decline.effect._ import com.monovore.decline.effect._
import com.monovore.decline.Argument import com.monovore.decline.Argument
import org.typelevel.log4cats.slf4j.Slf4jLogger
import org.typelevel.log4cats.Logger
import assemblyIR as asm import assemblyIR as asm
given Argument[File] = Argument.from("file") { str => given Argument[File] = Argument.from("file") { str =>
@@ -32,30 +34,33 @@ val cliCommand: Command[File] =
Opts.argument[File]("file") Opts.argument[File]("file")
} }
given logger: Logger[IO] = Slf4jLogger.getLogger[IO]
def frontend( def frontend(
contents: String contents: String
)(using stdout: PrintStream): IO[Either[Int, microWacc.Program]] = { ): IO[Either[Int, microWacc.Program]] = {
IO(parser.parse(contents)).map { IO(parser.parse(contents)).flatMap {
case Failure(msg) => case Failure(msg) =>
stdout.println(msg) logger.error(s"Syntax error: $msg").as(Left(100))
Left(100) // Syntax error
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.isEmpty) Right(typedProg) if (errors.result.isEmpty) IO.pure(Right(typedProg))
else { else {
errors.result.foreach(printError) val exitCode = errors.result.view.map {
Left(errors.result.view.map {
case _: Error.InternalError => 201 case _: Error.InternalError => 201
case _ => 200 case _ => 200
}.max) }.max
logger.error(s"Semantic errors:\n${errors.result.mkString("\n")}") *> IO.pure(
Left(exitCode)
)
} }
} }
} }
@@ -64,21 +69,18 @@ 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): IO[Int] =
stdout: PrintStream = Console.out
): IO[Int] =
for { for {
contents <- IO(os.read(os.Path(filename))) contents <- IO(os.read(os.Path(filename)))
_ <- logger.info(s"Compiling file: $filename")
result <- frontend(contents) result <- frontend(contents)
exitCode <- result.fold( exitCode <- result.fold(
IO.pure, // Return error code (handles Left case) code => logger.error(s"Compilation failed for $filename\nExit code: $code").as(code),
typedProg => typedProg =>
IO { val outputFile = outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s"))
writer.writeTo( writer.writeTo(backend(typedProg), outputFile) *> logger
backend(typedProg), .info(s"Compilation succeeded: $filename")
PrintStream(outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s"))) .as(0)
)
}.as(0) // Compilation succeeded
) )
} yield exitCode } yield exitCode

View File

@@ -1,12 +1,27 @@
package wacc package wacc
import java.io.PrintStream import cats.effect.Resource
import java.nio.charset.StandardCharsets
import java.io.File
import java.io.BufferedWriter
import java.io.FileWriter
import cats.data.Chain import cats.data.Chain
import cats.effect.IO
import org.typelevel.log4cats.Logger
object writer { object writer {
import assemblyIR._ import assemblyIR._
def writeTo(asmList: Chain[AsmLine], printStream: PrintStream): Unit = { def writeTo(asmList: Chain[AsmLine], outputFile: File)(using logger: Logger[IO]): IO[Unit] =
asmList.iterator.foreach(printStream.println) Resource
.fromAutoCloseable {
IO(BufferedWriter(FileWriter(outputFile, StandardCharsets.UTF_8)))
}
.use { writer =>
IO {
asmList.iterator.foreach(line => writer.write(line.toString + "\n"))
writer.flush() // TODO: NECESSARY OR NOT?
} *> logger.info(s"Wrote assembly to ${outputFile.getAbsolutePath}")
} }
} }

View File

@@ -7,7 +7,6 @@ import org.scalatest.freespec.AsyncFreeSpec
import cats.effect.testing.scalatest.AsyncIOSpec import cats.effect.testing.scalatest.AsyncIOSpec
import java.io.File import java.io.File
import sys.process._ import sys.process._
import java.io.PrintStream
import scala.io.Source import scala.io.Source
import cats.effect.IO import cats.effect.IO
import wacc.{compile as compileWacc} import wacc.{compile as compileWacc}
@@ -30,7 +29,6 @@ class ParallelExamplesSpec extends AsyncFreeSpec with AsyncIOSpec with BeforeAnd
forEvery(files) { (filename, expectedResult) => forEvery(files) { (filename, expectedResult) =>
val baseFilename = filename.stripSuffix(".wacc") val baseFilename = filename.stripSuffix(".wacc")
given stdout: PrintStream = PrintStream(File(baseFilename + ".out"))
s"$filename" - { s"$filename" - {
"should be compiled with correct result" in { "should be compiled with correct result" in {