package wacc import cats.data.Chain import wacc.assemblyIR._ sealed trait RuntimeError { val name: String protected val errStr: String protected def getErrLabel(using labelGenerator: LabelGenerator): LabelArg = labelGenerator.getLabelArg(errStr, name = name) protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] def generate(using labelGenerator: LabelGenerator): Chain[AsmLine] = labelGenerator.getLabelDef(this) +: generateHandler } object RuntimeError { // TODO: Refactor to mitigate imports and redeclared vals perhaps import wacc.asmGenerator.stackAlign import assemblyIR.Size._ import assemblyIR.RegName._ // private val RAX = Register(Q64, AX) // private val EAX = Register(D32, AX) private val RDI = Register(Q64, DI) private val RIP = Register(Q64, IP) // private val RBP = Register(Q64, BP) private val RSI = Register(Q64, SI) // private val RDX = Register(Q64, DX) // private val RCX = Register(Q64, CX) case object ZeroDivError extends RuntimeError { val name = "errDivZero" protected val errStr = "fatal error: division or modulo by zero" protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, Load(RDI, IndexAddress(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(-1)), assemblyIR.Call(CLibFunc.Exit) ) } case object BadChrError extends RuntimeError { val name = "errBadChr" protected val errStr = "fatal error: int %d is not an ASCII character 0-127" protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( Pop(RSI), stackAlign, Load(RDI, IndexAddress(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(255)), assemblyIR.Call(CLibFunc.Exit) ) } case object NullPtrError extends RuntimeError { val name = "errNullPtr" protected val errStr = "fatal error: null pair dereferenced or freed" protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, Load(RDI, IndexAddress(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(255)), assemblyIR.Call(CLibFunc.Exit) ) } case object OverflowError extends RuntimeError { val name = "errOverflow" protected val errStr = "fatal error: integer overflow or underflow occurred" protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( stackAlign, Load(RDI, IndexAddress(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(255)), assemblyIR.Call(CLibFunc.Exit) ) } case object OutOfBoundsError extends RuntimeError { val name = "errOutOfBounds" protected val errStr = "fatal error: array index %d out of bounds" protected def generateHandler(using labelGenerator: LabelGenerator): Chain[AsmLine] = Chain( Move(RSI, Register(Q64, CX)), stackAlign, Load(RDI, IndexAddress(RIP, getErrLabel)), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(255)), assemblyIR.Call(CLibFunc.Exit) ) } val all: Chain[RuntimeError] = Chain(ZeroDivError, BadChrError, NullPtrError, OverflowError, OutOfBoundsError) }