mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
some builtin functions
This commit is contained in:
parent
d68360461b
commit
f49eefad6f
@ -104,6 +104,7 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
|
||||
private val runtimeVariables = RuntimeVariables()
|
||||
private val functions = BuiltinFunctions()
|
||||
|
||||
class LoopControlBreak: Exception()
|
||||
class LoopControlContinue: Exception()
|
||||
@ -131,6 +132,7 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
|
||||
private fun executeStatement(sub: INameScope, stmt: IStatement) {
|
||||
val evalCtx = EvalContext(program, runtimeVariables, functions, ::executeSubroutine)
|
||||
instructionCounter++
|
||||
if(instructionCounter % 100 == 0)
|
||||
Thread.sleep(1)
|
||||
@ -161,7 +163,7 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
val args = evaluate(stmt.arglist)
|
||||
performBuiltinFunction(target.name, args)
|
||||
functions.performBuiltinFunction(target.name, args)
|
||||
}
|
||||
else -> {
|
||||
TODO("CALL $target")
|
||||
@ -171,7 +173,7 @@ class AstVm(val program: Program) {
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
TODO("builtinfun $stmt")
|
||||
}
|
||||
is Return -> throw LoopControlReturn(stmt.values.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) })
|
||||
is Return -> throw LoopControlReturn(stmt.values.map { evaluate(it, evalCtx) })
|
||||
is Continue -> throw LoopControlContinue()
|
||||
is Break -> throw LoopControlBreak()
|
||||
is Assignment -> {
|
||||
@ -179,11 +181,11 @@ class AstVm(val program: Program) {
|
||||
throw VmExecutionException("augmented assignment should have been converted into regular one $stmt")
|
||||
val target = stmt.singleTarget
|
||||
if(target!=null) {
|
||||
val value = evaluate(stmt.value, evalCtx)
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl
|
||||
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
|
||||
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
|
||||
val identScope = ident.definingScope()
|
||||
runtimeVariables.set(identScope, ident.name, value)
|
||||
}
|
||||
@ -191,9 +193,9 @@ class AstVm(val program: Program) {
|
||||
TODO("assign memory $stmt")
|
||||
}
|
||||
target.arrayindexed!=null -> {
|
||||
val array = evaluate(target.arrayindexed.identifier, program, runtimeVariables, ::executeSubroutine)
|
||||
val index = evaluate(target.arrayindexed.arrayspec.index, program, runtimeVariables, ::executeSubroutine)
|
||||
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
|
||||
val array = evaluate(target.arrayindexed.identifier, evalCtx)
|
||||
val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx)
|
||||
val value = evaluate(stmt.value, evalCtx)
|
||||
when(array.type) {
|
||||
DataType.ARRAY_UB -> {
|
||||
if(value.type!=DataType.UBYTE)
|
||||
@ -219,6 +221,10 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
array.array!![index.integerValue()] = value.numericValue()
|
||||
}
|
||||
target.register!=null -> {
|
||||
runtimeVariables.set(program.namespace, target.register.name, value)
|
||||
}
|
||||
else -> TODO("assign $target")
|
||||
}
|
||||
}
|
||||
else TODO("assign multitarget $stmt")
|
||||
@ -248,11 +254,21 @@ class AstVm(val program: Program) {
|
||||
TODO("jump $stmt")
|
||||
}
|
||||
is InlineAssembly -> {
|
||||
if(sub is Subroutine) {
|
||||
when(sub.scopedname) {
|
||||
"c64flt.print_f" -> {
|
||||
val arg = runtimeVariables.get(sub, sub.parameters.single().name)
|
||||
performSyscall(sub, listOf(arg))
|
||||
}
|
||||
else -> TODO("simulate asm subroutine ${sub.scopedname}")
|
||||
}
|
||||
throw LoopControlReturn(emptyList())
|
||||
}
|
||||
throw VmExecutionException("can't execute inline assembly in $sub")
|
||||
}
|
||||
is AnonymousScope -> executeAnonymousScope(stmt)
|
||||
is IfStatement -> {
|
||||
val condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
|
||||
val condition = evaluate(stmt.condition, evalCtx)
|
||||
if(condition.asBoolean)
|
||||
executeAnonymousScope(stmt.truepart)
|
||||
else
|
||||
@ -262,7 +278,7 @@ class AstVm(val program: Program) {
|
||||
TODO("branch $stmt")
|
||||
}
|
||||
is ForLoop -> {
|
||||
val iterable = evaluate(stmt.iterable, program, runtimeVariables, ::executeSubroutine)
|
||||
val iterable = evaluate(stmt.iterable, evalCtx)
|
||||
if (iterable.type !in IterableDatatypes && iterable !is RuntimeValueRange)
|
||||
throw VmExecutionException("can only iterate over an iterable value: $stmt")
|
||||
val loopvarDt: DataType
|
||||
@ -287,11 +303,11 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
}
|
||||
is WhileLoop -> {
|
||||
var condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
|
||||
var condition = evaluate(stmt.condition, evalCtx)
|
||||
while (condition.asBoolean) {
|
||||
try {
|
||||
executeAnonymousScope(stmt.body)
|
||||
condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine)
|
||||
condition = evaluate(stmt.condition, evalCtx)
|
||||
} catch(b: LoopControlBreak) {
|
||||
break
|
||||
} catch(c: LoopControlContinue){
|
||||
@ -301,7 +317,7 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
is RepeatLoop -> {
|
||||
do {
|
||||
val condition = evaluate(stmt.untilCondition, program, runtimeVariables, ::executeSubroutine)
|
||||
val condition = evaluate(stmt.untilCondition, evalCtx)
|
||||
try {
|
||||
executeAnonymousScope(stmt.body)
|
||||
} catch(b: LoopControlBreak) {
|
||||
@ -334,20 +350,8 @@ class AstVm(val program: Program) {
|
||||
executeAnonymousScope(stmt.body) // and run the code
|
||||
}
|
||||
|
||||
private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) }
|
||||
|
||||
private fun performBuiltinFunction(name: String, args: List<RuntimeValue>) {
|
||||
when(name) {
|
||||
"memset" -> {
|
||||
val target = args[0].array!!
|
||||
val amount = args[1].integerValue()
|
||||
val value = args[2].integerValue()
|
||||
for(i in 0 until amount) {
|
||||
target[i] = value
|
||||
}
|
||||
}
|
||||
else -> TODO("builtin function $name")
|
||||
}
|
||||
private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map {
|
||||
evaluate(it, EvalContext(program, runtimeVariables, functions, ::executeSubroutine))
|
||||
}
|
||||
|
||||
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>) {
|
||||
@ -387,7 +391,10 @@ class AstVm(val program: Program) {
|
||||
"c64.CHROUT" -> {
|
||||
dialog.canvas.printChar(args[0].byteval!!)
|
||||
}
|
||||
else -> TODO("syscall $sub")
|
||||
"c64flt.print_f" -> {
|
||||
dialog.canvas.printText(args[0].floatval.toString(), 1, true)
|
||||
}
|
||||
else -> TODO("syscall ${sub.scopedname} $sub")
|
||||
}
|
||||
}
|
||||
|
||||
|
289
compiler/src/prog8/astvm/BuiltinFunctions.kt
Normal file
289
compiler/src/prog8/astvm/BuiltinFunctions.kt
Normal file
@ -0,0 +1,289 @@
|
||||
package prog8.astvm
|
||||
|
||||
import prog8.ast.DataType
|
||||
import prog8.compiler.RuntimeValue
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
class BuiltinFunctions {
|
||||
|
||||
private val rnd = Random(0)
|
||||
|
||||
fun performBuiltinFunction(name: String, args: List<RuntimeValue>): 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())
|
||||
"memset" -> {
|
||||
val target = args[0].array!!
|
||||
val amount = args[1].integerValue()
|
||||
val value = args[2].integerValue()
|
||||
for (i in 0 until amount) {
|
||||
target[i] = value
|
||||
}
|
||||
null
|
||||
}
|
||||
"memsetw" -> {
|
||||
val target = args[0].array!!
|
||||
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
|
||||
}
|
||||
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,22 +5,25 @@ import prog8.compiler.RuntimeValue
|
||||
import prog8.compiler.RuntimeValueRange
|
||||
import kotlin.math.abs
|
||||
|
||||
fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>) -> List<RuntimeValue>): RuntimeValue {
|
||||
val constval = expr.constValue(program)
|
||||
class EvalContext(val program: Program, val runtimeVars: RuntimeVariables,
|
||||
val functions: BuiltinFunctions,
|
||||
val executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>) -> List<RuntimeValue>)
|
||||
|
||||
fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
||||
val constval = expr.constValue(ctx.program)
|
||||
if(constval!=null)
|
||||
return RuntimeValue.from(constval, program.heap)
|
||||
return RuntimeValue.from(constval, ctx.program.heap)
|
||||
|
||||
when(expr) {
|
||||
is LiteralValue -> {
|
||||
return RuntimeValue.from(expr, program.heap)
|
||||
return RuntimeValue.from(expr, ctx.program.heap)
|
||||
}
|
||||
is PrefixExpression -> {
|
||||
TODO("prefixexpr $expr")
|
||||
}
|
||||
is BinaryExpression -> {
|
||||
val left = evaluate(expr.left, program, runtimeVars, executeSubroutine)
|
||||
val right = evaluate(expr.right, program, runtimeVars, executeSubroutine)
|
||||
val left = evaluate(expr.left, ctx)
|
||||
val right = evaluate(expr.right, ctx)
|
||||
return when(expr.operator) {
|
||||
"<" -> RuntimeValue(DataType.UBYTE, if (left < right) 1 else 0)
|
||||
"<=" -> RuntimeValue(DataType.UBYTE, if (left <= right) 1 else 0)
|
||||
@ -40,8 +43,8 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
}
|
||||
}
|
||||
is ArrayIndexedExpression -> {
|
||||
val array = evaluate(expr.identifier, program, runtimeVars, executeSubroutine)
|
||||
val index = evaluate(expr.arrayspec.index, program, runtimeVars, executeSubroutine)
|
||||
val array = evaluate(expr.identifier, ctx)
|
||||
val index = evaluate(expr.arrayspec.index, ctx)
|
||||
val value = array.array!![index.integerValue()]
|
||||
return when(array.type) {
|
||||
DataType.ARRAY_UB -> RuntimeValue(DataType.UBYTE, num = value)
|
||||
@ -53,11 +56,11 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
}
|
||||
}
|
||||
is TypecastExpression -> {
|
||||
return evaluate(expr.expression, program, runtimeVars, executeSubroutine).cast(expr.type)
|
||||
return evaluate(expr.expression, ctx).cast(expr.type)
|
||||
}
|
||||
is AddressOf -> {
|
||||
// we support: address of heap var -> the heap id
|
||||
val heapId = expr.identifier.heapId(program.namespace)
|
||||
val heapId = expr.identifier.heapId(ctx.program.namespace)
|
||||
return RuntimeValue(DataType.UWORD, heapId)
|
||||
}
|
||||
is DirectMemoryRead -> {
|
||||
@ -66,25 +69,29 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
is DirectMemoryWrite -> {
|
||||
TODO("memorywrite $expr")
|
||||
}
|
||||
is RegisterExpr -> return runtimeVars.get(program.namespace, expr.register.name)
|
||||
is RegisterExpr -> return ctx.runtimeVars.get(ctx.program.namespace, expr.register.name)
|
||||
is IdentifierReference -> {
|
||||
val scope = expr.definingScope()
|
||||
val variable = scope.lookup(expr.nameInSource, expr)
|
||||
if(variable is VarDecl) {
|
||||
val stmt = scope.lookup(listOf(variable.name), expr)!!
|
||||
return runtimeVars.get(stmt.definingScope(), variable.name)
|
||||
return ctx.runtimeVars.get(stmt.definingScope(), variable.name)
|
||||
} else
|
||||
TODO("weird ref $variable")
|
||||
}
|
||||
is FunctionCall -> {
|
||||
val sub = expr.target.targetStatement(program.namespace)
|
||||
val args = expr.arglist.map { evaluate(it, program, runtimeVars, executeSubroutine) }
|
||||
when(sub) {
|
||||
val sub = expr.target.targetStatement(ctx.program.namespace)
|
||||
val args = expr.arglist.map { evaluate(it, ctx) }
|
||||
return when(sub) {
|
||||
is Subroutine -> {
|
||||
val results = executeSubroutine(sub, args)
|
||||
val results = ctx.executeSubroutine(sub, args)
|
||||
if(results.size!=1)
|
||||
throw VmExecutionException("expected 1 result from functioncall $expr")
|
||||
return results[0]
|
||||
results[0]
|
||||
}
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
val result = ctx.functions.performBuiltinFunction(sub.name, args) ?: throw VmExecutionException("expected 1 result from functioncall $expr")
|
||||
result
|
||||
}
|
||||
else -> {
|
||||
TODO("call expr function ${expr.target}")
|
||||
@ -92,12 +99,12 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
}
|
||||
}
|
||||
is RangeExpr -> {
|
||||
val cRange = expr.toConstantIntegerRange(program.heap)
|
||||
val cRange = expr.toConstantIntegerRange(ctx.program.heap)
|
||||
if(cRange!=null)
|
||||
return RuntimeValueRange(expr.resultingDatatype(program)!!, cRange)
|
||||
val fromVal = evaluate(expr.from, program, runtimeVars, executeSubroutine).integerValue()
|
||||
val toVal = evaluate(expr.to, program, runtimeVars, executeSubroutine).integerValue()
|
||||
val stepVal = evaluate(expr.step, program, runtimeVars, executeSubroutine).integerValue()
|
||||
return RuntimeValueRange(expr.resultingDatatype(ctx.program)!!, cRange)
|
||||
val fromVal = evaluate(expr.from, ctx).integerValue()
|
||||
val toVal = evaluate(expr.to, ctx).integerValue()
|
||||
val stepVal = evaluate(expr.step, ctx).integerValue()
|
||||
val range = when {
|
||||
fromVal <= toVal -> when {
|
||||
stepVal <= 0 -> IntRange.EMPTY
|
||||
@ -110,7 +117,7 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
|
||||
else -> fromVal downTo toVal step abs(stepVal)
|
||||
}
|
||||
}
|
||||
return RuntimeValueRange(expr.resultingDatatype(program)!!, range)
|
||||
return RuntimeValueRange(expr.resultingDatatype(ctx.program)!!, range)
|
||||
}
|
||||
else -> {
|
||||
TODO("implement eval $expr")
|
||||
|
@ -1,26 +1,44 @@
|
||||
%import c64utils
|
||||
%zeropage basicsafe
|
||||
%import c64flt
|
||||
|
||||
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
Y=99
|
||||
A=200
|
||||
Y=A
|
||||
ubyte r = subt()
|
||||
c64scr.print_ub(r)
|
||||
c64scr.print_ub(rnd())
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub subt() -> ubyte {
|
||||
|
||||
for Y in 20 to 50 step 5 {
|
||||
c64scr.print_ub(Y)
|
||||
c64.CHROUT(',')
|
||||
if Y>40
|
||||
return 99
|
||||
}
|
||||
c64scr.print_ub(rnd())
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(rnd())
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_uw(rndw())
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_uw(rndw())
|
||||
c64.CHROUT('\n')
|
||||
c64flt.print_f(rndf())
|
||||
c64.CHROUT('\n')
|
||||
c64flt.print_f(rndf())
|
||||
c64.CHROUT('\n')
|
||||
c64.CHROUT('\n')
|
||||
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
A=rnd()
|
||||
c64scr.print_ub(A)
|
||||
c64.CHROUT('\n')
|
||||
return 10
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user