diff --git a/compiler/src/prog8/astvm/AstVm.kt b/compiler/src/prog8/astvm/AstVm.kt index 054e6f291..ed76bc7b8 100644 --- a/compiler/src/prog8/astvm/AstVm.kt +++ b/compiler/src/prog8/astvm/AstVm.kt @@ -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): List = args.map { evaluate(it, program, runtimeVariables, ::executeSubroutine) } - - private fun performBuiltinFunction(name: String, args: List) { - 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): List = args.map { + evaluate(it, EvalContext(program, runtimeVariables, functions, ::executeSubroutine)) } private fun performSyscall(sub: Subroutine, args: List) { @@ -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") } } diff --git a/compiler/src/prog8/astvm/BuiltinFunctions.kt b/compiler/src/prog8/astvm/BuiltinFunctions.kt new file mode 100644 index 000000000..d107c6265 --- /dev/null +++ b/compiler/src/prog8/astvm/BuiltinFunctions.kt @@ -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? { + 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) + } + + + **/ diff --git a/compiler/src/prog8/astvm/Expressions.kt b/compiler/src/prog8/astvm/Expressions.kt index 97d4e8891..dd9649f34 100644 --- a/compiler/src/prog8/astvm/Expressions.kt +++ b/compiler/src/prog8/astvm/Expressions.kt @@ -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) -> List): RuntimeValue { - val constval = expr.constValue(program) +class EvalContext(val program: Program, val runtimeVars: RuntimeVariables, + val functions: BuiltinFunctions, + val executeSubroutine: (sub: Subroutine, args: List) -> List) + +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") diff --git a/examples/test.p8 b/examples/test.p8 index 6f9e91602..d1d00f513 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 } }