mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
implemented all builtin functions in the AstVm
This commit is contained in:
parent
29b3a7e94e
commit
53a4379c45
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
**/
|
||||
|
@ -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 -> {
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}")
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user