1
0
mirror of https://github.com/irmen/prog8.git synced 2025-03-31 16:29:59 +00:00

some builtin functions

This commit is contained in:
Irmen de Jong 2019-06-25 23:36:54 +02:00
parent d68360461b
commit f49eefad6f
4 changed files with 387 additions and 66 deletions
compiler/src/prog8/astvm
examples

@ -104,6 +104,7 @@ class AstVm(val program: Program) {
} }
private val runtimeVariables = RuntimeVariables() private val runtimeVariables = RuntimeVariables()
private val functions = BuiltinFunctions()
class LoopControlBreak: Exception() class LoopControlBreak: Exception()
class LoopControlContinue: Exception() class LoopControlContinue: Exception()
@ -131,6 +132,7 @@ class AstVm(val program: Program) {
} }
private fun executeStatement(sub: INameScope, stmt: IStatement) { private fun executeStatement(sub: INameScope, stmt: IStatement) {
val evalCtx = EvalContext(program, runtimeVariables, functions, ::executeSubroutine)
instructionCounter++ instructionCounter++
if(instructionCounter % 100 == 0) if(instructionCounter % 100 == 0)
Thread.sleep(1) Thread.sleep(1)
@ -161,7 +163,7 @@ class AstVm(val program: Program) {
} }
is BuiltinFunctionStatementPlaceholder -> { is BuiltinFunctionStatementPlaceholder -> {
val args = evaluate(stmt.arglist) val args = evaluate(stmt.arglist)
performBuiltinFunction(target.name, args) functions.performBuiltinFunction(target.name, args)
} }
else -> { else -> {
TODO("CALL $target") TODO("CALL $target")
@ -171,7 +173,7 @@ class AstVm(val program: Program) {
is BuiltinFunctionStatementPlaceholder -> { is BuiltinFunctionStatementPlaceholder -> {
TODO("builtinfun $stmt") 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 Continue -> throw LoopControlContinue()
is Break -> throw LoopControlBreak() is Break -> throw LoopControlBreak()
is Assignment -> { is Assignment -> {
@ -179,11 +181,11 @@ class AstVm(val program: Program) {
throw VmExecutionException("augmented assignment should have been converted into regular one $stmt") throw VmExecutionException("augmented assignment should have been converted into regular one $stmt")
val target = stmt.singleTarget val target = stmt.singleTarget
if(target!=null) { if(target!=null) {
val value = evaluate(stmt.value, evalCtx)
when { when {
target.identifier!=null -> { target.identifier!=null -> {
val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl val ident = stmt.definingScope().lookup(target.identifier.nameInSource, stmt) as? VarDecl
?: throw VmExecutionException("can't find assignment target ${target.identifier}") ?: throw VmExecutionException("can't find assignment target ${target.identifier}")
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine)
val identScope = ident.definingScope() val identScope = ident.definingScope()
runtimeVariables.set(identScope, ident.name, value) runtimeVariables.set(identScope, ident.name, value)
} }
@ -191,9 +193,9 @@ class AstVm(val program: Program) {
TODO("assign memory $stmt") TODO("assign memory $stmt")
} }
target.arrayindexed!=null -> { target.arrayindexed!=null -> {
val array = evaluate(target.arrayindexed.identifier, program, runtimeVariables, ::executeSubroutine) val array = evaluate(target.arrayindexed.identifier, evalCtx)
val index = evaluate(target.arrayindexed.arrayspec.index, program, runtimeVariables, ::executeSubroutine) val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx)
val value = evaluate(stmt.value, program, runtimeVariables, ::executeSubroutine) val value = evaluate(stmt.value, evalCtx)
when(array.type) { when(array.type) {
DataType.ARRAY_UB -> { DataType.ARRAY_UB -> {
if(value.type!=DataType.UBYTE) if(value.type!=DataType.UBYTE)
@ -219,6 +221,10 @@ class AstVm(val program: Program) {
} }
array.array!![index.integerValue()] = value.numericValue() 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") else TODO("assign multitarget $stmt")
@ -248,11 +254,21 @@ class AstVm(val program: Program) {
TODO("jump $stmt") TODO("jump $stmt")
} }
is InlineAssembly -> { 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") throw VmExecutionException("can't execute inline assembly in $sub")
} }
is AnonymousScope -> executeAnonymousScope(stmt) is AnonymousScope -> executeAnonymousScope(stmt)
is IfStatement -> { is IfStatement -> {
val condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine) val condition = evaluate(stmt.condition, evalCtx)
if(condition.asBoolean) if(condition.asBoolean)
executeAnonymousScope(stmt.truepart) executeAnonymousScope(stmt.truepart)
else else
@ -262,7 +278,7 @@ class AstVm(val program: Program) {
TODO("branch $stmt") TODO("branch $stmt")
} }
is ForLoop -> { is ForLoop -> {
val iterable = evaluate(stmt.iterable, program, runtimeVariables, ::executeSubroutine) val iterable = evaluate(stmt.iterable, evalCtx)
if (iterable.type !in IterableDatatypes && iterable !is RuntimeValueRange) if (iterable.type !in IterableDatatypes && iterable !is RuntimeValueRange)
throw VmExecutionException("can only iterate over an iterable value: $stmt") throw VmExecutionException("can only iterate over an iterable value: $stmt")
val loopvarDt: DataType val loopvarDt: DataType
@ -287,11 +303,11 @@ class AstVm(val program: Program) {
} }
} }
is WhileLoop -> { is WhileLoop -> {
var condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine) var condition = evaluate(stmt.condition, evalCtx)
while (condition.asBoolean) { while (condition.asBoolean) {
try { try {
executeAnonymousScope(stmt.body) executeAnonymousScope(stmt.body)
condition = evaluate(stmt.condition, program, runtimeVariables, ::executeSubroutine) condition = evaluate(stmt.condition, evalCtx)
} catch(b: LoopControlBreak) { } catch(b: LoopControlBreak) {
break break
} catch(c: LoopControlContinue){ } catch(c: LoopControlContinue){
@ -301,7 +317,7 @@ class AstVm(val program: Program) {
} }
is RepeatLoop -> { is RepeatLoop -> {
do { do {
val condition = evaluate(stmt.untilCondition, program, runtimeVariables, ::executeSubroutine) val condition = evaluate(stmt.untilCondition, evalCtx)
try { try {
executeAnonymousScope(stmt.body) executeAnonymousScope(stmt.body)
} catch(b: LoopControlBreak) { } catch(b: LoopControlBreak) {
@ -334,20 +350,8 @@ class AstVm(val program: Program) {
executeAnonymousScope(stmt.body) // and run the code executeAnonymousScope(stmt.body) // and run the code
} }
private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) } private fun evaluate(args: List<IExpression>): List<RuntimeValue> = args.map {
evaluate(it, EvalContext(program, runtimeVariables, functions, ::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 performSyscall(sub: Subroutine, args: List<RuntimeValue>) { private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>) {
@ -387,7 +391,10 @@ class AstVm(val program: Program) {
"c64.CHROUT" -> { "c64.CHROUT" -> {
dialog.canvas.printChar(args[0].byteval!!) 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")
} }
} }

@ -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 prog8.compiler.RuntimeValueRange
import kotlin.math.abs import kotlin.math.abs
fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables, class EvalContext(val program: Program, val runtimeVars: RuntimeVariables,
executeSubroutine: (sub: Subroutine, args: List<RuntimeValue>) -> List<RuntimeValue>): RuntimeValue { val functions: BuiltinFunctions,
val constval = expr.constValue(program) 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) if(constval!=null)
return RuntimeValue.from(constval, program.heap) return RuntimeValue.from(constval, ctx.program.heap)
when(expr) { when(expr) {
is LiteralValue -> { is LiteralValue -> {
return RuntimeValue.from(expr, program.heap) return RuntimeValue.from(expr, ctx.program.heap)
} }
is PrefixExpression -> { is PrefixExpression -> {
TODO("prefixexpr $expr") TODO("prefixexpr $expr")
} }
is BinaryExpression -> { is BinaryExpression -> {
val left = evaluate(expr.left, program, runtimeVars, executeSubroutine) val left = evaluate(expr.left, ctx)
val right = evaluate(expr.right, program, runtimeVars, executeSubroutine) val right = evaluate(expr.right, ctx)
return when(expr.operator) { return when(expr.operator) {
"<" -> RuntimeValue(DataType.UBYTE, if (left < right) 1 else 0) "<" -> RuntimeValue(DataType.UBYTE, if (left < right) 1 else 0)
"<=" -> 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 -> { is ArrayIndexedExpression -> {
val array = evaluate(expr.identifier, program, runtimeVars, executeSubroutine) val array = evaluate(expr.identifier, ctx)
val index = evaluate(expr.arrayspec.index, program, runtimeVars, executeSubroutine) val index = evaluate(expr.arrayspec.index, ctx)
val value = array.array!![index.integerValue()] val value = array.array!![index.integerValue()]
return when(array.type) { return when(array.type) {
DataType.ARRAY_UB -> RuntimeValue(DataType.UBYTE, num = value) DataType.ARRAY_UB -> RuntimeValue(DataType.UBYTE, num = value)
@ -53,11 +56,11 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
} }
} }
is TypecastExpression -> { is TypecastExpression -> {
return evaluate(expr.expression, program, runtimeVars, executeSubroutine).cast(expr.type) return evaluate(expr.expression, ctx).cast(expr.type)
} }
is AddressOf -> { is AddressOf -> {
// we support: address of heap var -> the heap id // 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) return RuntimeValue(DataType.UWORD, heapId)
} }
is DirectMemoryRead -> { is DirectMemoryRead -> {
@ -66,25 +69,29 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
is DirectMemoryWrite -> { is DirectMemoryWrite -> {
TODO("memorywrite $expr") 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 -> { is IdentifierReference -> {
val scope = expr.definingScope() val scope = expr.definingScope()
val variable = scope.lookup(expr.nameInSource, expr) val variable = scope.lookup(expr.nameInSource, expr)
if(variable is VarDecl) { if(variable is VarDecl) {
val stmt = scope.lookup(listOf(variable.name), expr)!! val stmt = scope.lookup(listOf(variable.name), expr)!!
return runtimeVars.get(stmt.definingScope(), variable.name) return ctx.runtimeVars.get(stmt.definingScope(), variable.name)
} else } else
TODO("weird ref $variable") TODO("weird ref $variable")
} }
is FunctionCall -> { is FunctionCall -> {
val sub = expr.target.targetStatement(program.namespace) val sub = expr.target.targetStatement(ctx.program.namespace)
val args = expr.arglist.map { evaluate(it, program, runtimeVars, executeSubroutine) } val args = expr.arglist.map { evaluate(it, ctx) }
when(sub) { return when(sub) {
is Subroutine -> { is Subroutine -> {
val results = executeSubroutine(sub, args) val results = ctx.executeSubroutine(sub, args)
if(results.size!=1) if(results.size!=1)
throw VmExecutionException("expected 1 result from functioncall $expr") 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 -> { else -> {
TODO("call expr function ${expr.target}") TODO("call expr function ${expr.target}")
@ -92,12 +99,12 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
} }
} }
is RangeExpr -> { is RangeExpr -> {
val cRange = expr.toConstantIntegerRange(program.heap) val cRange = expr.toConstantIntegerRange(ctx.program.heap)
if(cRange!=null) if(cRange!=null)
return RuntimeValueRange(expr.resultingDatatype(program)!!, cRange) return RuntimeValueRange(expr.resultingDatatype(ctx.program)!!, cRange)
val fromVal = evaluate(expr.from, program, runtimeVars, executeSubroutine).integerValue() val fromVal = evaluate(expr.from, ctx).integerValue()
val toVal = evaluate(expr.to, program, runtimeVars, executeSubroutine).integerValue() val toVal = evaluate(expr.to, ctx).integerValue()
val stepVal = evaluate(expr.step, program, runtimeVars, executeSubroutine).integerValue() val stepVal = evaluate(expr.step, ctx).integerValue()
val range = when { val range = when {
fromVal <= toVal -> when { fromVal <= toVal -> when {
stepVal <= 0 -> IntRange.EMPTY stepVal <= 0 -> IntRange.EMPTY
@ -110,7 +117,7 @@ fun evaluate(expr: IExpression, program: Program, runtimeVars: RuntimeVariables,
else -> fromVal downTo toVal step abs(stepVal) else -> fromVal downTo toVal step abs(stepVal)
} }
} }
return RuntimeValueRange(expr.resultingDatatype(program)!!, range) return RuntimeValueRange(expr.resultingDatatype(ctx.program)!!, range)
} }
else -> { else -> {
TODO("implement eval $expr") TODO("implement eval $expr")

@ -1,26 +1,44 @@
%import c64utils %import c64utils
%zeropage basicsafe %zeropage basicsafe
%import c64flt
~ main { ~ main {
sub start() { sub start() {
Y=99 c64scr.print_ub(rnd())
A=200
Y=A
ubyte r = subt()
c64scr.print_ub(r)
c64.CHROUT('\n') c64.CHROUT('\n')
} c64scr.print_ub(rnd())
c64.CHROUT('\n')
sub subt() -> ubyte { c64scr.print_ub(rnd())
c64.CHROUT('\n')
for Y in 20 to 50 step 5 { c64scr.print_uw(rndw())
c64scr.print_ub(Y) c64.CHROUT('\n')
c64.CHROUT(',') c64scr.print_uw(rndw())
if Y>40 c64.CHROUT('\n')
return 99 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') c64.CHROUT('\n')
return 10
} }
} }