wacc_37/src/main/wacc/Main.scala

91 lines
2.5 KiB
Scala

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 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
)
)
}
def frontend(
contents: String
)(using stdout: PrintStream): Either[microWacc.Program, Int] = {
parser.parse(contents) match {
case Success(prog) =>
given errors: mutable.Builder[Error, List[Error]] = List.newBuilder
val (names, funcs) = renamer.rename(prog)
given ctx: typeChecker.TypeCheckerCtx = typeChecker.TypeCheckerCtx(names, funcs, errors)
val typedProg = typeChecker.check(prog)
if (errors.result.nonEmpty) {
given errorContent: String = contents
Right(
errors.result
.map { error =>
printError(error)
error match {
case _: Error.InternalError => 201
case _ => 200
}
}
.max()
)
} else Left(typedProg)
case Failure(msg) =>
stdout.println(msg)
Right(100)
}
}
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
): Int =
frontend(os.read(os.Path(filename))) match {
case Left(typedProg) =>
val asmFile = outFile.getOrElse(File(filename.stripSuffix(".wacc") + ".s"))
val asm = backend(typedProg)
writer.writeTo(asm, PrintStream(asmFile))
0
case Right(exitCode) => exitCode
}
def main(args: Array[String]): Unit =
OParser.parse(cliParser, args, CliConfig()) match {
case Some(config) =>
compile(
config.file.getAbsolutePath,
outFile = Some(File(".", config.file.getName.stripSuffix(".wacc") + ".s"))
)
case None =>
}