Files
WACC_37/src/main/wacc/backend/LabelGenerator.scala

79 lines
2.6 KiB
Scala

package wacc
import scala.collection.mutable
import cats.data.Chain
import wacc.ast.Position
private class LabelGenerator {
import assemblyIR._
import microWacc.{CallTarget, Ident, Builtin}
import asmGenerator.escaped
private val strings = mutable.HashMap[String, String]()
private val files = mutable.HashMap[String, Int]()
private var labelVal = -1
private var permittedFuncFile: Option[String] = None
/** Get an arbitrary label. */
def getLabel(): String = {
labelVal += 1
s".L$labelVal"
}
private def getLabel(target: CallTarget | RuntimeError): String = target match {
case Ident(v, guid) => s"wacc_${v}_$guid"
case Builtin(name) => s"_$name"
case err: RuntimeError => s".L.${err.name}"
}
/** Get a named label def for a function or error. */
def getLabelDef(target: CallTarget | RuntimeError): LabelDef =
LabelDef(getLabel(target))
/** Get a named label for a function or error. */
def getLabelArg(target: CallTarget | RuntimeError): LabelArg =
LabelArg(getLabel(target))
/** Get an arbitrary label for a string. */
def getLabelArg(str: String): LabelArg =
LabelArg(strings.getOrElseUpdate(str, s".L.str${strings.size}"))
/** Get a named label for a string. */
def getLabelArg(src: String, name: String): LabelArg =
LabelArg(strings.getOrElseUpdate(src, s".L.$name.str${strings.size}"))
/** Get a debug directive for a file. */
def getDebugFile(file: java.io.File): Int =
files.getOrElseUpdate(file.getCanonicalPath, files.size)
/** Get a debug directive for a function. */
def getDebugFunc(pos: Position, name: String, label: LabelDef): Chain[AsmLine] = {
permittedFuncFile match {
case Some(f) if f != pos.file.getCanonicalPath => Chain.empty
case _ =>
val customLabel = if name == "main" then Chain.empty else Chain(LabelDef(name))
permittedFuncFile = Some(pos.file.getCanonicalPath)
customLabel ++ Chain(
Directive.Location(getDebugFile(pos.file), pos.line, None),
Directive.Type(label, SymbolType.Function),
Directive.Func(name, label)
)
}
}
/** Generate the assembly labels for constants that were labelled using the LabelGenerator. */
def generateConstants: Chain[AsmLine] =
strings.foldLeft(Chain.empty) { case (acc, (str, label)) =>
acc ++ Chain(
LabelDef(label),
Directive.Asciz(str.escaped)
)
}
/** Generates debug directives that were created using the LabelGenerator. */
def generateDebug: Chain[AsmLine] =
files.foldLeft(Chain.empty) { case (acc, (file, no)) =>
acc :+ Directive.File(no, file)
}
}