more swap logic, some typing fixes

This commit is contained in:
Irmen de Jong 2019-06-28 22:10:01 +02:00
parent 6c50043a4a
commit 267c678292
9 changed files with 140 additions and 68 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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