diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index d520453e7..67dfab042 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -814,8 +814,11 @@ private class AstChecker(private val namespace: INameScope, else { for (arg in args.withIndex().zip(target.parameters)) { val argDt = arg.first.value.resultingDatatype(namespace, heap) - if(argDt!=null && !argDt.assignableTo(arg.second.type)) - checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index+1} has invalid type $argDt, expected ${arg.second.type}", position)) + if(argDt!=null && !argDt.assignableTo(arg.second.type)) { + // for asm subroutines having STR param it's okay to provide a UWORD too (pointer value) + if(!(target.isAsmSubroutine && arg.second.type in StringDatatypes && argDt==DataType.UWORD)) + checkResult.add(ExpressionError("subroutine '${target.name}' argument ${arg.first.index + 1} has invalid type $argDt, expected ${arg.second.type}", position)) + } if(target.isAsmSubroutine) { if (target.asmParameterRegisters[arg.first.index].registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.XY, RegisterOrPair.X)) { diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 23a3e8d2f..a91830e95 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -14,13 +14,13 @@ fun Module.checkIdentifiers(namespace: INameScope) { // add any anonymous variables for heap values that are used, // and replace an iterable literalvalue by identifierref to new local variable - for (variable in checker.anonymousVariablesFromHeap) { + for (variable in checker.anonymousVariablesFromHeap.values) { val scope = variable.first.definingScope() scope.statements.add(variable.second) val parent = variable.first.parent when { parent is Assignment && parent.value === variable.first -> { - val idref = IdentifierReference(listOf("$autoHeapValuePrefix${variable.first.heapId}"), variable.first.position) + val idref = IdentifierReference(listOf("$${variable.first.heapId}"), variable.first.position) idref.linkParents(parent) parent.value = idref } @@ -217,7 +217,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro } - internal val anonymousVariablesFromHeap = mutableSetOf>() + internal val anonymousVariablesFromHeap = mutableMapOf>() override fun process(literalValue: LiteralValue): LiteralValue { @@ -225,10 +225,10 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro // a literal value that's not declared as a variable, which refers to something on the heap. // we need to introduce an auto-generated variable for this to be able to refer to the value! val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, literalValue.position) - anonymousVariablesFromHeap.add(Pair(literalValue, variable)) + anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable) } return super.process(literalValue) } } -private const val autoHeapValuePrefix = "auto_heap_value_" +internal const val autoHeapValuePrefix = "auto_heap_value_" diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index ec7e93547..a04142963 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -3,7 +3,7 @@ package prog8.ast import prog8.compiler.HeapValues fun Module.reorderStatements(namespace: INameScope, heap: HeapValues) { - val initvalueCreator = VarInitValueCreator() + val initvalueCreator = VarInitValueAndPointerOfCreator(namespace) this.process(initvalueCreator) val checker = StatementReorderer(namespace, heap) @@ -203,7 +203,7 @@ private class StatementReorderer(private val namespace: INameScope, private val } -private class VarInitValueCreator: IAstProcessor { +private class VarInitValueAndPointerOfCreator(private val namespace: INameScope): IAstProcessor { // Replace the var decl with an assignment and add a new vardecl with the default constant value. // This makes sure the variables get reset to the intended value on a next run of the program. // Variable decls without a value don't get this treatment, which means they retain the last @@ -211,6 +211,9 @@ private class VarInitValueCreator: IAstProcessor { // This is done in a separate step because it interferes with the namespace lookup of symbols // in other ast processors. + // Also takes care to insert PointerOf (&) expression where required (string params to a UWORD function param etc). + + private val vardeclsToAdd = mutableMapOf>() override fun process(module: Module) { @@ -252,4 +255,33 @@ private class VarInitValueCreator: IAstProcessor { return decl } + override fun process(functionCall: FunctionCall): IExpression { + val targetStatement = functionCall.target.targetStatement(namespace) as? Subroutine + if(targetStatement!=null) + addPointerToIfNeeded(targetStatement, functionCall.arglist, functionCall) + return functionCall + } + + override fun process(functionCallStatement: FunctionCallStatement): IStatement { + val targetStatement = functionCallStatement.target.targetStatement(namespace) as? Subroutine + if(targetStatement!=null) + addPointerToIfNeeded(targetStatement, functionCallStatement.arglist, functionCallStatement) + return functionCallStatement + } + + private fun addPointerToIfNeeded(subroutine: Subroutine, arglist: MutableList, parent: Node) { + // functions that accept UWORD and are given an array type, or string, will receive the Pointer (memory location) of that value instead. + for(argparam in subroutine.parameters.withIndex().zip(arglist)) { + if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type in StringDatatypes) { + val strvalue = argparam.second as? LiteralValue + if(strvalue!=null && strvalue.isString) { + val idref = IdentifierReference(listOf("$autoHeapValuePrefix${strvalue.heapId}"), strvalue.position) // TODO why does this result later in "pointer-of operand must be the name of a heap variable" + val pointerExpr = PointerOf(idref, strvalue.position) + pointerExpr.linkParents(arglist[argparam.first.index].parent) + arglist[argparam.first.index] = pointerExpr + } + } + } + } + } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 0b45c7447..5cfc2927e 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1089,19 +1089,7 @@ internal class Compiler(private val rootModule: Module, translate(arg.first) prog.instr(Opcode.POP_REGAX_WORD) } - // TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available - DataType.STR, DataType.STR_S -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGAX_WORD) - } - DataType.FLOAT -> { - pushFloatAddress(arg.first) - prog.instr(Opcode.POP_REGAX_WORD) - } - in ArrayDatatypes -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGAX_WORD) - } + in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition") else -> TODO("pass parameter of type $paramDt in registers AX at $callPosition") } } @@ -1124,19 +1112,7 @@ internal class Compiler(private val rootModule: Module, translate(arg.first) prog.instr(Opcode.POP_REGAY_WORD) } - // TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available - DataType.STR, DataType.STR_S -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGAY_WORD) - } - DataType.FLOAT -> { - pushFloatAddress(arg.first) - prog.instr(Opcode.POP_REGAY_WORD) - } - in ArrayDatatypes -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGAY_WORD) - } + in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition") else -> TODO("pass parameter of type $paramDt in registers AY at $callPosition") } } @@ -1163,19 +1139,7 @@ internal class Compiler(private val rootModule: Module, translate(arg.first) prog.instr(Opcode.POP_REGXY_WORD) } - // TODO auto-converting str/float/array to their pointer value should be done by explicitly rewriting the Ast into a pointer-of expression, once that is available - DataType.STR, DataType.STR_S -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGXY_WORD) - } - DataType.FLOAT -> { - pushFloatAddress(arg.first) - prog.instr(Opcode.POP_REGXY_WORD) - } - in ArrayDatatypes -> { - pushHeapVarAddress(arg.first, false) - prog.instr(Opcode.POP_REGXY_WORD) - } + in StringDatatypes + ArrayDatatypes -> throw CompilerException("string or array arguments should have been converted to their pointer value in the Ast $callPosition") else -> TODO("pass parameter of type $paramDt in registers XY at $callPosition") } } diff --git a/examples/test.p8 b/examples/test.p8 index ac5d12992..036b473b5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -106,9 +106,15 @@ ;uword[4] pointers = [&array1, &array2, &string1, &string2] ; @todo make it possible to initialize array with pointers + ;ptrsubasm("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler) ;pointersub("moet werken") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler) - ;myprintasm("moet werken3") ; @todo rewrite ast into pointer-of expression (and remove special cases from Compiler) + + myprintasm("moet werken3") + myprintasm("moet werken3") + myprintasm("moet werken4") + + c64.CHROUT('\n') ptrsubasm(&array1) ptrsubasm(&array2)