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

View File

@ -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")
}
}

View 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)
}
**/

View File

@ -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")

View File

@ -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
}
}