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 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]("") .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 ) ) } def frontend( contents: String )(using stdout: PrintStream): IO[Either[Int, microWacc.Program]] = { IO(parser.parse(contents)).map { case Failure(msg) => stdout.println(msg) Left(100) // Syntax error case Success(prog) => given errors: mutable.Builder[Error, List[Error]] = List.newBuilder given errorContent: String = contents val (names, funcs) = renamer.rename(prog) given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, funcs, errors) val typedProg = typeChecker.check(prog) if (errors.result.isEmpty) Right(typedProg) else { errors.result.foreach(printError) Left(errors.result.view.map { case _: Error.InternalError => 201 case _ => 200 }.max) } } } val s = "enter an integer to echo" def backend(typedProg: microWacc.Program): Chain[asm.AsmLine] = asmGenerator.generateAsm(typedProg) def compile(filename: String, outFile: Option[File] = None)(using stdout: PrintStream = Console.out ): IO[Int] = for { contents <- IO(os.read(os.Path(filename))) result <- frontend(contents) exitCode <- result.fold( IO.pure, // Return error code (handles Left case) typedProg => IO { writer.writeTo( backend(typedProg), PrintStream(outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s"))) ) }.as(0) // Compilation succeeded ) } yield exitCode object Main extends IOApp.Simple { override def run: IO[Unit] = OParser.parse(cliParser, sys.env.getOrElse("WACC_ARGS", "").split(" "), CliConfig()).traverse_ { config => compile( config.file.getAbsolutePath, outFile = Some(File(".", config.file.getName.stripSuffix(".wacc") + ".s")) ) } }