79 lines
2.6 KiB
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)
|
|
}
|
|
}
|