mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
more swap logic, some typing fixes
This commit is contained in:
parent
6c50043a4a
commit
267c678292
@ -111,7 +111,12 @@ val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, Data
|
||||
val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT)
|
||||
val StringDatatypes = setOf(DataType.STR, DataType.STR_S)
|
||||
val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F)
|
||||
|
||||
val ArrayElementTypes = mapOf(
|
||||
DataType.ARRAY_B to DataType.BYTE,
|
||||
DataType.ARRAY_UB to DataType.UBYTE,
|
||||
DataType.ARRAY_W to DataType.WORD,
|
||||
DataType.ARRAY_UW to DataType.UWORD,
|
||||
DataType.ARRAY_F to DataType.FLOAT)
|
||||
|
||||
class FatalAstException (override var message: String) : Exception(message)
|
||||
|
||||
|
@ -1132,6 +1132,31 @@ private class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
private fun checkArrayValues(value: LiteralValue, type: DataType): Boolean {
|
||||
if(value.isArray && value.heapId==null) {
|
||||
// TODO weird, array literal that hasn't been moved to the heap yet?
|
||||
val array = value.arrayvalue!!.map { it.constValue(program)!! }
|
||||
val correct: Boolean
|
||||
when(type) {
|
||||
DataType.ARRAY_UB -> {
|
||||
correct=array.all { it.bytevalue!=null && it.bytevalue in 0..255 }
|
||||
}
|
||||
DataType.ARRAY_B -> {
|
||||
correct=array.all { it.bytevalue!=null && it.bytevalue in -128..127 }
|
||||
}
|
||||
DataType.ARRAY_UW -> {
|
||||
correct=array.all { it.wordvalue!=null && it.wordvalue in 0..65535 }
|
||||
}
|
||||
DataType.ARRAY_W -> {
|
||||
correct=array.all { it.wordvalue!=null && it.wordvalue in -32768..32767}
|
||||
}
|
||||
DataType.ARRAY_F -> correct = true
|
||||
else -> throw AstException("invalid array type $type")
|
||||
}
|
||||
if(!correct)
|
||||
checkResult.add(ExpressionError("array value out of range for type $type", value.position))
|
||||
return correct
|
||||
}
|
||||
|
||||
val array = program.heap.get(value.heapId!!)
|
||||
val correct: Boolean
|
||||
when(type) {
|
||||
|
@ -267,18 +267,22 @@ private class StatementReorderer(private val program: Program): IAstProcessor {
|
||||
}
|
||||
}
|
||||
is BuiltinFunctionStatementPlaceholder -> {
|
||||
// if(sub.name in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "memset", "memcopy", "memsetw", "swap"))
|
||||
val func = BuiltinFunctions.getValue(sub.name)
|
||||
for(arg in func.parameters.zip(call.arglist.withIndex())) {
|
||||
val argtype = arg.second.value.inferType(program)
|
||||
if(argtype!=null) {
|
||||
if(arg.first.possibleDatatypes.any{ argtype == it})
|
||||
continue
|
||||
for(possibleType in arg.first.possibleDatatypes) {
|
||||
if(argtype isAssignableTo possibleType) {
|
||||
val typecasted = TypecastExpression(arg.second.value, possibleType, arg.second.value.position)
|
||||
typecasted.linkParents(arg.second.value.parent)
|
||||
call.arglist[arg.second.index] = typecasted
|
||||
break
|
||||
if(func.pure) {
|
||||
// non-pure functions don't get automatic typecasts because sometimes they act directly on their parameters
|
||||
for (arg in func.parameters.zip(call.arglist.withIndex())) {
|
||||
val argtype = arg.second.value.inferType(program)
|
||||
if (argtype != null) {
|
||||
if (arg.first.possibleDatatypes.any { argtype == it })
|
||||
continue
|
||||
for (possibleType in arg.first.possibleDatatypes) {
|
||||
if (argtype isAssignableTo possibleType) {
|
||||
val typecasted = TypecastExpression(arg.second.value, possibleType, arg.second.value.position)
|
||||
typecasted.linkParents(arg.second.value.parent)
|
||||
call.arglist[arg.second.index] = typecasted
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,11 +96,13 @@ class RuntimeVariables {
|
||||
return address
|
||||
}
|
||||
|
||||
fun swap(a1: VarDecl, a2: VarDecl) {
|
||||
val v1 = get(a1.definingScope(), a1.name)
|
||||
val v2 = get(a2.definingScope(), a2.name)
|
||||
set(a1.definingScope(), a1.name, v2)
|
||||
set(a2.definingScope(), a2.name, v1)
|
||||
fun swap(a1: VarDecl, a2: VarDecl) = swap(a1.definingScope(), a1.name, a2.definingScope(), a2.name)
|
||||
|
||||
fun swap(scope1: INameScope, name1: String, scope2: INameScope, name2: String) {
|
||||
val v1 = get(scope1, name1)
|
||||
val v2 = get(scope2, name2)
|
||||
set(scope1, name1, v2)
|
||||
set(scope2, name2, v1)
|
||||
}
|
||||
|
||||
private val vars = mutableMapOf<INameScope, MutableMap<String, RuntimeValue>>().withDefault { mutableMapOf() }
|
||||
@ -160,7 +162,7 @@ class AstVm(val program: Program) {
|
||||
when {
|
||||
jx.generatedLabel != null -> {
|
||||
val label = entrypoint.getLabelOrVariable(jx.generatedLabel) as Label
|
||||
TODO("$label")
|
||||
TODO("generatedlabel $label")
|
||||
}
|
||||
jx.identifier != null -> {
|
||||
when (val jumptarget = entrypoint.lookup(jx.identifier.nameInSource, jx.identifier.parent)) {
|
||||
@ -188,6 +190,7 @@ class AstVm(val program: Program) {
|
||||
|
||||
private val runtimeVariables = RuntimeVariables()
|
||||
private val functions = BuiltinFunctions()
|
||||
private val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
|
||||
|
||||
class LoopControlBreak : Exception()
|
||||
class LoopControlContinue : Exception()
|
||||
@ -205,8 +208,7 @@ class AstVm(val program: Program) {
|
||||
for (arg in sub.parameters.zip(arguments)) {
|
||||
val idref = IdentifierReference(listOf(arg.first.name), sub.position)
|
||||
performAssignment(AssignTarget(null, idref, null, null, idref.position),
|
||||
arg.second, sub.statements.first(),
|
||||
EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine))
|
||||
arg.second, sub.statements.first(), evalCtx)
|
||||
}
|
||||
|
||||
val statements = sub.statements.iterator()
|
||||
@ -239,8 +241,8 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun executeStatement(sub: INameScope, stmt: IStatement) {
|
||||
val evalCtx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
|
||||
instructionCounter++
|
||||
if (instructionCounter % 100 == 0)
|
||||
Thread.sleep(1)
|
||||
@ -396,11 +398,44 @@ class AstVm(val program: Program) {
|
||||
|
||||
private fun executeSwap(sub: INameScope, swap: FunctionCallStatement) {
|
||||
// TODO: can swap many different parameters.... in all combinations...
|
||||
println("TODO SWAP ${swap.arglist}")
|
||||
// val a1 = (swap.arglist[0] as IdentifierReference).targetVarDecl(program.namespace)!!
|
||||
// val a2 = (swap.arglist[1] as IdentifierReference).targetVarDecl(program.namespace)!!
|
||||
// runtimeVariables.swap(a1, a2)
|
||||
// TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
val v1 = swap.arglist[0]
|
||||
val v2 = swap.arglist[1]
|
||||
if(v1 is IdentifierReference && v2 is IdentifierReference) {
|
||||
val decl1 = v1.targetVarDecl(program.namespace)!!
|
||||
val decl2 = v2.targetVarDecl(program.namespace)!!
|
||||
runtimeVariables.swap(decl1, decl2)
|
||||
return
|
||||
}
|
||||
else if (v1 is RegisterExpr && v2 is RegisterExpr) {
|
||||
runtimeVariables.swap(program.namespace, v1.register.name, program.namespace, v2.register.name)
|
||||
return
|
||||
}
|
||||
else if(v1 is ArrayIndexedExpression && v2 is ArrayIndexedExpression) {
|
||||
val decl1 = v1.identifier.targetVarDecl(program.namespace)!!
|
||||
val decl2 = v2.identifier.targetVarDecl(program.namespace)!!
|
||||
val index1 = evaluate(v1.arrayspec.index, evalCtx)
|
||||
val index2 = evaluate(v2.arrayspec.index, evalCtx)
|
||||
val rvar1 = runtimeVariables.get(decl1.definingScope(), decl1.name)
|
||||
val rvar2 = runtimeVariables.get(decl2.definingScope(), decl2.name)
|
||||
val val1 = rvar1.array!![index1.integerValue()]
|
||||
val val2 = rvar2.array!![index2.integerValue()]
|
||||
val rval1 = RuntimeValue(ArrayElementTypes.getValue(rvar1.type), val1)
|
||||
val rval2 = RuntimeValue(ArrayElementTypes.getValue(rvar2.type), val2)
|
||||
performAssignment(AssignTarget(null, null, v1, null, v1.position), rval2, swap, evalCtx)
|
||||
performAssignment(AssignTarget(null, null, v2, null, v2.position), rval1, swap, evalCtx)
|
||||
return
|
||||
}
|
||||
else if(v1 is DirectMemoryRead && v2 is DirectMemoryRead) {
|
||||
val address1 = evaluate(v1.addressExpression, evalCtx).wordval!!
|
||||
val address2 = evaluate(v2.addressExpression, evalCtx).wordval!!
|
||||
val value1 = evalCtx.mem.getUByte(address1)
|
||||
val value2 = evalCtx.mem.getUByte(address2)
|
||||
evalCtx.mem.setUByte(address1, value2)
|
||||
evalCtx.mem.setUByte(address2, value1)
|
||||
return
|
||||
}
|
||||
|
||||
TODO("not implemented swap $v1 $v2")
|
||||
}
|
||||
|
||||
fun performAssignment(target: AssignTarget, value: RuntimeValue, contextStmt: IStatement, evalCtx: EvalContext) {
|
||||
@ -424,7 +459,8 @@ class AstVm(val program: Program) {
|
||||
runtimeVariables.set(decl.definingScope(), decl.name, value)
|
||||
}
|
||||
target.memoryAddress != null -> {
|
||||
TODO("assign memory")
|
||||
val address = evaluate(target.memoryAddress!!.addressExpression, evalCtx).wordval!!
|
||||
evalCtx.mem.setUByte(address, value.byteval!!)
|
||||
}
|
||||
target.arrayindexed != null -> {
|
||||
val array = evaluate(target.arrayindexed.identifier, evalCtx)
|
||||
@ -479,15 +515,11 @@ class AstVm(val program: Program) {
|
||||
private fun oneForCycle(stmt: ForLoop, loopvarDt: DataType, loopValue: Number, loopVar: IdentifierReference) {
|
||||
// assign the new loop value to the loopvar, and run the code
|
||||
performAssignment(AssignTarget(null, loopVar, null, null, loopVar.position),
|
||||
RuntimeValue(loopvarDt, loopValue), stmt.body.statements.first(),
|
||||
EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine))
|
||||
RuntimeValue(loopvarDt, loopValue), stmt.body.statements.first(), evalCtx)
|
||||
executeAnonymousScope(stmt.body)
|
||||
}
|
||||
|
||||
private fun evaluate(args: List<IExpression>): List<RuntimeValue> {
|
||||
val ctx = EvalContext(program, mem, statusflags, runtimeVariables, functions, ::executeSubroutine)
|
||||
return args.map { evaluate(it, ctx) }
|
||||
}
|
||||
private fun evaluate(args: List<IExpression>) = args.map { evaluate(it, evalCtx) }
|
||||
|
||||
private fun performSyscall(sub: Subroutine, args: List<RuntimeValue>) {
|
||||
assert(sub.isAsmSubroutine)
|
||||
|
@ -66,14 +66,7 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
||||
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)
|
||||
DataType.ARRAY_B -> RuntimeValue(DataType.BYTE, num = value)
|
||||
DataType.ARRAY_UW -> RuntimeValue(DataType.UWORD, num = value)
|
||||
DataType.ARRAY_W -> RuntimeValue(DataType.WORD, num = value)
|
||||
DataType.ARRAY_F -> RuntimeValue(DataType.FLOAT, num = value)
|
||||
else -> throw VmExecutionException("strange array type ${array.type}")
|
||||
}
|
||||
return RuntimeValue(ArrayElementTypes.getValue(array.type), value)
|
||||
}
|
||||
is TypecastExpression -> {
|
||||
return evaluate(expr.expression, ctx).cast(expr.type)
|
||||
@ -84,7 +77,8 @@ fun evaluate(expr: IExpression, ctx: EvalContext): RuntimeValue {
|
||||
return RuntimeValue(DataType.UWORD, heapId)
|
||||
}
|
||||
is DirectMemoryRead -> {
|
||||
TODO("memoryread $expr")
|
||||
val address = evaluate(expr.addressExpression, ctx).wordval!!
|
||||
return RuntimeValue(DataType.UBYTE, ctx.mem.getUByte(address))
|
||||
}
|
||||
is DirectMemoryWrite -> {
|
||||
TODO("memorywrite $expr")
|
||||
|
@ -843,12 +843,12 @@ internal class Compiler(private val program: Program): IAstProcessor {
|
||||
val arg = args.single()
|
||||
val dt = arg.inferType(program)
|
||||
when (dt) {
|
||||
DataType.UBYTE -> prog.instr(Opcode.ROL_BYTE)
|
||||
DataType.UWORD -> prog.instr(Opcode.ROL_WORD)
|
||||
in ByteDatatypes -> prog.instr(Opcode.ROL_BYTE)
|
||||
in WordDatatypes -> prog.instr(Opcode.ROL_WORD)
|
||||
else -> throw CompilerException("wrong datatype")
|
||||
}
|
||||
// this function doesn't return a value on the stack so we pop it directly into the argument register/variable again
|
||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt)
|
||||
popValueIntoTarget(AssignTarget.fromExpr(arg), dt!!)
|
||||
}
|
||||
"ror" -> {
|
||||
val arg = args.single()
|
||||
|
@ -288,13 +288,13 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
|
||||
fun rol(carry: Boolean): Pair<RuntimeValue, Boolean> {
|
||||
// 9 or 17 bit rotate left (with carry))
|
||||
return when(type) {
|
||||
DataType.UBYTE -> {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
val v = byteval!!.toInt()
|
||||
val newCarry = (v and 0x80) != 0
|
||||
val newval = (v and 0x7f shl 1) or (if(carry) 1 else 0)
|
||||
Pair(RuntimeValue(DataType.UBYTE, newval), newCarry)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
val v = wordval!!
|
||||
val newCarry = (v and 0x8000) != 0
|
||||
val newval = (v and 0x7fff shl 1) or (if(carry) 1 else 0)
|
||||
@ -307,13 +307,13 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
|
||||
fun ror(carry: Boolean): Pair<RuntimeValue, Boolean> {
|
||||
// 9 or 17 bit rotate right (with carry)
|
||||
return when(type) {
|
||||
DataType.UBYTE -> {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
val v = byteval!!.toInt()
|
||||
val newCarry = v and 1 != 0
|
||||
val newval = (v ushr 1) or (if(carry) 0x80 else 0)
|
||||
Pair(RuntimeValue(DataType.UBYTE, newval), newCarry)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
val v = wordval!!
|
||||
val newCarry = v and 1 != 0
|
||||
val newval = (v ushr 1) or (if(carry) 0x8000 else 0)
|
||||
@ -326,13 +326,13 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
|
||||
fun rol2(): RuntimeValue {
|
||||
// 8 or 16 bit rotate left
|
||||
return when(type) {
|
||||
DataType.UBYTE -> {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
val v = byteval!!.toInt()
|
||||
val carry = (v and 0x80) ushr 7
|
||||
val newval = (v and 0x7f shl 1) or carry
|
||||
RuntimeValue(DataType.UBYTE, newval)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
val v = wordval!!
|
||||
val carry = (v and 0x8000) ushr 15
|
||||
val newval = (v and 0x7fff shl 1) or carry
|
||||
@ -345,13 +345,13 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?=
|
||||
fun ror2(): RuntimeValue {
|
||||
// 8 or 16 bit rotate right
|
||||
return when(type) {
|
||||
DataType.UBYTE -> {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
val v = byteval!!.toInt()
|
||||
val carry = v and 1 shl 7
|
||||
val newval = (v ushr 1) or carry
|
||||
RuntimeValue(DataType.UBYTE, newval)
|
||||
}
|
||||
DataType.UWORD -> {
|
||||
DataType.UWORD, DataType.WORD -> {
|
||||
val v = wordval!!
|
||||
val carry = v and 1 shl 15
|
||||
val newval = (v ushr 1) or carry
|
||||
|
@ -126,11 +126,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, program
|
||||
return when(dt) {
|
||||
in NumericDatatypes -> dt!!
|
||||
in StringDatatypes -> dt!!
|
||||
DataType.ARRAY_UB -> DataType.UBYTE
|
||||
DataType.ARRAY_B -> DataType.BYTE
|
||||
DataType.ARRAY_UW -> DataType.UWORD
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
in ArrayDatatypes -> ArrayElementTypes.getValue(dt!!)
|
||||
else -> throw FatalAstException("function '$function' requires one argument which is an iterable")
|
||||
}
|
||||
}
|
||||
@ -157,11 +153,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, program
|
||||
when(dt) {
|
||||
in NumericDatatypes -> dt
|
||||
in StringDatatypes -> DataType.UBYTE
|
||||
DataType.ARRAY_UB -> DataType.UBYTE
|
||||
DataType.ARRAY_B -> DataType.BYTE
|
||||
DataType.ARRAY_UW -> DataType.UWORD
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
in ArrayDatatypes -> ArrayElementTypes.getValue(dt)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,37 @@
|
||||
~ main {
|
||||
|
||||
sub start() {
|
||||
ubyte[100] arr1
|
||||
ubyte[100] arr2
|
||||
; TODO array to heap ubyte[100] arr1 = 1 to 100
|
||||
; TODO array to heap ubyte[100] arr2 = 101 to 200
|
||||
|
||||
|
||||
&ubyte m1 = $d020
|
||||
&uword mw1 = $c000
|
||||
|
||||
ubyte[] arr1 = [1,2,3,4,5,6,7,8,9,10,11]
|
||||
ubyte[] arr2 = [11,22,33,44,55,66,77,88,99,100,101]
|
||||
|
||||
word w1 = 1111
|
||||
word w2 = 2222
|
||||
|
||||
m1 = 0
|
||||
mw1 = 65535
|
||||
|
||||
Y = @($d020)
|
||||
@($d020) = A
|
||||
|
||||
ror(w1)
|
||||
ror2(w1)
|
||||
rol(w1)
|
||||
rol2(w1)
|
||||
lsr(w1)
|
||||
lsl(w1)
|
||||
|
||||
swap(w1, w2)
|
||||
swap(A, Y)
|
||||
swap(arr1[10], arr2[20])
|
||||
swap(arr1[10], Y)
|
||||
swap(Y, arr2[10])
|
||||
swap(arr1[4], arr2[9])
|
||||
; TODO swap(arr1[4], Y)
|
||||
; TODO swap(Y, arr2[9])
|
||||
swap(@($d020), @($d021))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user