mirror of
https://github.com/irmen/prog8.git
synced 2024-10-18 01:24:51 +00:00
made more opcodes type-specific (will be needed for assembly generation later)
This commit is contained in:
parent
4501276217
commit
d2ffb1063b
@ -299,6 +299,107 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePush(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.BYTE -> Opcode.PUSH
|
||||
DataType.WORD -> Opcode.PUSH_W
|
||||
DataType.FLOAT -> Opcode.PUSH_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePushvar(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.BYTE -> Opcode.PUSH_VAR
|
||||
DataType.WORD -> Opcode.PUSH_VAR_W
|
||||
DataType.FLOAT -> Opcode.PUSH_VAR_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePushvar(reg: Register): Opcode {
|
||||
return when(reg) {
|
||||
Register.A, Register.X, Register.Y -> Opcode.PUSH_VAR
|
||||
Register.AX, Register.AY, Register.XY -> Opcode.PUSH_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePopvar(reg: Register): Opcode {
|
||||
return when(reg) {
|
||||
Register.A, Register.X, Register.Y -> Opcode.POP_VAR
|
||||
Register.AX, Register.AY, Register.XY -> Opcode.POP_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeReadindexedvar(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.ARRAY -> Opcode.READ_INDEXED_VAR
|
||||
DataType.ARRAY_W -> Opcode.READ_INDEXED_VAR_W
|
||||
DataType.ARRAY_F -> Opcode.READ_INDEXED_VAR_F
|
||||
else -> throw CompilerException("invalid dt for indexed $dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeWriteindexedvar(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.ARRAY -> Opcode.WRITE_INDEXED_VAR
|
||||
DataType.ARRAY_W -> Opcode.WRITE_INDEXED_VAR_W
|
||||
DataType.ARRAY_F -> Opcode.WRITE_INDEXED_VAR_F
|
||||
else -> throw CompilerException("invalid dt for indexed $dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeDiscard(dt: DataType): Opcode {
|
||||
return when(dt) {
|
||||
DataType.BYTE -> Opcode.DISCARD
|
||||
DataType.WORD -> Opcode.DISCARD_W
|
||||
DataType.FLOAT -> Opcode.DISCARD_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.DISCARD_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodePopvar(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.BYTE -> Opcode.POP_VAR
|
||||
DataType.WORD -> Opcode.POP_VAR_W
|
||||
DataType.FLOAT -> Opcode.POP_VAR_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.POP_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeDecvar(reg: Register): Opcode {
|
||||
return when(reg) {
|
||||
Register.A, Register.X, Register.Y -> Opcode.DEC_VAR
|
||||
Register.AX, Register.AY, Register.XY -> Opcode.DEC_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeIncvar(reg: Register): Opcode {
|
||||
return when(reg) {
|
||||
Register.A, Register.X, Register.Y -> Opcode.INC_VAR
|
||||
Register.AX, Register.AY, Register.XY -> Opcode.INC_VAR_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeDecvar(dt: DataType): Opcode {
|
||||
return when(dt) {
|
||||
DataType.BYTE -> Opcode.DEC_VAR
|
||||
DataType.WORD -> Opcode.DEC_VAR_W
|
||||
else -> throw CompilerException("can't dec type $dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun opcodeIncvar(dt: DataType): Opcode {
|
||||
return when(dt) {
|
||||
DataType.BYTE -> Opcode.INC_VAR
|
||||
DataType.WORD -> Opcode.INC_VAR_W
|
||||
else -> throw CompilerException("can't inc type $dt")
|
||||
}
|
||||
}
|
||||
|
||||
private fun translate(stmt: Continue) {
|
||||
stackvmProg.line(stmt.position)
|
||||
@ -413,7 +514,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
|
||||
private fun translate(expr: IExpression) {
|
||||
when(expr) {
|
||||
is RegisterExpr -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = expr.register.toString())
|
||||
is RegisterExpr -> {
|
||||
val opcode = opcodePushvar(expr.register)
|
||||
stackvmProg.instr(opcode, callLabel = expr.register.toString())
|
||||
}
|
||||
is PrefixExpression -> {
|
||||
translate(expr.expression)
|
||||
translatePrefixOperator(expr.operator)
|
||||
@ -447,17 +551,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
val lv = expr.constValue(namespace, heap) ?: throw CompilerException("constant expression required, not $expr")
|
||||
when(lv.type) {
|
||||
DataType.BYTE -> stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, lv.bytevalue!!))
|
||||
DataType.WORD -> stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, lv.wordvalue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH, Value(DataType.FLOAT, lv.floatvalue!!))
|
||||
DataType.WORD -> stackvmProg.instr(Opcode.PUSH_W, Value(DataType.WORD, lv.wordvalue!!))
|
||||
DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH_F, Value(DataType.FLOAT, lv.floatvalue!!))
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
stackvmProg.instr(Opcode.PUSH_W, Value(lv.type, lv.heapId))
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
stackvmProg.instr(Opcode.PUSH_W, Value(lv.type, lv.heapId))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -469,8 +573,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
when (target) {
|
||||
is VarDecl -> {
|
||||
when (target.type) {
|
||||
VarDeclType.VAR ->
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
|
||||
VarDeclType.VAR -> {
|
||||
val opcode = opcodePushvar(target.datatype)
|
||||
stackvmProg.instr(opcode, callLabel = target.scopedname)
|
||||
}
|
||||
VarDeclType.CONST ->
|
||||
throw CompilerException("const ref should have been const-folded away")
|
||||
VarDeclType.MEMORY -> {
|
||||
@ -504,8 +610,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
is Subroutine -> {
|
||||
translateSubroutineCall(targetStmt, stmt.arglist)
|
||||
// make sure we clean up the unused result values from the stack.
|
||||
for(rv in targetStmt.returnvalues)
|
||||
stackvmProg.instr(Opcode.DISCARD)
|
||||
for(rv in targetStmt.returnvalues) {
|
||||
val opcode=opcodeDiscard(rv)
|
||||
stackvmProg.instr(opcode)
|
||||
}
|
||||
}
|
||||
else ->
|
||||
throw AstException("invalid call target node type: ${targetStmt::class}")
|
||||
@ -545,7 +653,8 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
// evaluate the arguments and assign them into the subroutine's argument variables.
|
||||
for(arg in arguments.zip(subroutine.parameters)) {
|
||||
translate(arg.first)
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = subroutine.scopedname+"."+arg.second.name)
|
||||
val opcode=opcodePopvar(arg.second.type)
|
||||
stackvmProg.instr(opcode, callLabel = subroutine.scopedname+"."+arg.second.name)
|
||||
}
|
||||
stackvmProg.instr(Opcode.CALL, callLabel=subroutine.scopedname)
|
||||
}
|
||||
@ -612,12 +721,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
}
|
||||
|
||||
if(write)
|
||||
stackvmProg.instr(Opcode.WRITE_INDEXED_VAR, callLabel = variableName)
|
||||
stackvmProg.instr(opcodeWriteindexedvar(variable!!.datatype), callLabel = variableName)
|
||||
else
|
||||
stackvmProg.instr(Opcode.READ_INDEXED_VAR, callLabel = variableName)
|
||||
stackvmProg.instr(opcodeReadindexedvar(variable!!.datatype), callLabel = variableName)
|
||||
}
|
||||
|
||||
|
||||
private fun createSyscall(funcname: String) {
|
||||
val function = (
|
||||
if (funcname.startsWith("_vm_"))
|
||||
@ -653,20 +761,22 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
stackvmProg.line(stmt.position)
|
||||
when {
|
||||
stmt.target.register!=null -> when(stmt.operator) {
|
||||
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = stmt.target.register.toString())
|
||||
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = stmt.target.register.toString())
|
||||
"++" -> stackvmProg.instr(opcodeIncvar(stmt.target.register!!), callLabel = stmt.target.register.toString())
|
||||
"--" -> stackvmProg.instr(opcodeDecvar(stmt.target.register!!), callLabel = stmt.target.register.toString())
|
||||
}
|
||||
stmt.target.identifier!=null -> {
|
||||
val targetStatement = stmt.target.identifier!!.targetStatement(namespace) as VarDecl
|
||||
when(stmt.operator) {
|
||||
"++" -> stackvmProg.instr(Opcode.INC_VAR, callLabel = targetStatement.scopedname)
|
||||
"--" -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = targetStatement.scopedname)
|
||||
"++" -> stackvmProg.instr(opcodeIncvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
|
||||
"--" -> stackvmProg.instr(opcodeDecvar(targetStatement.datatype), callLabel = targetStatement.scopedname)
|
||||
}
|
||||
}
|
||||
stmt.target.arrayindexed!=null -> {
|
||||
// todo: generate more efficient bytecode for this?
|
||||
translate(stmt.target.arrayindexed!!, false)
|
||||
stackvmProg.instr(Opcode.PUSH, Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1))
|
||||
val one = Value(stmt.target.arrayindexed!!.resultingDatatype(namespace, heap)!!, 1)
|
||||
val opcode = opcodePush(one.type)
|
||||
stackvmProg.instr(opcode, one)
|
||||
when(stmt.operator) {
|
||||
"++" -> stackvmProg.instr(Opcode.ADD)
|
||||
"--" -> stackvmProg.instr(Opcode.SUB)
|
||||
@ -711,11 +821,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
stmt.target.identifier!=null -> {
|
||||
val target = stmt.target.identifier!!.targetStatement(namespace)!!
|
||||
when(target) {
|
||||
is VarDecl -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = target.scopedname)
|
||||
is VarDecl -> {
|
||||
val opcode = opcodePushvar(stmt.target.determineDatatype(namespace, heap, stmt))
|
||||
stackvmProg.instr(opcode, callLabel = target.scopedname)
|
||||
}
|
||||
else -> throw CompilerException("invalid assignment target type ${target::class}")
|
||||
}
|
||||
}
|
||||
stmt.target.register!=null -> stackvmProg.instr(Opcode.PUSH_VAR, callLabel = stmt.target.register.toString())
|
||||
stmt.target.register!=null -> {
|
||||
val opcode= opcodePushvar(stmt.target.register!!)
|
||||
stackvmProg.instr(opcode, callLabel = stmt.target.register.toString())
|
||||
}
|
||||
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
|
||||
}
|
||||
|
||||
@ -727,11 +843,17 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
stmt.target.identifier!=null -> {
|
||||
val target = stmt.target.identifier!!.targetStatement(namespace)!!
|
||||
when(target) {
|
||||
is VarDecl -> stackvmProg.instr(Opcode.POP_VAR, callLabel = target.scopedname)
|
||||
is VarDecl -> {
|
||||
val opcode = opcodePopvar(stmt.target.determineDatatype(namespace, heap, stmt))
|
||||
stackvmProg.instr(opcode, callLabel = target.scopedname)
|
||||
}
|
||||
else -> throw CompilerException("invalid assignment target type ${target::class}")
|
||||
}
|
||||
}
|
||||
stmt.target.register!=null -> stackvmProg.instr(Opcode.POP_VAR, callLabel = stmt.target.register.toString())
|
||||
stmt.target.register!=null -> {
|
||||
val opcode=opcodePopvar(stmt.target.register!!)
|
||||
stackvmProg.instr(opcode, callLabel = stmt.target.register.toString())
|
||||
}
|
||||
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, true) // write value to it
|
||||
}
|
||||
}
|
||||
@ -835,13 +957,13 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
}
|
||||
}
|
||||
|
||||
private fun translateForOverIterableVar(loop: ForLoop, varDt: DataType, iterableValue: LiteralValue) {
|
||||
if(varDt==DataType.BYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.MATRIX))
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (byte)")
|
||||
else if(varDt==DataType.WORD && iterableValue.type != DataType.ARRAY_W)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (word)")
|
||||
else if(varDt==DataType.FLOAT && iterableValue.type != DataType.ARRAY_F)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type (float)")
|
||||
private fun translateForOverIterableVar(loop: ForLoop, loopvarDt: DataType, iterableValue: LiteralValue) {
|
||||
if(loopvarDt==DataType.BYTE && iterableValue.type !in setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.MATRIX))
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type")
|
||||
else if(loopvarDt==DataType.WORD && iterableValue.type != DataType.ARRAY_W)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type")
|
||||
else if(loopvarDt==DataType.FLOAT && iterableValue.type != DataType.ARRAY_F)
|
||||
throw CompilerException("loop variable type doesn't match iterableValue type")
|
||||
val numElements: Int
|
||||
val indexVar: String
|
||||
when(iterableValue.type) {
|
||||
@ -893,8 +1015,9 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
stackvmProg.instr(Opcode.PUSH, Value(if(numElements<=255) DataType.BYTE else DataType.WORD, 0))
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = indexVar)
|
||||
val zero = Value(if(numElements<=255) DataType.BYTE else DataType.WORD, 0)
|
||||
stackvmProg.instr(opcodePush(zero.type), zero)
|
||||
stackvmProg.instr(opcodePopvar(zero.type), callLabel = indexVar)
|
||||
stackvmProg.label(loopLabel)
|
||||
val assignTarget = if(loop.loopRegister!=null)
|
||||
AssignTarget(loop.loopRegister, null, null, loop.position)
|
||||
@ -906,11 +1029,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
translate(assignLv)
|
||||
translate(loop.body)
|
||||
stackvmProg.label(continueLabel)
|
||||
stackvmProg.instr(Opcode.INC_VAR, callLabel = indexVar)
|
||||
stackvmProg.instr(opcodeIncvar(zero.type), callLabel = indexVar)
|
||||
|
||||
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value.
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, numElements))
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = indexVar)
|
||||
stackvmProg.instr(opcodePush(zero.type), Value(zero.type, numElements))
|
||||
stackvmProg.instr(opcodePushvar(zero.type), callLabel = indexVar)
|
||||
stackvmProg.instr(Opcode.SUB)
|
||||
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
|
||||
@ -948,31 +1071,31 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
continueStmtLabelStack.push(continueLabel)
|
||||
breakStmtLabelStack.push(breakLabel)
|
||||
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.first))
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname)
|
||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.first))
|
||||
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
||||
stackvmProg.label(loopLabel)
|
||||
translate(body)
|
||||
stackvmProg.label(continueLabel)
|
||||
when {
|
||||
range.step==1 -> stackvmProg.instr(Opcode.INC_VAR, callLabel = varname)
|
||||
range.step==-1 -> stackvmProg.instr(Opcode.DEC_VAR, callLabel = varname)
|
||||
range.step==1 -> stackvmProg.instr(opcodeIncvar(varDt), callLabel = varname)
|
||||
range.step==-1 -> stackvmProg.instr(opcodeDecvar(varDt), callLabel = varname)
|
||||
range.step>1 -> {
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname)
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.step))
|
||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.step))
|
||||
stackvmProg.instr(Opcode.ADD)
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname)
|
||||
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
||||
}
|
||||
range.step<1 -> {
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname)
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, abs(range.step)))
|
||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, abs(range.step)))
|
||||
stackvmProg.instr(Opcode.SUB)
|
||||
stackvmProg.instr(Opcode.POP_VAR, callLabel = varname)
|
||||
stackvmProg.instr(opcodePopvar(varDt), callLabel = varname)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: optimize edge cases if last value = 255 or 0 (for bytes) etc. to avoid PUSH / SUB opcodes and make use of the wrapping around of the value.
|
||||
stackvmProg.instr(Opcode.PUSH, Value(varDt, range.last+range.step))
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel = varname)
|
||||
stackvmProg.instr(opcodePush(varDt), Value(varDt, range.last+range.step))
|
||||
stackvmProg.instr(opcodePushvar(varDt), callLabel = varname)
|
||||
stackvmProg.instr(Opcode.SUB)
|
||||
stackvmProg.instr(Opcode.BNZ, callLabel = loopLabel)
|
||||
|
||||
@ -1083,9 +1206,11 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
||||
postIncr.linkParents(range.parent)
|
||||
translate(postIncr)
|
||||
if(lvTarget.register!=null)
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel =lvTarget.register.toString())
|
||||
else
|
||||
stackvmProg.instr(Opcode.PUSH_VAR, callLabel =targetStatement!!.scopedname)
|
||||
stackvmProg.instr(opcodePushvar(lvTarget.register), callLabel =lvTarget.register.toString())
|
||||
else {
|
||||
val opcode = opcodePushvar(targetStatement!!.datatype)
|
||||
stackvmProg.instr(opcode, callLabel = targetStatement.scopedname)
|
||||
}
|
||||
val branch = BranchStatement(
|
||||
BranchCondition.NZ,
|
||||
listOf(Jump(null, null, loopLabel, range.position)),
|
||||
|
@ -104,10 +104,7 @@ class Program (val name: String,
|
||||
Instruction(opcode, callLabel = args)
|
||||
}
|
||||
}
|
||||
Opcode.INC_VAR, Opcode.DEC_VAR,
|
||||
Opcode.SHR_VAR, Opcode.SHL_VAR, Opcode.ROL_VAR, Opcode.ROR_VAR,
|
||||
Opcode.ROL2_VAR, Opcode.ROR2_VAR, Opcode.POP_VAR, Opcode.PUSH_VAR,
|
||||
Opcode.READ_INDEXED_VAR, Opcode.WRITE_INDEXED_VAR -> {
|
||||
in opcodesWithVarArgument -> {
|
||||
val withoutQuotes =
|
||||
if(args!!.startsWith('"') && args.endsWith('"'))
|
||||
args.substring(1, args.length-1) else args
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -113,9 +113,18 @@ class TestStackVmOpcodes {
|
||||
assertFalse(vm.P_irqd)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPushWrongDt() {
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH, Value(DataType.WORD, 4299)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertFailsWith<VmExecutionException> {
|
||||
vm.step(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPush() {
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)))
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.999)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(1)
|
||||
@ -151,7 +160,7 @@ class TestStackVmOpcodes {
|
||||
|
||||
@Test
|
||||
fun testPushVar() {
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH_VAR, callLabel = "varname"))
|
||||
val ins = mutableListOf(Instruction(Opcode.PUSH_VAR_F, callLabel = "varname"))
|
||||
vm.load(makeProg(ins, mapOf("varname" to Value(DataType.FLOAT, 42.999))), null)
|
||||
assertEquals(7, vm.variables.size)
|
||||
assertTrue(vm.variables.containsKey("varname"))
|
||||
@ -165,40 +174,12 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.FLOAT, 42.999), vm.variables["varname"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDup() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)),
|
||||
Instruction(Opcode.DUP))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(2)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.FLOAT, 42.999), vm.evalstack.pop())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSwap() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 9999)),
|
||||
Instruction(Opcode.SWAP)
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(3)
|
||||
assertEquals(2, vm.evalstack.size)
|
||||
assertEquals(Value(DataType.BYTE, 123), vm.evalstack.pop())
|
||||
assertEquals(Value(DataType.WORD, 9999), vm.evalstack.pop())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDiscard() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.999)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 3.1415)),
|
||||
Instruction(Opcode.DISCARD))
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.999)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 3.1415)),
|
||||
Instruction(Opcode.DISCARD_F))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertThat(vm.evalstack, empty())
|
||||
vm.step(2)
|
||||
@ -211,12 +192,12 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testPopMem() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.25)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.25)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x2000)),
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM, Value(DataType.WORD, 0x4000)))
|
||||
Instruction(Opcode.POP_MEM_W, Value(DataType.WORD, 0x3000)),
|
||||
Instruction(Opcode.POP_MEM_F, Value(DataType.WORD, 0x4000)))
|
||||
vm.load(makeProg(ins), null)
|
||||
assertEquals(0, vm.mem.getWord(0x2000))
|
||||
assertEquals(0, vm.mem.getWord(0x3000))
|
||||
@ -233,12 +214,12 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testPopVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 42.25)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 42.25)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
|
||||
Instruction(Opcode.POP_VAR, callLabel = "var1"),
|
||||
Instruction(Opcode.POP_VAR, callLabel = "var2"),
|
||||
Instruction(Opcode.POP_VAR, callLabel = "var3"))
|
||||
Instruction(Opcode.POP_VAR_W, callLabel = "var2"),
|
||||
Instruction(Opcode.POP_VAR_F, callLabel = "var3"))
|
||||
val vars = mapOf(
|
||||
"var1" to Value(DataType.BYTE, 0),
|
||||
"var2" to Value(DataType.WORD, 0),
|
||||
@ -252,8 +233,8 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.FLOAT, 42.25), vm.variables["var3"])
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.POP_VAR, callLabel = "var1"))
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0x42ea)),
|
||||
Instruction(Opcode.POP_VAR_W, callLabel = "var1"))
|
||||
val vars2 = mapOf(
|
||||
"var1" to Value(DataType.BYTE, 0)
|
||||
)
|
||||
@ -505,65 +486,89 @@ class TestStackVmOpcodes {
|
||||
Value(DataType.BYTE, 20))
|
||||
val expected = listOf(
|
||||
Value(DataType.BYTE, 0),
|
||||
Value(DataType.BYTE, 1),
|
||||
Value(DataType.BYTE, 0),
|
||||
Value(DataType.BYTE, 1),
|
||||
Value(DataType.BYTE, 0),
|
||||
Value(DataType.BYTE, 1),
|
||||
Value(DataType.BYTE, 0),
|
||||
Value(DataType.BYTE, 1),
|
||||
Value(DataType.BYTE, 0)
|
||||
)
|
||||
val operator = Opcode.NOT
|
||||
|
||||
testUnaryOperator(values, operator, expected)
|
||||
testUnaryOperator(values, operator, expected, listOf(DataType.BYTE, DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE,DataType.BYTE))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInc() {
|
||||
val values = listOf(
|
||||
Value(DataType.FLOAT, 2022.5),
|
||||
Value(DataType.WORD, 65535),
|
||||
Value(DataType.WORD, 999),
|
||||
Value(DataType.BYTE, 255),
|
||||
Value(DataType.BYTE, 99)
|
||||
)
|
||||
val expected = listOf(
|
||||
Value(DataType.BYTE, 100),
|
||||
Value(DataType.BYTE, 0),
|
||||
Value(DataType.WORD, 1000),
|
||||
Value(DataType.BYTE, 100)
|
||||
)
|
||||
testUnaryOperator(values, Opcode.INC, expected)
|
||||
|
||||
val valuesw = listOf(
|
||||
Value(DataType.WORD, 65535),
|
||||
Value(DataType.WORD, 999)
|
||||
)
|
||||
val expectedw = listOf(
|
||||
Value(DataType.WORD, 0),
|
||||
Value(DataType.WORD, 1000)
|
||||
)
|
||||
testUnaryOperator(valuesw, Opcode.INC_W, expectedw)
|
||||
|
||||
val valuesf = listOf(
|
||||
Value(DataType.FLOAT, -1.0),
|
||||
Value(DataType.FLOAT, 2022.5)
|
||||
)
|
||||
val expectedf = listOf(
|
||||
Value(DataType.FLOAT, 0.0),
|
||||
Value(DataType.FLOAT, 2023.5)
|
||||
)
|
||||
val operator = Opcode.INC
|
||||
testUnaryOperator(values, operator, expected)
|
||||
testUnaryOperator(valuesf, Opcode.INC_F, expectedf)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDec() {
|
||||
val values = listOf(
|
||||
Value(DataType.FLOAT, 0.5),
|
||||
Value(DataType.FLOAT, 123.456),
|
||||
Value(DataType.WORD, 1000),
|
||||
Value(DataType.WORD, 0),
|
||||
Value(DataType.BYTE, 100),
|
||||
Value(DataType.BYTE, 0)
|
||||
)
|
||||
val expected = listOf(
|
||||
Value(DataType.BYTE, 255),
|
||||
Value(DataType.BYTE, 99),
|
||||
Value(DataType.WORD, 65535),
|
||||
Value(DataType.WORD, 999),
|
||||
Value(DataType.FLOAT, 122.456),
|
||||
Value(DataType.FLOAT, -0.5)
|
||||
Value(DataType.BYTE, 255)
|
||||
)
|
||||
val operator = Opcode.DEC
|
||||
testUnaryOperator(values, operator, expected)
|
||||
testUnaryOperator(values, Opcode.DEC, expected)
|
||||
|
||||
val valuesw = listOf(
|
||||
Value(DataType.WORD, 1000),
|
||||
Value(DataType.WORD, 0)
|
||||
)
|
||||
val expectedw = listOf(
|
||||
Value(DataType.WORD, 999),
|
||||
Value(DataType.WORD, 65535)
|
||||
)
|
||||
testUnaryOperator(valuesw, Opcode.DEC_W, expectedw)
|
||||
|
||||
val valuesf = listOf(
|
||||
Value(DataType.FLOAT, 0.5),
|
||||
Value(DataType.FLOAT, 123.456)
|
||||
)
|
||||
val expectedf = listOf(
|
||||
Value(DataType.FLOAT, -0.5),
|
||||
Value(DataType.FLOAT, 122.456)
|
||||
)
|
||||
testUnaryOperator(valuesf, Opcode.DEC_F, expectedf)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNeg() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 123.456)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 123.456)),
|
||||
Instruction(Opcode.NEG),
|
||||
Instruction(Opcode.NEG)
|
||||
)
|
||||
@ -577,7 +582,7 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.FLOAT, 123.456), vm.evalstack.peek())
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 1234)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1234)),
|
||||
Instruction(Opcode.NEG)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
@ -597,7 +602,7 @@ class TestStackVmOpcodes {
|
||||
fun testInv() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 4044)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 4044)),
|
||||
Instruction(Opcode.INV),
|
||||
Instruction(Opcode.INV),
|
||||
Instruction(Opcode.INV)
|
||||
@ -612,7 +617,7 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.BYTE, 0x84), vm.evalstack.pop())
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1234.33)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.FLOAT, 1234.33)), // todo should crash
|
||||
Instruction(Opcode.INV)
|
||||
)
|
||||
vm.load(makeProg(ins2), null)
|
||||
@ -624,9 +629,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testLsb() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1.23)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 1.23)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.LSB),
|
||||
Instruction(Opcode.LSB),
|
||||
Instruction(Opcode.LSB)
|
||||
@ -644,9 +649,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testMsb() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 1.23)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 1.23)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.MSB),
|
||||
Instruction(Opcode.MSB),
|
||||
Instruction(Opcode.MSB)
|
||||
@ -664,7 +669,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testB2Word() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
|
||||
Instruction(Opcode.B2WORD),
|
||||
Instruction(Opcode.B2WORD)
|
||||
@ -680,7 +685,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testMSB2Word() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 0x45)),
|
||||
Instruction(Opcode.MSB2WORD),
|
||||
Instruction(Opcode.MSB2WORD)
|
||||
@ -696,7 +701,7 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testB2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0xea31)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 123)),
|
||||
Instruction(Opcode.B2FLOAT),
|
||||
Instruction(Opcode.B2FLOAT)
|
||||
@ -713,7 +718,7 @@ class TestStackVmOpcodes {
|
||||
fun testW2Float() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 11)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 12345)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 12345)),
|
||||
Instruction(Opcode.W2FLOAT),
|
||||
Instruction(Opcode.W2FLOAT)
|
||||
)
|
||||
@ -725,76 +730,54 @@ class TestStackVmOpcodes {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIncMemAndIncMemW() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.INC_MEM, Value(DataType.WORD, 0x2000)),
|
||||
Instruction(Opcode.INC_MEM, Value(DataType.WORD, 0x2001)),
|
||||
Instruction(Opcode.INC_MEM_W, Value(DataType.WORD, 0x3000)),
|
||||
Instruction(Opcode.INC_MEM_W, Value(DataType.WORD, 0x3002))
|
||||
)
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 255)),
|
||||
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0xffff)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
vm.step(4)
|
||||
assertEquals(101, vm.mem.getByte(0x2000))
|
||||
assertEquals(0, vm.mem.getByte(0x2001))
|
||||
assertEquals(0x42eb, vm.mem.getWord(0x3000))
|
||||
assertEquals(0, vm.mem.getWord(0x3002))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIncVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.INC_VAR, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR_W, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR, callLabel ="var2"),
|
||||
Instruction(Opcode.INC_VAR, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR, callLabel ="var2"))
|
||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3"),
|
||||
Instruction(Opcode.INC_VAR_W, callLabel ="var1"),
|
||||
Instruction(Opcode.INC_VAR, callLabel ="var2"),
|
||||
Instruction(Opcode.INC_VAR_F, callLabel ="var3")
|
||||
)
|
||||
val vars = mapOf("var1" to Value(DataType.WORD, 65534),
|
||||
"var2" to Value(DataType.BYTE, 254))
|
||||
"var2" to Value(DataType.BYTE, 254),
|
||||
"var3" to Value(DataType.FLOAT, -1.5)
|
||||
)
|
||||
vm.load(makeProg(ins, vars = vars), null)
|
||||
vm.step(2)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"])
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"])
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"])
|
||||
assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDecVar() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.DEC_VAR, callLabel = "var1"),
|
||||
Instruction(Opcode.DEC_VAR_W, callLabel = "var1"),
|
||||
Instruction(Opcode.DEC_VAR, callLabel = "var2"),
|
||||
Instruction(Opcode.DEC_VAR, callLabel = "var1"),
|
||||
Instruction(Opcode.DEC_VAR, callLabel = "var2"))
|
||||
Instruction(Opcode.DEC_VAR_F, callLabel = "var3"),
|
||||
Instruction(Opcode.DEC_VAR_W, callLabel = "var1"),
|
||||
Instruction(Opcode.DEC_VAR, callLabel = "var2"),
|
||||
Instruction(Opcode.DEC_VAR_F, callLabel = "var3")
|
||||
)
|
||||
val vars = mapOf("var1" to Value(DataType.WORD,1),
|
||||
"var2" to Value(DataType.BYTE, 1))
|
||||
"var2" to Value(DataType.BYTE, 1),
|
||||
"var3" to Value(DataType.FLOAT, 1.5)
|
||||
)
|
||||
vm.load(makeProg(ins, vars = vars), null)
|
||||
vm.step(2)
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 0), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 0), vm.variables["var2"])
|
||||
vm.step(2)
|
||||
assertEquals(Value(DataType.FLOAT, 0.5), vm.variables["var3"])
|
||||
vm.step(3)
|
||||
assertEquals(Value(DataType.WORD, 65535), vm.variables["var1"])
|
||||
assertEquals(Value(DataType.BYTE, 255), vm.variables["var2"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDecMemAndDecMemW() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.DEC_MEM, Value(DataType.WORD, 0x2000)),
|
||||
Instruction(Opcode.DEC_MEM, Value(DataType.WORD, 0x2001)),
|
||||
Instruction(Opcode.DEC_MEM_W, Value(DataType.WORD, 0x3000)),
|
||||
Instruction(Opcode.DEC_MEM_W, Value(DataType.WORD, 0x3002))
|
||||
)
|
||||
val mem=mapOf(0x2000 to listOf(Value(DataType.BYTE, 100), Value(DataType.BYTE, 0)),
|
||||
0x3000 to listOf(Value(DataType.WORD, 0x42ea), Value(DataType.WORD, 0)))
|
||||
vm.load(makeProg(ins, mem=mem), null)
|
||||
vm.step(4)
|
||||
assertEquals(99, vm.mem.getByte(0x2000))
|
||||
assertEquals(255, vm.mem.getByte(0x2001))
|
||||
assertEquals(0x42e9, vm.mem.getWord(0x3000))
|
||||
assertEquals(65535, vm.mem.getWord(0x3002))
|
||||
assertEquals(Value(DataType.FLOAT, -0.5), vm.variables["var3"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -805,7 +788,7 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)),
|
||||
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_RND.callNr)),
|
||||
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 25544)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 25544)),
|
||||
Instruction(Opcode.SYSCALL, Value(DataType.BYTE, Syscall.FUNC_SIN.callNr))
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
@ -1050,9 +1033,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testBZ() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.BZ, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.BZ, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
@ -1070,9 +1053,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testBNZ() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.BNZ, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.BNZ, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
@ -1090,11 +1073,11 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testBNEG() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 1)),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.BNEG, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
@ -1114,9 +1097,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testBPOS() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, -99)),
|
||||
Instruction(Opcode.BPOS, callLabel = "label"),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0)),
|
||||
Instruction(Opcode.BPOS, callLabel = "label"),
|
||||
Instruction(Opcode.LINE, callLabel = "string1"),
|
||||
Instruction(Opcode.TERMINATE),
|
||||
@ -1195,9 +1178,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testSHR() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 9.99)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 3)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 61005)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 9.99)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 3)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 61005)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)),
|
||||
Instruction(Opcode.SHR), // 124
|
||||
@ -1207,12 +1190,12 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.SHR), // 0
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHR), // 30502
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.DISCARD_W),
|
||||
Instruction(Opcode.SHR), // 1
|
||||
Instruction(Opcode.SHR), // 0
|
||||
Instruction(Opcode.SHR), // 0
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHR) // error
|
||||
Instruction(Opcode.DISCARD_W),
|
||||
Instruction(Opcode.SHR) // error on float
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(6)
|
||||
@ -1237,9 +1220,9 @@ class TestStackVmOpcodes {
|
||||
@Test
|
||||
fun testSHL() {
|
||||
val ins = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.FLOAT, 9.99)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 3)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 61005)),
|
||||
Instruction(Opcode.PUSH_F, Value(DataType.FLOAT, 9.99)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 3)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 61005)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 3)),
|
||||
Instruction(Opcode.PUSH, Value(DataType.BYTE, 249)),
|
||||
Instruction(Opcode.SHL), // 242
|
||||
@ -1247,10 +1230,10 @@ class TestStackVmOpcodes {
|
||||
Instruction(Opcode.SHL), // 6
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHL), // 56474
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.DISCARD_W),
|
||||
Instruction(Opcode.SHL), // 6
|
||||
Instruction(Opcode.DISCARD),
|
||||
Instruction(Opcode.SHL) // error
|
||||
Instruction(Opcode.DISCARD_W),
|
||||
Instruction(Opcode.SHL) // error on float
|
||||
)
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(6)
|
||||
@ -1302,7 +1285,7 @@ class TestStackVmOpcodes {
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.CLC),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.ROR), // 0b0100100110000110 c=1
|
||||
Instruction(Opcode.ROR), // 0b1010010011000011 c=0
|
||||
Instruction(Opcode.ROR),
|
||||
@ -1367,7 +1350,7 @@ class TestStackVmOpcodes {
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.CLC),
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.ROL), // 0b0010011000011010 c=1
|
||||
Instruction(Opcode.ROL), // 0b0100110000110101 c=0
|
||||
Instruction(Opcode.ROL),
|
||||
@ -1424,7 +1407,7 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek())
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.ROR2), // 0b1100100110000110
|
||||
Instruction(Opcode.ROR2), // 0b0110010011000011
|
||||
Instruction(Opcode.ROR2),
|
||||
@ -1476,7 +1459,7 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.BYTE, 0b10010011), vm.evalstack.peek())
|
||||
|
||||
val ins2 = mutableListOf(
|
||||
Instruction(Opcode.PUSH, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.PUSH_W, Value(DataType.WORD, 0b1001001100001101)),
|
||||
Instruction(Opcode.ROL2), // 0b0010011000011011
|
||||
Instruction(Opcode.ROL2), // 0b0100110000110110
|
||||
Instruction(Opcode.ROL2),
|
||||
@ -1505,13 +1488,36 @@ class TestStackVmOpcodes {
|
||||
assertEquals(Value(DataType.WORD, 0b1001001100001101), vm.evalstack.peek())
|
||||
}
|
||||
|
||||
|
||||
private fun discardOpcode(dt: DataType): Opcode {
|
||||
return when(dt) {
|
||||
DataType.BYTE -> Opcode.DISCARD
|
||||
DataType.WORD -> Opcode.DISCARD_W
|
||||
DataType.FLOAT -> Opcode.DISCARD_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.DISCARD_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun pushOpcode(dt: DataType): Opcode {
|
||||
return when (dt) {
|
||||
DataType.BYTE -> Opcode.PUSH
|
||||
DataType.WORD -> Opcode.PUSH_W
|
||||
DataType.FLOAT -> Opcode.PUSH_F
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> Opcode.PUSH_W
|
||||
}
|
||||
}
|
||||
|
||||
private fun testComparisonOperator(values: List<Value>, expected: List<Int>, operator: Opcode) {
|
||||
assertEquals(values.size, expected.size*2)
|
||||
val ins = mutableListOf<Instruction>()
|
||||
val vars = values.iterator()
|
||||
while(vars.hasNext()) {
|
||||
ins.add(Instruction(Opcode.PUSH, vars.next()))
|
||||
ins.add(Instruction(Opcode.PUSH, vars.next()))
|
||||
var nextvar = vars.next()
|
||||
ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
|
||||
nextvar = vars.next()
|
||||
ins.add(Instruction(pushOpcode(nextvar.type), nextvar))
|
||||
ins.add(Instruction(operator))
|
||||
}
|
||||
vm.load(makeProg(ins), null)
|
||||
@ -1524,8 +1530,9 @@ class TestStackVmOpcodes {
|
||||
private fun testBinaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>) {
|
||||
assertEquals(valuesToPush.size, expected.size+1)
|
||||
val ins = mutableListOf<Instruction>()
|
||||
for (value in valuesToPush)
|
||||
ins.add(Instruction(Opcode.PUSH, value))
|
||||
for (value in valuesToPush) {
|
||||
ins.add(Instruction(pushOpcode(value.type), value))
|
||||
}
|
||||
for (i in 1 until valuesToPush.size)
|
||||
ins.add(Instruction(operator))
|
||||
vm.load(makeProg(ins), null)
|
||||
@ -1540,19 +1547,23 @@ class TestStackVmOpcodes {
|
||||
}
|
||||
}
|
||||
|
||||
private fun testUnaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>) {
|
||||
private fun testUnaryOperator(valuesToPush: List<Value>, operator: Opcode, expected: List<Value>, expectedTypes: List<DataType>?=null) {
|
||||
assertEquals(valuesToPush.size, expected.size)
|
||||
val typesExpected = expectedTypes?.reversed() ?: expected.reversed().map{it.type}
|
||||
|
||||
val ins = mutableListOf<Instruction>()
|
||||
for (value in valuesToPush)
|
||||
ins.add(Instruction(Opcode.PUSH, value))
|
||||
for (i in 1..valuesToPush.size) {
|
||||
for (value in valuesToPush) {
|
||||
ins.add(Instruction(pushOpcode(value.type), value))
|
||||
}
|
||||
for (type in typesExpected) {
|
||||
ins.add(Instruction(operator))
|
||||
ins.add(Instruction(Opcode.DISCARD))
|
||||
ins.add(Instruction(discardOpcode(type)))
|
||||
}
|
||||
vm.load(makeProg(ins), null)
|
||||
vm.step(valuesToPush.size)
|
||||
assertEquals(valuesToPush.size, vm.evalstack.size)
|
||||
for (expectedVal in expected) {
|
||||
|
||||
for (expectedVal in expected.reversed()) {
|
||||
vm.step(1)
|
||||
assertEquals(expectedVal, vm.evalstack.peek())
|
||||
vm.step(1)
|
||||
|
Loading…
Reference in New Issue
Block a user