implemented all builtin functions in the AstVm

This commit is contained in:
Irmen de Jong 2019-06-28 00:10:27 +02:00
parent 29b3a7e94e
commit 53a4379c45
6 changed files with 270 additions and 332 deletions

View File

@ -14,6 +14,49 @@ class VmTerminationException(msg: String?) : Exception(msg)
class VmBreakpointException : Exception("breakpoint")
class StatusFlags {
var carry: Boolean = false
var zero: Boolean = true
var negative: Boolean = false
var irqd: Boolean = false
private fun setFlags(value: LiteralValue?) {
if (value != null) {
when (value.type) {
DataType.UBYTE -> {
val v = value.bytevalue!!.toInt()
negative = v > 127
zero = v == 0
}
DataType.BYTE -> {
val v = value.bytevalue!!.toInt()
negative = v < 0
zero = v == 0
}
DataType.UWORD -> {
val v = value.wordvalue!!
negative = v > 32767
zero = v == 0
}
DataType.WORD -> {
val v = value.wordvalue!!
negative = v < 0
zero = v == 0
}
DataType.FLOAT -> {
val flt = value.floatvalue!!
negative = flt < 0.0
zero = flt == 0.0
}
else -> {
// no flags for non-numeric type
}
}
}
}
}
class RuntimeVariables {
fun define(scope: INameScope, name: String, initialValue: RuntimeValue) {
val where = vars.getValue(scope)
@ -53,6 +96,13 @@ class RuntimeVariables {
return address
}
fun swap(a1: VarDecl, a2: VarDecl) {
val v1 = get(a1.definingScope(), a1.name)
val v2 = get(a2.definingScope(), a2.name)
set(a1.definingScope(), a1.name, v2)
set(a2.definingScope(), a2.name, v1)
}
private val vars = mutableMapOf<INameScope, MutableMap<String, RuntimeValue>>().withDefault { mutableMapOf() }
private val memvars = mutableMapOf<INameScope, MutableMap<String, Int>>().withDefault { mutableMapOf() }
}
@ -60,14 +110,8 @@ class RuntimeVariables {
class AstVm(val program: Program) {
val mem = Memory()
var P_carry: Boolean = false
private set
var P_zero: Boolean = true
private set
var P_negative: Boolean = false
private set
var P_irqd: Boolean = false
private set
val statusflags = StatusFlags()
private var dialog = ScreenDialog()
var instructionCounter = 0
@ -135,7 +179,7 @@ class AstVm(val program: Program) {
val idref = IdentifierReference(listOf(arg.first.name), sub.position)
performAssignment(AssignTarget(null, idref, null, null, idref.position),
arg.second, sub.statements.first(),
EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine))
EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine))
}
try {
@ -161,7 +205,7 @@ class AstVm(val program: Program) {
}
private fun executeStatement(sub: INameScope, stmt: IStatement) {
val evalCtx = EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine)
val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
instructionCounter++
if (instructionCounter % 100 == 0)
Thread.sleep(1)
@ -191,8 +235,15 @@ class AstVm(val program: Program) {
}
}
is BuiltinFunctionStatementPlaceholder -> {
val args = evaluate(stmt.arglist)
functions.performBuiltinFunction(target.name, args)
if(target.name=="swap") {
// swap cannot be implemented as a function, so inline it here
val a1 = (stmt.arglist[0] as IdentifierReference).targetVarDecl(program.namespace)!!
val a2 = (stmt.arglist[1] as IdentifierReference).targetVarDecl(program.namespace)!!
runtimeVariables.swap(a1, a2)
} else {
val args = evaluate(stmt.arglist)
functions.performBuiltinFunction(target.name, args, statusflags)
}
}
else -> {
TODO("weird call $target")
@ -394,12 +445,12 @@ class AstVm(val program: Program) {
// assign the new loop value to the loopvar, and run the code
performAssignment(AssignTarget(null, loopVar, null, null, loopVar.position),
RuntimeValue(loopvarDt, loopValue), stmt.body.statements.first(),
EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine))
EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine))
executeAnonymousScope(stmt.body)
}
private fun evaluate(args: List<IExpression>): List<RuntimeValue> {
val ctx = EvalContext(program, mem, runtimeVariables, functions, ::executeSubroutine)
val ctx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
return args.map { evaluate(it, ctx) }
}
@ -420,22 +471,32 @@ class AstVm(val program: Program) {
"c64scr.print_b" -> {
dialog.canvas.printText(args[0].byteval!!.toString(), 1, true)
}
"c64scr.print_ubhex" -> {
val prefix = if (args[0].asBoolean) "$" else ""
val number = args[1].byteval!!
dialog.canvas.printText("$prefix${number.toString(16).padStart(2, '0')}", 1, true)
}
"c64scr.print_uw" -> {
dialog.canvas.printText(args[0].wordval!!.toString(), 1, true)
}
"c64scr.print_w" -> {
dialog.canvas.printText(args[0].wordval!!.toString(), 1, true)
}
"c64scr.print_ubhex" -> {
val prefix = if (args[0].asBoolean) "$" else ""
val number = args[1].byteval!!
dialog.canvas.printText("$prefix${number.toString(16).padStart(2, '0')}", 1, true)
}
"c64scr.print_uwhex" -> {
val prefix = if (args[0].asBoolean) "$" else ""
val number = args[1].wordval!!
dialog.canvas.printText("$prefix${number.toString(16).padStart(4, '0')}", 1, true)
}
"c64scr.print_uwbin" -> {
val prefix = if (args[0].asBoolean) "%" else ""
val number = args[1].wordval!!
dialog.canvas.printText("$prefix${number.toString(2).padStart(16, '0')}", 1, true)
}
"c64scr.print_ubbin" -> {
val prefix = if (args[0].asBoolean) "%" else ""
val number = args[1].byteval!!
dialog.canvas.printText("$prefix${number.toString(2).padStart(8, '0')}", 1, true)
}
"c64.CHROUT" -> {
dialog.canvas.printChar(args[0].byteval!!)
}
@ -445,40 +506,5 @@ class AstVm(val program: Program) {
else -> TODO("syscall ${sub.scopedname} $sub")
}
}
private fun setFlags(value: LiteralValue?) {
if (value != null) {
when (value.type) {
DataType.UBYTE -> {
val v = value.bytevalue!!.toInt()
P_negative = v > 127
P_zero = v == 0
}
DataType.BYTE -> {
val v = value.bytevalue!!.toInt()
P_negative = v < 0
P_zero = v == 0
}
DataType.UWORD -> {
val v = value.wordvalue!!
P_negative = v > 32767
P_zero = v == 0
}
DataType.WORD -> {
val v = value.wordvalue!!
P_negative = v < 0
P_zero = v == 0
}
DataType.FLOAT -> {
val flt = value.floatvalue!!
P_negative = flt < 0.0
P_zero = flt == 0.0
}
else -> {
// no flags for non-numeric type
}
}
}
}
}

View File

@ -2,23 +2,131 @@ package prog8.astvm
import prog8.ast.DataType
import prog8.compiler.RuntimeValue
import java.lang.Math.toDegrees
import java.lang.Math.toRadians
import java.util.*
import kotlin.math.*
import kotlin.random.Random
class BuiltinFunctions {
private val rnd = Random(0)
private val statusFlagsSave = Stack<StatusFlags>()
fun performBuiltinFunction(name: String, args: List<RuntimeValue>): RuntimeValue? {
return when(name) {
fun performBuiltinFunction(name: String, args: List<RuntimeValue>, statusflags: StatusFlags): RuntimeValue? {
return when (name) {
"rnd" -> RuntimeValue(DataType.UBYTE, rnd.nextInt() and 255)
"rndw" -> RuntimeValue(DataType.UWORD, rnd.nextInt() and 65535)
"rndf" -> RuntimeValue(DataType.FLOAT, rnd.nextDouble())
"lsb" -> RuntimeValue(DataType.UBYTE, args[0].integerValue() and 255)
"msb" -> RuntimeValue(DataType.UBYTE, (args[0].integerValue() ushr 8) and 255)
"sin" -> RuntimeValue(DataType.FLOAT, sin(args[0].numericValue().toDouble()))
"sin8" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.BYTE, (127.0 * sin(rad)).toShort())
}
"sin8u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort())
}
"sin16" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.BYTE, (32767.0 * sin(rad)).toShort())
}
"sin16u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * sin(rad)).toShort())
}
"cos" -> RuntimeValue(DataType.FLOAT, cos(args[0].numericValue().toDouble()))
"cos8" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.BYTE, (127.0 * cos(rad)).toShort())
}
"cos8u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort())
}
"cos16" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.BYTE, (32767.0 * cos(rad)).toShort())
}
"cos16u" -> {
val rad = args[0].numericValue().toDouble() / 256.0 * 2.0 * PI
RuntimeValue(DataType.UBYTE, (32768.0 + 32767.5 * cos(rad)).toShort())
}
"tan" -> RuntimeValue(DataType.FLOAT, tan(args[0].numericValue().toDouble()))
"atan" -> RuntimeValue(DataType.FLOAT, atan(args[0].numericValue().toDouble()))
"ln" -> RuntimeValue(DataType.FLOAT, ln(args[0].numericValue().toDouble()))
"log2" -> RuntimeValue(DataType.FLOAT, log2(args[0].numericValue().toDouble()))
"sqrt" -> RuntimeValue(DataType.FLOAT, sqrt(args[0].numericValue().toDouble()))
"sqrt16" -> RuntimeValue(DataType.UBYTE, sqrt(args[0].wordval!!.toDouble()).toInt())
"rad" -> RuntimeValue(DataType.FLOAT, toRadians(args[0].numericValue().toDouble()))
"deg" -> RuntimeValue(DataType.FLOAT, toDegrees(args[0].numericValue().toDouble()))
"round" -> RuntimeValue(DataType.FLOAT, round(args[0].numericValue().toDouble()))
"floor" -> RuntimeValue(DataType.FLOAT, floor(args[0].numericValue().toDouble()))
"ceil" -> RuntimeValue(DataType.FLOAT, ceil(args[0].numericValue().toDouble()))
"rol" -> {
val (result, newCarry) = args[0].rol(statusflags.carry)
statusflags.carry = newCarry
return result
}
"rol2" -> args[0].rol2()
"ror" -> {
val (result, newCarry) = args[0].ror(statusflags.carry)
statusflags.carry = newCarry
return result
}
"ror2" -> args[0].ror2()
"lsl" -> args[0].shl()
"lsr" -> args[0].shr()
"abs" -> {
when (args[0].type) {
DataType.UBYTE -> args[0]
DataType.BYTE -> RuntimeValue(DataType.UBYTE, abs(args[0].numericValue().toDouble()))
DataType.UWORD -> args[0]
DataType.WORD -> RuntimeValue(DataType.UWORD, abs(args[0].numericValue().toDouble()))
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, abs(args[0].numericValue().toDouble()))
else -> TODO("strange abs type")
}
}
"max" -> {
val numbers = args.map { it.numericValue().toDouble() }
RuntimeValue(args[0].type, numbers.max())
}
"min" -> {
val numbers = args.map { it.numericValue().toDouble() }
RuntimeValue(args[0].type, numbers.min())
}
"avg" -> {
val numbers = args.map { it.numericValue().toDouble() }
RuntimeValue(DataType.FLOAT, numbers.average())
}
"sum" -> {
val sum = args.map { it.numericValue().toDouble() }.sum()
when (args[0].type) {
DataType.UBYTE -> RuntimeValue(DataType.UWORD, sum)
DataType.BYTE -> RuntimeValue(DataType.WORD, sum)
DataType.UWORD -> RuntimeValue(DataType.UWORD, sum)
DataType.WORD -> RuntimeValue(DataType.WORD, sum)
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, sum)
else -> TODO("weird sum type")
}
}
"any" -> {
val numbers = args.map { it.numericValue().toDouble() }
RuntimeValue(DataType.UBYTE, if (numbers.any { it != 0.0 }) 1 else 0)
}
"all" -> {
val numbers = args.map { it.numericValue().toDouble() }
RuntimeValue(DataType.UBYTE, if (numbers.all { it != 0.0 }) 1 else 0)
}
"swap" ->
throw VmExecutionException("swap() cannot be implemented as a function")
"strlen" -> {
val zeroIndex = args[0].str!!.indexOf(0.toChar())
if(zeroIndex>=0)
if (zeroIndex >= 0)
RuntimeValue(DataType.UBYTE, zeroIndex)
else
RuntimeValue(DataType.UBYTE, args[0].str!!.length)
@ -37,262 +145,60 @@ class BuiltinFunctions {
val amount = args[1].integerValue()
val value = args[2].integerValue()
for (i in 0 until amount step 2) {
target[i*2] = value and 255
target[i*2+1] = value ushr 8
target[i * 2] = value and 255
target[i * 2 + 1] = value ushr 8
}
null
}
"memcopy" -> {
val source = args[0].array!!
val dest = args[1].array!!
val amount = args[2].integerValue()
for(i in 0 until amount) {
dest[i] = source[i]
}
null
}
"mkword" -> {
val result = (args[0].integerValue() shl 8) or args[1].integerValue()
RuntimeValue(DataType.UWORD, result)
}
"set_carry" -> {
statusflags.carry=true
null
}
"clear_carry" -> {
statusflags.carry=false
null
}
"set_irqd" -> {
statusflags.irqd=true
null
}
"clear_irqd" -> {
statusflags.irqd=false
null
}
"read_flags" -> {
val carry = if(statusflags.carry) 1 else 0
val zero = if(statusflags.zero) 2 else 0
val irqd = if(statusflags.irqd) 4 else 0
val negative = if(statusflags.negative) 128 else 0
RuntimeValue(DataType.UBYTE, carry or zero or irqd or negative)
}
"rsave" -> {
statusFlagsSave.push(statusflags)
null
}
"rrestore" -> {
val flags = statusFlagsSave.pop()
statusflags.carry = flags.carry
statusflags.negative = flags.negative
statusflags.zero = flags.zero
statusflags.irqd = flags.irqd
null
}
else -> TODO("builtin function $name")
}
}
}
/**
Syscall.FUNC_LEN_STR, Syscall.FUNC_LEN_STRS -> {
val strPtr = evalstack.pop().integerValue()
val text = heap.get(strPtr).str!!
evalstack.push(RuntimeValue(DataType.UBYTE, text.length))
}
Syscall.FUNC_STRLEN -> {
val strPtr = evalstack.pop().integerValue()
val text = heap.get(strPtr).str!!
val zeroIdx = text.indexOf('\u0000')
val len = if(zeroIdx>=0) zeroIdx else text.length
evalstack.push(RuntimeValue(DataType.UBYTE, len))
}
Syscall.FUNC_READ_FLAGS -> {
val carry = if(P_carry) 1 else 0
val zero = if(P_zero) 2 else 0
val irqd = if(P_irqd) 4 else 0
val negative = if(P_negative) 128 else 0
val flags = carry or zero or irqd or negative
evalstack.push(RuntimeValue(DataType.UBYTE, flags))
}
Syscall.FUNC_SIN -> evalstack.push(RuntimeValue(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_COS -> evalstack.push(RuntimeValue(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_SIN8 -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.BYTE, (127.0 * sin(rad)).toShort()))
}
Syscall.FUNC_SIN8U -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * sin(rad)).toShort()))
}
Syscall.FUNC_SIN16 -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.WORD, (32767.0 * sin(rad)).toInt()))
}
Syscall.FUNC_SIN16U -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.WORD, (32768.0 + 32767.5 * sin(rad)).toInt()))
}
Syscall.FUNC_COS8 -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.BYTE, (127.0 * cos(rad)).toShort()))
}
Syscall.FUNC_COS8U -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.UBYTE, (128.0 + 127.5 * cos(rad)).toShort()))
}
Syscall.FUNC_COS16 -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.WORD, (32767.0 * cos(rad)).toInt()))
}
Syscall.FUNC_COS16U -> {
val rad = evalstack.pop().numericValue().toDouble() /256.0 * 2.0 * PI
evalstack.push(RuntimeValue(DataType.WORD, (32768.0 + 32767.5 * cos(rad)).toInt()))
}
Syscall.FUNC_ROUND -> evalstack.push(RuntimeValue(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))
Syscall.FUNC_ABS -> {
val value = evalstack.pop()
val absValue =
when (value.type) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, value.numericValue())
DataType.UWORD -> RuntimeValue(DataType.UWORD, value.numericValue())
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, value.numericValue())
else -> throw VmExecutionException("cannot get abs of $value")
}
evalstack.push(absValue)
}
Syscall.FUNC_TAN -> evalstack.push(RuntimeValue(DataType.FLOAT, tan(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_ATAN -> evalstack.push(RuntimeValue(DataType.FLOAT, atan(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_LN -> evalstack.push(RuntimeValue(DataType.FLOAT, ln(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_LOG2 -> evalstack.push(RuntimeValue(DataType.FLOAT, log2(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_SQRT -> evalstack.push(RuntimeValue(DataType.FLOAT, sqrt(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_SQRT16 -> evalstack.push(RuntimeValue(DataType.UBYTE, sqrt(evalstack.pop().numericValue().toDouble()).toInt()))
Syscall.FUNC_RAD -> evalstack.push(RuntimeValue(DataType.FLOAT, Math.toRadians(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_DEG -> evalstack.push(RuntimeValue(DataType.FLOAT, Math.toDegrees(evalstack.pop().numericValue().toDouble())))
Syscall.FUNC_FLOOR -> {
val value = evalstack.pop()
if (value.type in NumericDatatypes)
evalstack.push(RuntimeValue(DataType.FLOAT, floor(value.numericValue().toDouble())))
else throw VmExecutionException("cannot get floor of $value")
}
Syscall.FUNC_CEIL -> {
val value = evalstack.pop()
if (value.type in NumericDatatypes)
evalstack.push(RuntimeValue(DataType.FLOAT, ceil(value.numericValue().toDouble())))
else throw VmExecutionException("cannot get ceil of $value")
}
Syscall.FUNC_MAX_UB -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, value.array.map { it.integer!! }.max() ?: 0))
}
Syscall.FUNC_MAX_B -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.BYTE, value.array.map { it.integer!! }.max() ?: 0))
}
Syscall.FUNC_MAX_UW -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(RuntimeValue(DataType.UWORD, value.array.map { it.integer!! }.max() ?: 0))
}
Syscall.FUNC_MAX_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.WORD, value.array.map { it.integer!! }.max() ?: 0))
}
Syscall.FUNC_MAX_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.FLOAT, value.doubleArray.max() ?: 0.0))
}
Syscall.FUNC_MIN_UB -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, value.array.map { it.integer!! }.min() ?: 0))
}
Syscall.FUNC_MIN_B -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.BYTE, value.array.map { it.integer!! }.min() ?: 0))
}
Syscall.FUNC_MIN_UW -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(RuntimeValue(DataType.UWORD, value.array.map { it.integer!! }.min() ?: 0))
}
Syscall.FUNC_MIN_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.WORD, value.array.map { it.integer!! }.min() ?: 0))
}
Syscall.FUNC_MIN_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.FLOAT, value.doubleArray.min() ?: 0.0))
}
Syscall.FUNC_SUM_W, Syscall.FUNC_SUM_B -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.WORD, value.array.map { it.integer!! }.sum()))
}
Syscall.FUNC_SUM_UW -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
if(value.array.any {it.addressOf!=null})
throw VmExecutionException("stackvm cannot process raw memory pointers")
evalstack.push(RuntimeValue(DataType.UWORD, value.array.map { it.integer!! }.sum()))
}
Syscall.FUNC_SUM_UB -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UWORD, value.array.map { it.integer!! }.sum()))
}
Syscall.FUNC_SUM_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.FLOAT, value.doubleArray.sum()))
}
Syscall.FUNC_ANY_B, Syscall.FUNC_ANY_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, if (value.array.any { it.integer != 0 }) 1 else 0))
}
Syscall.FUNC_ANY_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, if (value.doubleArray.any { it != 0.0 }) 1 else 0))
}
Syscall.FUNC_ALL_B, Syscall.FUNC_ALL_W -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.array!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, if (value.array.all { it.integer != 0 }) 1 else 0))
}
Syscall.FUNC_ALL_F -> {
val length = evalstack.pop().integerValue()
val heapVarId = evalstack.pop().integerValue()
val value = heap.get(heapVarId)
if(length!=value.doubleArray!!.size)
throw VmExecutionException("iterable length mismatch")
evalstack.push(RuntimeValue(DataType.UBYTE, if (value.doubleArray.all { it != 0.0 }) 1 else 0))
}
Syscall.FUNC_MEMCOPY -> {
val numbytes = evalstack.pop().integerValue()
val to = evalstack.pop().integerValue()
val from = evalstack.pop().integerValue()
mem.copy(from, to, numbytes)
}
**/

View File

@ -5,7 +5,7 @@ import prog8.compiler.RuntimeValue
import prog8.compiler.RuntimeValueRange
import kotlin.math.abs
class EvalContext(val program: Program, val mem: Memory,
class EvalContext(val program: Program, val mem: Memory, val statusflags: StatusFlags,
val runtimeVars: RuntimeVariables, val functions: BuiltinFunctions,
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>) -> List<RuntimeValue>)
@ -19,7 +19,13 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
return RuntimeValue.from(expr, ctx.program.heap)
}
is PrefixExpression -> {
TODO("prefixexpr $expr")
return when(expr.operator) {
"-" -> evaluate(expr.expression, ctx).neg()
"~" -> evaluate(expr.expression, ctx).inv()
"not" -> evaluate(expr.expression, ctx).not()
// unary '+' should have been optimized away
else -> TODO("prefixexpr ${expr.operator}")
}
}
is BinaryExpression -> {
val left = evaluate(expr.left, ctx)
@ -35,6 +41,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
"-" -> left.sub(right)
"*" -> left.mul(right)
"/" -> left.div(right)
"**" -> left.pow(right)
"<<" -> {
var result = left
repeat(right.integerValue()) {result = result.shl()}
@ -46,9 +53,12 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
result
}
"%" -> left.remainder(right)
"|" -> left.or(right)
"&" -> left.and(right)
"^" -> left.xor(right)
"|" -> left.bitor(right)
"&" -> left.bitand(right)
"^" -> left.bitxor(right)
"and" -> left.and(right)
"or" -> left.or(right)
"xor" -> left.xor(right)
else -> TODO("binexpression operator ${expr.operator}")
}
}
@ -113,7 +123,8 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
results[0]
}
is BuiltinFunctionStatementPlaceholder -> {
val result = ctx.functions.performBuiltinFunction(sub.name, args) ?: throw VmExecutionException("expected 1 result from functioncall $expr")
val result = ctx.functions.performBuiltinFunction(sub.name, args, ctx.statusflags)
?: throw VmExecutionException("expected 1 result from functioncall $expr")
result
}
else -> {

View File

@ -407,27 +407,27 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
fun inv(): RuntimeValue {
return when(type) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, byteval!!.toInt().inv())
DataType.UWORD -> RuntimeValue(DataType.UWORD, wordval!!.inv())
in ByteDatatypes -> RuntimeValue(type, byteval!!.toInt().inv())
in WordDatatypes -> RuntimeValue(type, wordval!!.inv())
else -> throw ArithmeticException("inv can only work on byte/word")
}
}
fun inc(): RuntimeValue {
return when(type) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, byteval!! + 1)
DataType.UWORD -> RuntimeValue(DataType.UWORD, wordval!! + 1)
in ByteDatatypes -> RuntimeValue(type, byteval!! + 1)
in WordDatatypes -> RuntimeValue(type, wordval!! + 1)
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, floatval!! + 1)
else -> throw ArithmeticException("inc can only work on byte/word/float")
else -> throw ArithmeticException("inc can only work on numeric types")
}
}
fun dec(): RuntimeValue {
return when(type) {
DataType.UBYTE -> RuntimeValue(DataType.UBYTE, byteval!! - 1)
DataType.UWORD -> RuntimeValue(DataType.UWORD, wordval!! - 1)
in ByteDatatypes -> RuntimeValue(type, byteval!! - 1)
in WordDatatypes -> RuntimeValue(type, wordval!! - 1)
DataType.FLOAT -> RuntimeValue(DataType.FLOAT, floatval!! - 1)
else -> throw ArithmeticException("dec can only work on byte/word/float")
else -> throw ArithmeticException("dec can only work on numeric types")
}
}

View File

@ -327,6 +327,7 @@ class IntermediateProgram(val name: String, var loadAddress: Int, val heap: Heap
instructionsToReplace[index1] = Instruction(Opcode.NOP)
}
Opcode.DISCARD_WORD, Opcode.DISCARD_FLOAT -> throw CompilerException("invalid discard type following a byte")
Opcode.MKWORD -> {}
else -> throw CompilerException("invalid conversion opcode ${ins1.opcode}")
}
}

View File

@ -6,16 +6,10 @@
~ main {
sub start() {
ubyte u1 = 100
ubyte u2 = 30
byte bb = -30
byte bb2 = -30
float ff = -3.3
word ww
bb = (u2 as word) as byte
bb = (((u2 as word) as byte) as word) as byte
ubyte[100] arr1
ubyte[100] arr2
memcopy(arr1, arr2, len(arr2))
}