diff --git a/src/main/wacc/Main.scala b/src/main/wacc/Main.scala index 571103b..33c4fef 100644 --- a/src/main/wacc/Main.scala +++ b/src/main/wacc/Main.scala @@ -23,11 +23,10 @@ import cats.data.ValidatedNel /* TODO: 1) IO correctness - 2) --greedy, - 3) parallelised compilation - 4) splitting the file up and nicer refactoring - 5) logging could be removed - 6) errors can be handled more gracefully probably + 2) Errors can be handled more gracefully - currently, parallelised compilation is not fail fast as far as I am aware + 3) splitting the file up and nicer refactoring + 4) logging could be removed + 5) general cleanup and comments (things like replacing home/ with ~ , and names of parameters and args, descriptions etc) */ given logger: Logger[IO] = Slf4jLogger.getLogger[IO] @@ -49,12 +48,14 @@ val filesOpt: Opts[NonEmptyList[Path]] = _.traverse(validateFile) } -// TODO: Is intermediate String necessary val outputOpt: Opts[Option[Path]] = Opts .option[Path]("output", metavar = "path", help = "Output directory for compiled files.") .orNone +val greedyOpt: Opts[Boolean] = + Opts.flag("greedy", "Compile WACC files sequentially instead of parallelly", short = "g").orFalse + def frontend( contents: String ): IO[Either[Int, microWacc.Program]] = { @@ -138,27 +139,43 @@ def compile(filePath: Path, outputDir: Option[Path], log: Boolean): IO[Int] = { } yield exitCode } -// TODO: this is sequential, thus should be what occurs when --greedy is passed in -val compileCommand: Opts[IO[ExitCode]] = - (filesOpt, logOpt, outputOpt).mapN { (files, log, outDir) => - files - .traverse { file => - compile(file.toAbsolutePath, outDir, log).handleErrorWith { err => - // TODO: probably a more elegant way of doing this - // also, -1 arbitrary - // also - this outputs two messages for some reason - logger.error(err.getMessage) // *> IO.pure(ExitCode(-1)) - } +// TODO: Remove duplicate code between compileCommandSequential and compileCommandParallel +def compileCommandSequential( + files: NonEmptyList[Path], + log: Boolean, + outDir: Option[Path] +): IO[ExitCode] = + files + .traverse { file => + compile(file.toAbsolutePath, outDir, log).handleErrorWith { err => + // TODO: probably a more elegant way of doing this + // also, -1 arbitrary + // also - this outputs two messages for some reason + logger.error(err.getMessage) // *> IO.raiseError(err) } - .map { exitCodes => - if (exitCodes.exists(_ != 0)) - ExitCode.Error // TODO- it should be the first one to exit when parallelised :) - else ExitCode.Success + } + .map { exitCodes => + if (exitCodes.exists(_ != 0)) ExitCode.Error else ExitCode.Success + } + +def compileCommandParallel( + files: NonEmptyList[Path], + log: Boolean, + outDir: Option[Path] +): IO[ExitCode] = + files + .parTraverse { file => + compile(file.toAbsolutePath, outDir, log).handleErrorWith { err => + // TODO: probably a more elegant way of doing this + // also, -1 arbitrary + // also - this outputs two messages for some reason + logger.error(err.getMessage) // *> IO.raiseError(err) } + } + .map { exitCodes => + if (exitCodes.exists(_ != 0)) ExitCode.Error else ExitCode.Success + } - } - -// TODO: add parallelisable option object Main extends CommandIOApp( name = "wacc", @@ -166,6 +183,9 @@ object Main version = "1.0" ) { def main: Opts[IO[ExitCode]] = - compileCommand + (greedyOpt, filesOpt, logOpt, outputOpt).mapN { (greedy, files, log, outDir) => + if (greedy) compileCommandSequential(files, log, outDir) + else compileCommandParallel(files, log, outDir) + } }