package wacc import cats.data.Chain import wacc.assemblyIR._ val ERROR_CODE = 255 sealed trait RuntimeError { def strLabel: String def errStr: String def errLabel: String def stringDef: Chain[AsmLine] = Chain( Directive.Int(errStr.length), LabelDef(strLabel), Directive.Asciz(errStr) ) def generateHandler: Chain[AsmLine] } 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 strLabel = ".L._errDivZero_str0" val errStr = "fatal error: division or modulo by zero" val errLabel = ".L._errDivZero" def generateHandler: Chain[AsmLine] = Chain( LabelDef(ZeroDivError.errLabel), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(ZeroDivError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(-1)), assemblyIR.Call(CLibFunc.Exit) ) } case object BadChrError extends RuntimeError { val strLabel = ".L._errBadChr_str0" val errStr = "fatal error: int %d is not an ASCII character 0-127" val errLabel = ".L._errBadChr" def generateHandler: Chain[AsmLine] = Chain( LabelDef(BadChrError.errLabel), Pop(RSI), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(BadChrError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) ) } case object NullPtrError extends RuntimeError { val strLabel = ".L._errNullPtr_str0" val errStr = "fatal error: null pair dereferenced or freed" val errLabel = ".L._errNullPtr" def generateHandler: Chain[AsmLine] = Chain( LabelDef(NullPtrError.errLabel), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(NullPtrError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) ) } case object OverflowError extends RuntimeError { val strLabel = ".L._errOverflow_str0" val errStr = "fatal error: integer overflow or underflow occurred" val errLabel = ".L._errOverflow" def generateHandler: Chain[AsmLine] = Chain( LabelDef(OverflowError.errLabel), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(OverflowError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) ) } case object OutOfBoundsError extends RuntimeError { val strLabel = ".L._errOutOfBounds_str0" val errStr = "fatal error: array index %d out of bounds" val errLabel = ".L._errOutOfBounds" def generateHandler: Chain[AsmLine] = Chain( LabelDef(OutOfBoundsError.errLabel), Move(RSI, RCX), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(OutOfBoundsError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) ) } case object OutOfMemoryError extends RuntimeError { val strLabel = ".L._errOutOfMemory_str0" val errStr = "fatal error: out of memory" val errLabel = ".L._errOutOfMemory" def generateHandler: Chain[AsmLine] = Chain( LabelDef(OutOfMemoryError.errLabel), stackAlign, Load(RDI, IndexAddress(RIP, LabelArg(OutOfMemoryError.strLabel))), assemblyIR.Call(CLibFunc.PrintF), Move(RDI, ImmediateVal(ERROR_CODE)), assemblyIR.Call(CLibFunc.Exit) ) } val all: Chain[RuntimeError] = Chain(ZeroDivError, BadChrError, NullPtrError, OverflowError, OutOfBoundsError, OutOfMemoryError) }