From ff3f985658e72ff96b2fe4e578a5ffc0bf70af35 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 22 Oct 2020 23:41:16 +0200 Subject: [PATCH] refactoring --- compiler/res/prog8lib/diskio.p8 | 3 +- compiler/res/version.txt | 2 +- .../src/prog8/ast/processing/AstChecker.kt | 26 +++++------ .../ast/processing/StatementReorderer.kt | 2 +- .../prog8/ast/processing/TypecastsAdder.kt | 44 +++++++++---------- .../ast/processing/VerifyFunctionArgTypes.kt | 10 ++--- .../src/prog8/ast/statements/AstStatements.kt | 6 +-- .../target/c64/codegen/FunctionCallAsmGen.kt | 2 +- docs/source/programming.rst | 4 +- docs/source/todo.rst | 9 ++-- examples/test.p8 | 23 ++++------ 11 files changed, 64 insertions(+), 67 deletions(-) diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index b9466c16a..67f133728 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -151,8 +151,7 @@ io_error: filename[0] = 'r' filename[1] = ':' memcopy(newfileptr, &filename+2, flen_new) - ubyte fis_ix = flen_new+2 ; TODO is temp var for array indexing - filename[fis_ix] = '=' + filename[flen_new+2] = '=' memcopy(oldfileptr, &filename+3+flen_new, flen_old+1) c64.SETNAM(3+flen_new+flen_old, filename) c64.SETLFS(1, drivenumber, 15) diff --git a/compiler/res/version.txt b/compiler/res/version.txt index b3d791d75..318489dff 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -4.6 +4.7-SNAPSHOT diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 88561462e..d874861fb 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -250,19 +250,19 @@ internal class AstChecker(private val program: Program, err("parameter '${param.first.name}' should be ubyte") } } - for(ret in subroutine.returntypes.withIndex().zip(subroutine.asmReturnvaluesRegisters)) { - if(ret.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { - if (ret.first.value != DataType.UBYTE && ret.first.value != DataType.BYTE) - err("return value #${ret.first.index + 1} should be (u)byte") + subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).forEachIndexed { index, pair -> + if(pair.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { + if (pair.first != DataType.UBYTE && pair.first != DataType.BYTE) + err("return value #${index + 1} should be (u)byte") } - else if(ret.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { - if (ret.first.value != DataType.UWORD && ret.first.value != DataType.WORD - && ret.first.value != DataType.STR && ret.first.value !in ArrayDatatypes && ret.first.value != DataType.FLOAT) - err("return value #${ret.first.index + 1} should be (u)word/address") + else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { + if (pair.first != DataType.UWORD && pair.first != DataType.WORD + && pair.first != DataType.STR && pair.first !in ArrayDatatypes && pair.first != DataType.FLOAT) + err("return value #${index + 1} should be (u)word/address") } - else if(ret.second.statusflag!=null) { - if (ret.first.value != DataType.UBYTE) - err("return value #${ret.first.index + 1} should be ubyte") + else if(pair.second.statusflag!=null) { + if (pair.first != DataType.UBYTE) + err("return value #${index + 1} should be ubyte") } } @@ -984,8 +984,8 @@ internal class AstChecker(private val program: Program, if(target.regXasResult()) errors.warn("subroutine call return value in X register is discarded and replaced by 0", position) if(target.isAsmSubroutine) { - for (arg in args.withIndex().zip(target.parameters)) { - val argIDt = arg.first.value.inferType(program) + for (arg in args.zip(target.parameters)) { + val argIDt = arg.first.inferType(program) if (!argIDt.isKnown) return } diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index d116f7962..50a153fc8 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -279,7 +279,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte } // TODO use a pointer loop instead of individual assignments - return alv.value.withIndex().map { (index, value)-> + return alv.value.mapIndexed { index, value -> val idx = ArrayIndexedExpression(identifier, ArrayIndex(NumericLiteralValue(DataType.UBYTE, index, position), position), position) Assignment(AssignTarget(null, idx, null, position), value, value.position) } diff --git a/compiler/src/prog8/ast/processing/TypecastsAdder.kt b/compiler/src/prog8/ast/processing/TypecastsAdder.kt index eb638efbf..052a2555b 100644 --- a/compiler/src/prog8/ast/processing/TypecastsAdder.kt +++ b/compiler/src/prog8/ast/processing/TypecastsAdder.kt @@ -116,30 +116,30 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke when(val sub = call.target.targetStatement(scope)) { is Subroutine -> { - for(arg in sub.parameters.zip(call.args.withIndex())) { - val argItype = arg.second.value.inferType(program) + sub.parameters.zip(call.args).forEachIndexed { index, pair -> + val argItype = pair.second.inferType(program) if(argItype.isKnown) { val argtype = argItype.typeOrElse(DataType.STRUCT) - val requiredType = arg.first.type + val requiredType = pair.first.type if (requiredType != argtype) { if (argtype isAssignableTo requiredType) { modifications += IAstModification.ReplaceNode( - call.args[arg.second.index], - TypecastExpression(arg.second.value, requiredType, true, arg.second.value.position), + call.args[index], + TypecastExpression(pair.second, requiredType, true, pair.second.position), call as Node) } else if(requiredType == DataType.UWORD && argtype in PassByReferenceDatatypes) { // we allow STR/ARRAY values in place of UWORD parameters. Take their address instead. - if(arg.second.value is IdentifierReference) { + if(pair.second is IdentifierReference) { modifications += IAstModification.ReplaceNode( - call.args[arg.second.index], - AddressOf(arg.second.value as IdentifierReference, arg.second.value.position), + call.args[index], + AddressOf(pair.second as IdentifierReference, pair.second.position), call as Node) } - } else if(arg.second.value is NumericLiteralValue) { - val cast = (arg.second.value as NumericLiteralValue).cast(requiredType) + } else if(pair.second is NumericLiteralValue) { + val cast = (pair.second as NumericLiteralValue).cast(requiredType) if(cast.isValid) modifications += IAstModification.ReplaceNode( - call.args[arg.second.index], + call.args[index], cast.valueOrZero(), call as Node) } @@ -149,19 +149,19 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke } is BuiltinFunctionStatementPlaceholder -> { val func = BuiltinFunctions.getValue(sub.name) - for (arg in func.parameters.zip(call.args.withIndex())) { - val argItype = arg.second.value.inferType(program) + func.parameters.zip(call.args).forEachIndexed { index, pair -> + val argItype = pair.second.inferType(program) if (argItype.isKnown) { val argtype = argItype.typeOrElse(DataType.STRUCT) - if (arg.first.possibleDatatypes.any { argtype == it }) - continue - for (possibleType in arg.first.possibleDatatypes) { - if (argtype isAssignableTo possibleType) { - modifications += IAstModification.ReplaceNode( - call.args[arg.second.index], - TypecastExpression(arg.second.value, possibleType, true, arg.second.value.position), - call as Node) - break + if (pair.first.possibleDatatypes.all { argtype != it }) { + for (possibleType in pair.first.possibleDatatypes) { + if (argtype isAssignableTo possibleType) { + modifications += IAstModification.ReplaceNode( + call.args[index], + TypecastExpression(pair.second, possibleType, true, pair.second.position), + call as Node) + break + } } } } diff --git a/compiler/src/prog8/ast/processing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/ast/processing/VerifyFunctionArgTypes.kt index 584ee6c87..8765e727d 100644 --- a/compiler/src/prog8/ast/processing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/ast/processing/VerifyFunctionArgTypes.kt @@ -67,12 +67,12 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor { if(call.args.size != func.parameters.size) return "invalid number of arguments" val paramtypes = func.parameters.map { it.possibleDatatypes } - for (x in argtypes.zip(paramtypes).withIndex()) { - val anyCompatible = x.value.second.any { argTypeCompatible(x.value.first, it) } + argtypes.zip(paramtypes).forEachIndexed { index, pair -> + val anyCompatible = pair.second.any { argTypeCompatible(pair.first, it) } if (!anyCompatible) { - val actual = x.value.first.toString() - val expected = x.value.second.toString() - return "argument ${x.index + 1} type mismatch, was: $actual expected: $expected" + val actual = pair.first.toString() + val expected = pair.second.toString() + return "argument ${index + 1} type mismatch, was: $actual expected: $expected" } } } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index fd531bc3c..8899b493a 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -252,9 +252,9 @@ open class VarDecl(val type: VarDeclType, } fun flattenStructMembers(): MutableList { - val result = struct!!.statements.withIndex().map { - val member = it.value as VarDecl - val initvalue = if(value!=null) (value as ArrayLiteralValue).value[it.index] else null + val result = struct!!.statements.mapIndexed { index, statement -> + val member = statement as VarDecl + val initvalue = if(value!=null) (value as ArrayLiteralValue).value[index] else null VarDecl( VarDeclType.VAR, member.datatype, diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 5603ef778..c8556b641 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -33,7 +33,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // via registers if(sub.parameters.size==1) { // just a single parameter, no risk of clobbering registers - argumentViaRegister(sub, sub.parameters.withIndex().single(), stmt.args[0]) + argumentViaRegister(sub, IndexedValue(0, sub.parameters.single()), stmt.args[0]) } else { // multiple register arguments, risk of register clobbering. // evaluate arguments onto the stack, and load the registers from the evaluated values on the stack. diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 37106ffa9..21b376f26 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -775,8 +775,8 @@ memcopy(from, to, numbytes) memset(address, numbytes, bytevalue) Efficiently set a part of memory to the given (u)byte value. But the most efficient will always be to write a specialized fill routine in assembly yourself! - Note that for clearing the character screen, very fast specialized subroutines are - available in the ``txt`` block (part of the ``textio`` module) + Note that for clearing the screen, very fast specialized subroutines are + available in the ``textio`` and ``graphics`` library modules. memsetw(address, numwords, wordvalue) Efficiently set a part of memory to the given (u)word value. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ec1fd333b..43bc58b79 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,14 +2,17 @@ TODO ==== -- get rid of all other TODO's in the code ;-) -- implement @stack for asmsub parameters +- make memset(w) and memcopy able to work with >256 bytes +- make memset and memcopy use the ROM routines on the CX16 +- calling convention for builtin functions no longer via stack but via statically allocated vars inside the subroutine proc (just as normal subroutines) +- get rid of @stack in asmsub altogether (because all subroutines are no longer using this calling convention anymore) - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) - see if we can group some errors together for instance the (now single) errors about unidentified symbols - use VIC banking to move up the graphics bitmap memory location. Don't move it under the ROM though as that would require IRQ disabling and memory bank swapping for every bitmap manipulation - add some primitives/subroutines/examples for using custom char sets, copying the default charset. -- recursive subroutines? via %option recursive, allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters +- some better handling of recursive subroutines? via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters +- get rid of all other TODO's in the code ;-) More optimizations ^^^^^^^^^^^^^^^^^^ diff --git a/examples/test.p8 b/examples/test.p8 index d102daf86..245ff8276 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,26 +1,21 @@ %import textio -%import conv -%import floats +%import diskio %zeropage basicsafe main { sub start() { - - uword[] array = [1, 2, 3] - ubyte ii = 0 - ubyte ii2 = ii+2 - array[ii+1] = array[ii2] ; TODO fix overwriting the single array index autovar - - uword xx - for xx in array { - txt.print_uw(xx) - txt.chrout('\n') - } - + memcopy($aaaa, $bbbb, 200) + mcp($aaaa, $bbbb, 200) testX() } + sub mcp(uword from, uword dest, ubyte length) { + txt.print_uw(from) + txt.print_uw(dest) + txt.print_ub(length) + } + asmsub testX() { %asm {{ stx _saveX