use require() more often

This commit is contained in:
Irmen de Jong 2022-09-27 18:27:55 +02:00
parent 1d2ce2cbeb
commit 7ea7e63f44
7 changed files with 37 additions and 66 deletions

View File

@ -173,8 +173,7 @@ class PtPrefix(val operator: String, type: DataType, position: Position): PtExpr
init { init {
// note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0 // note: the "not" operator may no longer occur in the ast; not x should have been replaced with x==0
if(operator !in setOf("+", "-", "~")) require(operator in setOf("+", "-", "~")) { "invalid prefix operator: $operator" }
throw IllegalArgumentException("invalid prefix operator: $operator")
} }
override fun printProperties() { override fun printProperties() {

View File

@ -544,8 +544,7 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) {
} }
private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk { private fun operatorModulo(binExpr: PtBinaryExpression, vmDt: VmDataType, resultRegister: Int): IRCodeChunk {
if(vmDt==VmDataType.FLOAT) require(vmDt!=VmDataType.FLOAT) {"floating-point modulo not supported"}
throw IllegalArgumentException("floating-point modulo not supported")
val code = IRCodeChunk(binExpr.position) val code = IRCodeChunk(binExpr.position)
val rightResultReg = codeGen.vmRegisters.nextFree() val rightResultReg = codeGen.vmRegisters.nextFree()
if(binExpr.right is PtNumber) { if(binExpr.right is PtNumber) {

View File

@ -3,8 +3,6 @@ TODO
For next release For next release
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
- replace throw IllegalArgumentException() by require()?
... ...

View File

@ -434,59 +434,41 @@ data class IRInstruction(
val fpReg1direction: OperandDirection val fpReg1direction: OperandDirection
init { init {
if(labelSymbol?.startsWith('_')==true) { require(labelSymbol?.first()!='_') {"label/symbol should not start with underscore $labelSymbol"}
throw IllegalArgumentException("label/symbol should not start with underscore $labelSymbol") require(reg1==null || reg1 in 0..65536) {"reg1 out of bounds"}
} require(reg2==null || reg2 in 0..65536) {"reg2 out of bounds"}
if(reg1!=null && (reg1<0 || reg1>65536)) require(fpReg1==null || fpReg1 in 0..65536) {"fpReg1 out of bounds"}
throw IllegalArgumentException("reg1 out of bounds") require(fpReg2==null || fpReg2 in 0..65536) {"fpReg2 out of bounds"}
if(reg2!=null && (reg2<0 || reg2>65536))
throw IllegalArgumentException("reg2 out of bounds")
if(fpReg1!=null && (fpReg1<0 || fpReg1>65536))
throw IllegalArgumentException("fpReg1 out of bounds")
if(fpReg2!=null && (fpReg2<0 || fpReg2>65536))
throw IllegalArgumentException("fpReg2 out of bounds")
if(value!=null && opcode !in OpcodesWithAddress) { if(value!=null && opcode !in OpcodesWithAddress) {
when (type) { when (type) {
VmDataType.BYTE -> { VmDataType.BYTE -> require(value in -128..255) {"value out of range for byte: $value"}
if (value < -128 || value > 255) VmDataType.WORD -> require(value in -32768..65535) {"value out of range for word: $value"}
throw IllegalArgumentException("value out of range for byte: $value")
}
VmDataType.WORD -> {
if (value < -32768 || value > 65535)
throw IllegalArgumentException("value out of range for word: $value")
}
VmDataType.FLOAT, null -> {} VmDataType.FLOAT, null -> {}
} }
} }
if(opcode==Opcode.BINARYDATA && binaryData==null || binaryData!=null && opcode!=Opcode.BINARYDATA) require((opcode==Opcode.BINARYDATA && binaryData!=null) || (opcode!=Opcode.BINARYDATA && binaryData==null)) {
throw IllegalArgumentException("binarydata inconsistency") "binarydata inconsistency"
}
val formats = instructionFormats.getValue(opcode) val formats = instructionFormats.getValue(opcode)
if(type==null && !formats.containsKey(null)) require (type != null || formats.containsKey(null)) { "missing type" }
throw IllegalArgumentException("missing type")
val format = formats.getValue(type) val format = formats.getValue(type)
if(format.reg1 && reg1==null || format.reg2 && reg2==null) if(format.reg1) require(reg1!=null) { "missing reg1" }
throw IllegalArgumentException("missing a register (int)") if(format.reg2) require(reg2!=null) { "missing reg2" }
if(format.fpReg1) require(fpReg1!=null) { "missing fpReg1" }
if(format.fpReg1 && fpReg1==null || format.fpReg2 && fpReg2==null) if(format.fpReg2) require(fpReg2!=null) { "missing fpReg2" }
throw IllegalArgumentException("missing a register (float)") if(!format.reg1) require(reg1==null) { "invalid reg1" }
if(!format.reg2) require(reg2==null) { "invalid reg2" }
if(!format.reg1 && reg1!=null || !format.reg2 && reg2!=null) if(!format.fpReg1) require(fpReg1==null) { "invalid fpReg1" }
throw IllegalArgumentException("too many registers (int)") if(!format.fpReg2) require(fpReg2==null) { "invalid fpReg2" }
if(!format.fpReg1 && fpReg1!=null || !format.fpReg2 && fpReg2!=null)
throw IllegalArgumentException("too many registers (float)")
if (type==VmDataType.FLOAT) { if (type==VmDataType.FLOAT) {
if(format.fpValue && (fpValue==null && labelSymbol==null)) if(format.fpValue) require(fpValue!=null || labelSymbol!=null) {"missing a fp-value or labelsymbol"}
throw IllegalArgumentException("missing a fp-value or labelsymbol")
} else { } else {
if(format.value && (value==null && labelSymbol==null)) if(format.value) require(value!=null || labelSymbol!=null) {"missing a value or labelsymbol"}
throw IllegalArgumentException("missing a value or labelsymbol") require(fpReg1==null && fpReg2==null) {"integer point instruction can't use floating point registers"}
if (fpReg1 != null || fpReg2 != null)
throw IllegalArgumentException("integer point instruction can't use floating point registers")
} }
reg1direction = format.reg1direction reg1direction = format.reg1direction
@ -498,9 +480,10 @@ data class IRInstruction(
Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS, Opcode.SEQ, Opcode.SNE, Opcode.SLT, Opcode.SLTS,
Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES, Opcode.SGT, Opcode.SGTS, Opcode.SLE, Opcode.SLES,
Opcode.SGE, Opcode.SGES)) { Opcode.SGE, Opcode.SGES)) {
if((type==VmDataType.FLOAT && fpReg1==fpReg2) || reg1==reg2) { if(type==VmDataType.FLOAT)
throw IllegalArgumentException("$opcode: reg1 and reg2 should be different") require(fpReg1!=fpReg2) {"$opcode: fpReg1 and fpReg2 should be different"}
} else
require(reg1!=reg2) {"$opcode: reg1 and reg2 should be different"}
} }
} }

View File

@ -55,8 +55,7 @@ class IRProgram(val name: String,
fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines) fun addGlobalInits(chunk: IRCodeChunk) = globalInits.addAll(chunk.lines)
fun addBlock(block: IRBlock) { fun addBlock(block: IRBlock) {
if(blocks.any { it.name==block.name }) require(blocks.all { it.name != block.name}) { "duplicate block ${block.name} ${block.position}" }
throw IllegalArgumentException("duplicate block ${block.name} ${block.position}")
blocks.add(block) blocks.add(block)
} }
} }
@ -94,16 +93,12 @@ class IRSubroutine(val name: String,
val chunks = mutableListOf<IRCodeChunkBase>() val chunks = mutableListOf<IRCodeChunkBase>()
init { init {
if(!name.contains('.')) require('.' in name) {"subroutine name is not scoped: $name"}
throw IllegalArgumentException("subroutine name is not scoped: $name") require(!name.startsWith("main.main.")) {"subroutine name invalid main prefix: $name"}
if(name.startsWith("main.main."))
throw IllegalArgumentException("subroutine name invalid main prefix: $name")
// params and return value should not be str // params and return value should not be str
if(parameters.any{ it.dt !in NumericDatatypes }) require(parameters.all{ it.dt in NumericDatatypes }) {"non-numeric parameter"}
throw IllegalArgumentException("non-numeric parameter") require(returnType==null || returnType in NumericDatatypes) {"non-numeric returntype $returnType"}
if(returnType!=null && returnType !in NumericDatatypes)
throw IllegalArgumentException("non-numeric returntype $returnType")
} }
operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk } operator fun plusAssign(chunk: IRCodeChunkBase) { chunks+= chunk }
@ -117,10 +112,8 @@ class IRAsmSubroutine(val name: String,
val returns: List<Pair<DataType, RegisterOrStatusflag>>, val returns: List<Pair<DataType, RegisterOrStatusflag>>,
val assembly: String) { val assembly: String) {
init { init {
if(!name.contains('.')) require('.' in name) { "subroutine name is not scoped: $name" }
throw IllegalArgumentException("subroutine name is not scoped: $name") require(!name.startsWith("main.main.")) { "subroutine name invalid main prefix: $name" }
if(name.startsWith("main.main."))
throw IllegalArgumentException("subroutine name invalid main prefix: $name")
} }
} }

View File

@ -79,7 +79,7 @@ class TestInstructions: FunSpec({
} }
test("missing registers should fail") { test("missing registers should fail") {
shouldThrowWithMessage<IllegalArgumentException>("missing a register (int)") { shouldThrowWithMessage<IllegalArgumentException>("missing reg1") {
IRInstruction(Opcode.BZ, VmDataType.BYTE, value=99) IRInstruction(Opcode.BZ, VmDataType.BYTE, value=99)
} }
} }

View File

@ -45,8 +45,7 @@ class VirtualMachine(irProgram: IRProgram) {
init { init {
program = VmProgramLoader().load(irProgram, memory).toTypedArray() program = VmProgramLoader().load(irProgram, memory).toTypedArray()
if(program.size>65536) require(program.size<=65536) {"program cannot contain more than 65536 instructions"}
throw IllegalArgumentException("program cannot contain more than 65536 instructions")
cx16virtualregsBaseAddress = (irProgram.st.lookup("cx16.r0") as? StMemVar)?.address?.toInt() ?: 0xff02 cx16virtualregsBaseAddress = (irProgram.st.lookup("cx16.r0") as? StMemVar)?.address?.toInt() ?: 0xff02
} }