From aaa81210ce8cf70dab65f20b34b22650a9387ef2 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 25 May 2025 02:56:32 +0200 Subject: [PATCH] cleaning up pointer indexing --- .../codegen/intermediate/AssignmentGen.kt | 4 - .../codegen/intermediate/ExpressionGen.kt | 58 ------ .../optimizer/ConstantFoldingOptimizer.kt | 18 +- .../prog8/optimizer/ExpressionSimplifier.kt | 39 ++-- .../compiler/astprocessing/AstChecker.kt | 96 +++++----- .../compiler/astprocessing/CodeDesugarer.kt | 58 +++--- ...teralsToAutoVarsAndRecombineIdentifiers.kt | 17 +- .../astprocessing/SimplifiedAstMaker.kt | 36 ++-- .../astprocessing/SimplifiedAstPostprocess.kt | 2 - .../compiler/astprocessing/TypecastsAdder.kt | 2 +- .../compiler/astprocessing/VariousCleanups.kt | 24 +-- compiler/test/TestMemory.kt | 6 +- compiler/test/TestPointers.kt | 117 ++++++++++-- compiler/test/ast/TestAstChecks.kt | 7 +- .../src/prog8/ast/AstToSourceTextConverter.kt | 9 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 25 +-- .../prog8/ast/expressions/AstExpressions.kt | 169 +++++++++--------- .../src/prog8/ast/statements/AstStatements.kt | 49 ++--- compilerAst/src/prog8/ast/walk/AstWalker.kt | 12 +- compilerAst/src/prog8/ast/walk/IAstVisitor.kt | 8 +- docs/source/todo.rst | 4 +- examples/test.p8 | 17 +- parser/src/main/antlr/Prog8ANTLR.g4 | 5 - .../src/prog8/code/ast/AstExpressions.kt | 11 -- simpleAst/src/prog8/code/ast/AstPrinter.kt | 3 - simpleAst/src/prog8/code/ast/AstStatements.kt | 3 - 26 files changed, 382 insertions(+), 417 deletions(-) diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 5c4af06a5..60f154601 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -409,7 +409,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val targetMemory = assignment.target.memory val targetArray = assignment.target.array val targetPointerDeref = assignment.target.pointerDeref - val targetPointerIndexedDeref = assignment.target.pointerIndexedDeref val valueDt = irType(assignment.value.type) val targetDt = irType(assignment.target.type) val result = mutableListOf() @@ -604,9 +603,6 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express codeGen.storeValueAtPointersLocation(result, addressReg, targetPointerDeref.type, zero, actualValueReg) return result } - else if(targetPointerIndexedDeref!=null) { - TODO("assign to pointer indexed $targetPointerIndexedDeref") - } else throw AssemblyError("weird assigntarget") } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index fdd88d056..d7f2e1f28 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -87,70 +87,12 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { is PtFunctionCall -> translate(expr) is PtContainmentCheck -> translate(expr) is PtPointerDeref -> translate(expr) - is PtPointerIndexedDeref -> translate(expr) is PtRange, is PtArray, is PtString -> throw AssemblyError("range/arrayliteral/string should no longer occur as expression") } } - private fun translate(idxderef: PtPointerIndexedDeref): ExpressionCodeResult { - if (idxderef.type.isStructInstance) - throw AssemblyError("cannot translate POINTER[x] resulting in a struct instance (only when it results in a basic type); this is likely part of a larger expression POINTER[x].field and that has to be translated earlier as a whole") - - val eltSize = codeGen.program.memsizer.memorySize(idxderef.type, null) - val result = mutableListOf() - if(!idxderef.variable.type.isPointer) { - TODO("expression: indexing non-pointer field ${idxderef.variable}") - } - - TODO("expression: evaluate address of pointer dereference ${idxderef.position}") - - val pointerReg = -1 // pointerTr.resultReg - val constIndex = idxderef.index.asConstInteger() - if(constIndex!=null) { - val offset = constIndex * eltSize - addInstr(result, IRInstruction(Opcode.ADD, IRDataType.WORD, reg1 = pointerReg, immediate = offset), null) - } else { - val indexTr = translateExpression(idxderef.index) - result += indexTr.chunks - result += IRCodeChunk(null, null).also { - val indexReg: Int - if (idxderef.index.type.isByte) { - // extend array index to word - indexReg = codeGen.registers.next(IRDataType.WORD) - it += IRInstruction(Opcode.EXT, IRDataType.BYTE, indexReg, indexTr.resultReg) - } else { - indexReg = indexTr.resultReg - } - it += codeGen.multiplyByConst(DataType.UWORD, indexReg, eltSize) - it += IRInstruction(Opcode.ADDR, IRDataType.WORD, reg1 = pointerReg, reg2 = indexReg) - } - } - - when { - idxderef.type.isByteOrBool -> { - val resultReg = codeGen.registers.next(IRDataType.BYTE) - addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.BYTE, reg1 = resultReg, reg2 = pointerReg), null) - return ExpressionCodeResult(result, IRDataType.BYTE, resultReg, -1) - } - - idxderef.type.isWord || idxderef.type.isPointer -> { - // LOADI has an exception to allow reg1 and reg2 to be the same, so we can avoid using extra temporary registers and LOADS - addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.WORD, reg1 = pointerReg, reg2 = pointerReg), null) - return ExpressionCodeResult(result, IRDataType.WORD, pointerReg, -1) - } - - idxderef.type.isFloat -> { - val resultReg = codeGen.registers.next(IRDataType.FLOAT) - addInstr(result, IRInstruction(Opcode.LOADI, IRDataType.FLOAT, fpReg1 = resultReg, reg1 = pointerReg), null) - return ExpressionCodeResult(result, IRDataType.FLOAT, -1, resultReg) - } - - else -> throw AssemblyError("unsupported dereference type ${idxderef.type} at ${idxderef.position}") - } - } - private fun translate(deref: PtPointerDeref): ExpressionCodeResult { val result = mutableListOf() var actualDeref = deref diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index e4f65391f..e1f8e8143 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -332,15 +332,19 @@ class ConstantFoldingOptimizer(private val program: Program, private val errors: val constIndex = arrayIndexedExpression.indexer.constIndex() if (constIndex != null) { - val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl() - if(arrayVar!=null) { - val array =arrayVar.value as? ArrayLiteral - if(array!=null) { - val value = array.value[constIndex].constValue(program) - if(value!=null) { - return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, value, parent)) + if(arrayIndexedExpression.plainarrayvar!=null) { + val arrayVar = arrayIndexedExpression.plainarrayvar!!.targetVarDecl() + if(arrayVar!=null) { + val array =arrayVar.value as? ArrayLiteral + if(array!=null) { + val value = array.value[constIndex].constValue(program) + if(value!=null) { + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, value, parent)) + } } } + } else if(arrayIndexedExpression.pointerderef!=null) { + TODO("constant fold pointer[i]") } } } diff --git a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt index e499a189d..2dde34007 100644 --- a/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/codeOptimizers/src/prog8/optimizer/ExpressionSimplifier.kt @@ -424,27 +424,26 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr } override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { - if(parent is PtrIndexedDereference) - return noModifications - if(arrayIndexedExpression.indexer.constIndex()==0) { - val dt = arrayIndexedExpression.arrayvar.inferType(program).getOrUndef() - if(dt.isPointer) { - // pointer[0] --> pointer^^ - if(dt.sub==null) { - val parentExpr = parent as? BinaryExpression - if(parentExpr?.operator=="." && parentExpr.right is IdentifierReference) { - // we're part of an expression: pointer[x].ptr.ptr.field - val chain = (parentExpr.right as? IdentifierReference)?.nameInSource?.toMutableList() ?: mutableListOf() - val field = chain.removeLastOrNull() - val deref = PtrDereference(arrayIndexedExpression.arrayvar, chain, field, field==null, arrayIndexedExpression.position) - return listOf(IAstModification.ReplaceNode(parent, deref, parent.parent)) - } else - throw FatalAstException("cannot dereference a 'bare' pointer to a struct, only to a basic type at ${arrayIndexedExpression.position}") - } else { - // points to a simple type, can simply dereference the pointer itself directly - val deref = PtrDereference(arrayIndexedExpression.arrayvar, emptyList(), null, true,arrayIndexedExpression.position) - return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, deref, parent)) + if(arrayIndexedExpression.plainarrayvar!=null) { + val dt = arrayIndexedExpression.plainarrayvar!!.inferType(program).getOrUndef() + if(dt.isPointer) { + // pointer[0] --> pointer^^ + val deref = PtrDereference(arrayIndexedExpression.plainarrayvar!!, emptyList(), null, true, arrayIndexedExpression.plainarrayvar!!.position) + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression,deref, parent)) + } + } + val ptrDeref = arrayIndexedExpression.pointerderef + if(ptrDeref!=null) { + val dt = ptrDeref.inferType(program).getOrUndef() + if(dt.isPointer) { + if(ptrDeref.field!=null) { + // pointer[0] --> pointer^^ + val deref = PtrDereference(ptrDeref.identifier, ptrDeref.chain + ptrDeref.field!!, null, true, ptrDeref.position) + return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, deref, parent)) + } else { + TODO("ptr[0] rewrite") + } } } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 59ad2a9af..1089016d9 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -88,9 +88,6 @@ internal class AstChecker(private val program: Program, val ppExpr = identifier.parent.parent as? BinaryExpression if(ppExpr?.operator==".") return // identifiers will be checked over at the BinaryExpression itself - val ppIdxExpr = identifier.parent.parent as? PtrIndexedDereference - if(ppIdxExpr!=null) - return // identifiers will be checked over at the PtrIndexedDereference itself } errors.undefined(identifier.nameInSource, identifier.position) } @@ -770,10 +767,13 @@ internal class AstChecker(private val program: Program, fun checkRomTarget(target: AssignTarget) { val idx=target.arrayindexed if(idx!=null) { - val decl = idx.arrayvar.targetVarDecl()!! - if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) { - // memory mapped arrays are assumed to be in RAM. If they're not.... well, POOF - errors.err("cannot assign to an array or string that is located in ROM (option romable is enabled)", assignTarget.position) + // cannot check pointer deref for rom target, assume no there. + if(idx.plainarrayvar!=null) { + val decl = idx.plainarrayvar!!.targetVarDecl()!! + if(decl.type!=VarDeclType.MEMORY && decl.zeropage!=ZeropageWish.REQUIRE_ZEROPAGE) { + // memory mapped arrays are assumed to be in RAM. If they're not.... well, POOF + errors.err("cannot assign to an array or string that is located in ROM (option romable is enabled)", assignTarget.position) + } } } } @@ -1336,7 +1336,8 @@ internal class AstChecker(private val program: Program, leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl } else if(leftIndexer!=null) { // ARRAY[x].NAME --> maybe it's a pointer dereference - leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl + TODO("array[x].name pointer check?") + // leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl } else null if (struct != null) { @@ -1366,21 +1367,22 @@ internal class AstChecker(private val program: Program, } else if(rightIndexer!=null) { val leftDt = expr.left.inferType(program) if(leftDt.isStructInstance) { - // pointer[x].field[y] --> type is the dt of 'field' - var struct = leftDt.getOrUndef().subType as? StructDecl - if (struct==null) { - errors.err("cannot find struct type", expr.position) - } else { - var fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) - if (fieldDt == null) - errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${(leftDt.getOrUndef().subType as? StructDecl)?.name}'", expr.position) - else { - struct = fieldDt.subType as StructDecl - fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) - if(fieldDt==null) - errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${struct.name}'", expr.position) - } - } + TODO("pointer[x].field[y] ??") +// // pointer[x].field[y] --> type is the dt of 'field' +// var struct = leftDt.getOrUndef().subType as? StructDecl +// if (struct==null) { +// errors.err("cannot find struct type", expr.position) +// } else { +// var fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) +// if (fieldDt == null) +// errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${(leftDt.getOrUndef().subType as? StructDecl)?.name}'", expr.position) +// else { +// struct = fieldDt.subType as StructDecl +// fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) +// if(fieldDt==null) +// errors.err("no such field '${rightIndexer.arrayvar.nameInSource.single()}' in struct '${struct.name}'", expr.position) +// } +// } } else { errors.err("at the moment it is not possible to chain array syntax on pointers like ...p1[x].p2[y]... use separate expressions for the time being", expr.right.position) // TODO add support for chained array syntax on pointers (rewrite ast?) // TODO I don't think we can evaluate this because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error? @@ -1843,7 +1845,7 @@ internal class AstChecker(private val program: Program, override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { checkLongType(arrayIndexedExpression) - val target = arrayIndexedExpression.arrayvar.targetStatement(program.builtinFunctions) + val target = arrayIndexedExpression.plainarrayvar?.targetStatement(program.builtinFunctions) if(target is VarDecl) { if (!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer) errors.err( @@ -1875,26 +1877,36 @@ internal class AstChecker(private val program: Program, } else if (index != null && index < 0) { errors.err("index out of bounds", arrayIndexedExpression.indexer.position) } - } else if(target is StructFieldRef) { - if(!target.type.isPointer && !target.type.isUnsignedWord) + } else if(target!=null) { + throw FatalAstException("target is not a variable") + } + + if(arrayIndexedExpression.pointerderef!=null) { + val dt = arrayIndexedExpression.pointerderef!!.inferType(program) + if(!dt.isPointer && !dt.isUnsignedWord && !dt.isIterable) { errors.err("cannot array index on this field type", arrayIndexedExpression.indexer.position) - } else { - val parentExpr = arrayIndexedExpression.parent - if(parentExpr is BinaryExpression) { - if (parentExpr.operator != ".") - errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position) - } else if(parentExpr is PtrIndexedDereference) { - // all is fine - } else { - errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position) } +// else if(target is StructFieldRef) { +// if(!target.type.isPointer && !target.type.isUnsignedWord) +// errors.err("cannot array index on this field type", arrayIndexedExpression.indexer.position) +// } else { +// val parentExpr = arrayIndexedExpression.parent +// if(parentExpr is BinaryExpression) { +// if (parentExpr.operator != ".") +// errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position) +// } else if(parentExpr is PtrIndexedDereference) { +// // all is fine +// } else { +// errors.err("indexing requires a variable to act upon", arrayIndexedExpression.position) +// } +// } } // check index value 0..255 if the index variable is not a pointer val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) if(dtxNum.isKnown) { - val arrayVarDt = arrayIndexedExpression.arrayvar.inferType(program) - if (!arrayVarDt.isPointer && !(dtxNum issimpletype BaseDataType.UBYTE) && !(dtxNum issimpletype BaseDataType.BYTE)) + val arrayVarDt = arrayIndexedExpression.plainarrayvar?.inferType(program) + if (arrayVarDt!=null && !arrayVarDt.isPointer && !(dtxNum issimpletype BaseDataType.UBYTE) && !(dtxNum issimpletype BaseDataType.BYTE)) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) } @@ -1999,12 +2011,12 @@ internal class AstChecker(private val program: Program, private fun allowedMemoryAccessAddressExpression(addressExpression: Expression, program: Program): Boolean { val dt = addressExpression.inferType(program) - if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE)) + if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByte==true)) return true val tc = addressExpression as? TypecastExpression if(tc!=null && tc.implicit) { val dt = tc.expression.inferType(program) - if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub==BaseDataType.UBYTE)) + if(dt.isUnsignedWord || (dt.isPointer && dt.getOrUndef().sub?.isByte==true)) return true } return false @@ -2372,12 +2384,6 @@ internal class AstChecker(private val program: Program, errors.err("on..goto index must be an unsigned byte", onGoto.index.position) } } - - override fun visit(idxderef: PtrIndexedDereference) { - val dt = idxderef.indexed.arrayvar.inferType(program) - if(!dt.isUnsignedWord && !dt.isPointer) - errors.err("cannot array index on this field type", idxderef.indexed.position) - } } internal fun checkUnusedReturnValues(call: FunctionCallStatement, target: Statement, errors: IErrorReporter) { diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index 66aadc135..d7fad648f 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -216,12 +216,17 @@ _after: override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { // replace pointervar[word] by @(pointervar+word) to avoid the // "array indexing is limited to byte size 0..255" error for pointervariables. + + if(arrayIndexedExpression.pointerderef!=null) { + return noModifications + } + val indexExpr = arrayIndexedExpression.indexer.indexExpr - val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl() + val arrayVar = arrayIndexedExpression.plainarrayvar!!.targetVarDecl() if(arrayVar!=null && (arrayVar.datatype.isUnsignedWord || (arrayVar.datatype.isPointer && arrayVar.datatype.sub==BaseDataType.UBYTE))) { val wordIndex = TypecastExpression(indexExpr, DataType.UWORD, true, indexExpr.position) val address = BinaryExpression( - arrayIndexedExpression.arrayvar.copy(), + arrayIndexedExpression.plainarrayvar!!.copy(), "+", wordIndex, arrayIndexedExpression.position @@ -243,23 +248,24 @@ _after: val memread = DirectMemoryRead(address, arrayIndexedExpression.position) listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent)) } - } else if(arrayVar!=null && (arrayVar.datatype.isPointer || arrayVar.datatype.isArray)) { + } else if(arrayVar!=null && (arrayVar.type==VarDeclType.MEMORY || arrayVar.datatype.isString || arrayVar.datatype.isPointer || arrayVar.datatype.isArray)) { return noModifications - } else { + } else if(arrayVar!=null) { // it could be a pointer dereference instead of a simple array variable - val dt = arrayIndexedExpression.arrayvar.traverseDerefChainForDt(null) - if(dt.isUnsignedWord) { - // ptr.field[index] --> @(ptr.field + index) - val index = arrayIndexedExpression.indexer.indexExpr - val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", index, arrayIndexedExpression.position) - if(parent is AssignTarget) { - val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position) - return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memwrite, parent)) - } else { - val memread = DirectMemoryRead(address, arrayIndexedExpression.position) - return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent)) - } - } + TODO("deref[word] rewrite ???? $arrayIndexedExpression") +// val dt = arrayIndexedExpression.plainarrayvar!!.traverseDerefChainForDt(null) +// if(dt.isUnsignedWord) { +// // ptr.field[index] --> @(ptr.field + index) +// val index = arrayIndexedExpression.indexer.indexExpr +// val address = BinaryExpression(arrayIndexedExpression.arrayvar.copy(), "+", index, arrayIndexedExpression.position) +// if(parent is AssignTarget) { +// val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position) +// return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memwrite, parent)) +// } else { +// val memread = DirectMemoryRead(address, arrayIndexedExpression.position) +// return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, memread, parent)) +// } +// } } return noModifications } @@ -396,9 +402,6 @@ _after: override fun after(identifier: IdentifierReference, parent: Node): Iterable { - if(parent is PtrIndexedDereference || parent.parent is PtrIndexedDereference) - return noModifications - if(identifier.nameInSource.size>1 && (identifier.firstTarget() as? VarDecl)?.datatype?.isPointer==true) { // the a.b.c.d is be a pointer dereference chain ending in a struct field; a^^.b^^.c^^.d @@ -426,13 +429,7 @@ _after: struct = fieldDt.subType as StructDecl } - if(parent is ArrayIndexedExpression) { - if(struct.getFieldType(field!!)!!.isUnsignedWord) { - return noModifications - } - val deref = PtrIndexedDereference(parent, parent.position) - return listOf(IAstModification.ReplaceNode(parent, deref, parent.parent)) - } else if (parent !is PtrDereference) { + if (parent !is PtrDereference) { val deref = PtrDereference(IdentifierReference(identifier.nameInSource.take(i), identifier.position), chain, field, false, identifier.position) return listOf(IAstModification.ReplaceNode(identifier, deref, parent)) } @@ -472,7 +469,12 @@ _after: assignIndex = Assignment(varTarget, ongoto.index, AssignmentOrigin.USERCODE, ongoto.position) } - val callTarget = ArrayIndexedExpression(IdentifierReference(listOf(jumplistArray.name), jumplistArray.position), ArrayIndex(indexValue.copy(), indexValue.position), ongoto.position) + val callTarget = ArrayIndexedExpression( + IdentifierReference(listOf(jumplistArray.name), jumplistArray.position), + null, + ArrayIndex(indexValue.copy(), indexValue.position), + ongoto.position + ) val callIndexed = AnonymousScope(mutableListOf(), ongoto.position) if(ongoto.isCall) { callIndexed.statements.add(FunctionCallStatement(IdentifierReference(listOf("call"), ongoto.position), mutableListOf(callTarget), true, ongoto.position)) diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVarsAndRecombineIdentifiers.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVarsAndRecombineIdentifiers.kt index e36b8612e..bda8f9529 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVarsAndRecombineIdentifiers.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVarsAndRecombineIdentifiers.kt @@ -1,9 +1,6 @@ package prog8.compiler.astprocessing -import prog8.ast.IFunctionCall -import prog8.ast.IStatementContainer -import prog8.ast.Node -import prog8.ast.Program +import prog8.ast.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker @@ -169,10 +166,14 @@ internal class LiteralsToAutoVarsAndRecombineIdentifiers(private val program: Pr // maybe recombine IDENTIFIER . ARRAY[IDX] --> COMBINEDIDENTIFIER[IDX] val leftTarget = leftIdent.targetStatement() if(leftTarget==null || leftTarget !is StructDecl) { - val combinedName = leftIdent.nameInSource + rightIndex.arrayvar.nameInSource - val combined = IdentifierReference(combinedName, leftIdent.position) - val indexer = ArrayIndexedExpression(combined, rightIndex.indexer, leftIdent.position) - return listOf(IAstModification.ReplaceNode(expr, indexer, parent)) + if(rightIndex.plainarrayvar!=null) { + val combinedName = leftIdent.nameInSource + rightIndex.plainarrayvar!!.nameInSource + val combined = IdentifierReference(combinedName, leftIdent.position) + val indexer = ArrayIndexedExpression(combined, null, rightIndex.indexer, leftIdent.position) + return listOf(IAstModification.ReplaceNode(expr, indexer, parent)) + } else { + throw FatalAstException("didn't expect pointer[idx] in this phase already") + } } } } diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index c1aeb581f..7693335ab 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -100,22 +100,9 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro is TypecastExpression -> transform(expr) is IfExpression -> transform(expr) is PtrDereference -> transform(expr) - is PtrIndexedDereference -> transform(expr) } } - private fun transform(idxderef: PtrIndexedDereference): PtPointerIndexedDeref { - val type = idxderef.inferType(program).getOrElse { - throw FatalAstException("unknown dt") - } - val derefType = if(type.isPointer) DataType.forDt(type.sub!!) else type - val deref = PtPointerIndexedDeref(derefType, idxderef.position) - val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), DataType.pointer(derefType), idxderef.indexed.arrayvar.position) - deref.add(identifier) - deref.add(transformExpression(idxderef.indexed.indexer.indexExpr)) - return deref - } - private fun transform(deref: PtrDereference): PtPointerDeref { val type = deref.inferType(program).getOrElse { throw FatalAstException("unknown dt") @@ -244,7 +231,6 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro srcTarget.arrayindexed!=null -> target.add(transform(srcTarget.arrayindexed!!)) srcTarget.memoryAddress!=null -> target.add(transform(srcTarget.memoryAddress!!)) srcTarget.pointerDereference !=null -> target.add(transform(srcTarget.pointerDereference!!)) - srcTarget.pointerIndexedDeref!=null -> target.add(transform(srcTarget.pointerIndexedDeref!!)) !srcTarget.void -> throw FatalAstException("invalid AssignTarget") } return target @@ -699,14 +685,20 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro } private fun transform(srcArr: ArrayIndexedExpression): PtArrayIndexer { - val dt = srcArr.arrayvar.inferType(program) - if(!dt.isArray && !dt.isString && !dt.isPointer) - throw FatalAstException("array indexing can only be used on array, string or pointer variables ${srcArr.position}") - val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } - val array = PtArrayIndexer(eltType, srcArr.position) - array.add(transform(srcArr.arrayvar)) - array.add(transformExpression(srcArr.indexer.indexExpr)) - return array + if(srcArr.plainarrayvar!=null) { + val dt = srcArr.plainarrayvar!!.inferType(program) + if (!dt.isArray && !dt.isString && !dt.isPointer) + throw FatalAstException("array indexing can only be used on array, string or pointer variables ${srcArr.position}") + val eltType = srcArr.inferType(program).getOrElse { throw FatalAstException("unknown dt") } + val array = PtArrayIndexer(eltType, srcArr.position) + array.add(transform(srcArr.plainarrayvar!!)) + array.add(transformExpression(srcArr.indexer.indexExpr)) + return array + } + if(srcArr.pointerderef!=null) { + TODO("transform pointer index") + } + throw FatalAstException("expected plain array variable or pointer dereference") } private fun transform(srcArr: ArrayLiteral): PtArray { diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstPostprocess.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstPostprocess.kt index cbefd1d08..47da18b1e 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstPostprocess.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstPostprocess.kt @@ -28,7 +28,6 @@ private fun checkForPointerTypesOn6502(program: PtProgram, errors: IErrorReporte //is PtBinaryExpression -> if(node.left.type.isPointer || node.right.type.isPointer) errors.err("cannot do pointer arithmetic yet on 6502 target $node", node.position) is PtIdentifier -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtPointerDeref -> errors.err("cannot use pointer type yet on 6502 target $node", node.position) - is PtPointerIndexedDeref -> errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtPrefix -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtTypeCast -> if(node.type.isPointer) errors.err("cannot use pointer type yet on 6502 target $node", node.position) is PtStructDecl -> errors.err("cannot use struct type yet on 6502 target $node", node.position) @@ -62,7 +61,6 @@ private fun processSubtypesIntoStReferences(program: PtProgram, st: SymbolTable) when(node) { is IPtVariable -> fixSubtype(node.type) is PtPointerDeref -> fixSubtype(node.type) - is PtPointerIndexedDeref -> fixSubtype(node.type) is PtStructDecl -> node.fields.forEach { fixSubtype(it.first) } is PtAsmSub -> node.returns.forEach { fixSubtype(it.second) } is PtExpression -> fixSubtype(node.type) diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 1fe555781..a754a4c02 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -636,7 +636,7 @@ class TypecastsAdder(val program: Program, val options: CompilationOptions, val val idxDt = arrayIndexedExpression.indexer.indexExpr.inferType(program).getOrUndef() if(idxDt.base.largerSizeThan(smaller.type)) { val newIdx = ArrayIndex(smaller, smaller.position) - val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.arrayvar, newIdx, arrayIndexedExpression.position) + val newIndexer = ArrayIndexedExpression(arrayIndexedExpression.plainarrayvar, arrayIndexedExpression.pointerderef, newIdx, arrayIndexedExpression.position) return listOf(IAstModification.ReplaceNode(arrayIndexedExpression, newIndexer, parent)) } } diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 3cbaf0808..1d202b05b 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -428,17 +428,21 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { val index = arrayIndexedExpression.indexer.constIndex() if(index!=null && index<0) { - val target = arrayIndexedExpression.arrayvar.targetVarDecl() - val arraysize = target?.arraysize?.constIndex() - if(arraysize!=null) { - if(arraysize+index < 0) { - errors.err("index out of bounds", arrayIndexedExpression.position) - return noModifications + if(arrayIndexedExpression.plainarrayvar!=null) { + val target = arrayIndexedExpression.plainarrayvar!!.targetVarDecl() + val arraysize = target?.arraysize?.constIndex() + if(arraysize!=null) { + if(arraysize+index < 0) { + errors.err("index out of bounds", arrayIndexedExpression.position) + return noModifications + } + // replace the negative index by the normal index + val newIndex = NumericLiteral.optimalNumeric(arraysize+index, arrayIndexedExpression.indexer.position) + arrayIndexedExpression.indexer.indexExpr = newIndex + newIndex.linkParents(arrayIndexedExpression.indexer) } - // replace the negative index by the normal index - val newIndex = NumericLiteral.optimalNumeric(arraysize+index, arrayIndexedExpression.indexer.position) - arrayIndexedExpression.indexer.indexExpr = newIndex - newIndex.linkParents(arrayIndexedExpression.indexer) + } else if(arrayIndexedExpression.pointerderef!=null) { + TODO("cleanup pointer indexing") } } return noModifications diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 0d7a265f8..a36150c02 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -322,7 +322,7 @@ class TestMemory: FunSpec({ test("array not in mapped IO ram") { val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, SplitWish.DONTCARE, null, "address", emptyList(), null, false, 0u, false, Position.DUMMY) - val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) + val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -336,7 +336,7 @@ class TestMemory: FunSpec({ val address = 0x1000u val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY) - val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) + val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) @@ -350,7 +350,7 @@ class TestMemory: FunSpec({ val address = 0xd800u val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.arrayFor(BaseDataType.UBYTE), ZeropageWish.DONTCARE, SplitWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, 0u, false, Position.DUMMY) - val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) + val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), null, ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, arrayindexed, null, null, false, position = Position.DUMMY) val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY) val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY) diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index c246702fb..1e60f00c7 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -7,6 +7,8 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain import io.kotest.matchers.types.instanceOf +import prog8.ast.expressions.ArrayIndexedExpression +import prog8.ast.expressions.DirectMemoryRead import prog8.ast.expressions.PtrDereference import prog8.ast.statements.Assignment import prog8.ast.statements.VarDecl @@ -193,6 +195,8 @@ main { cx16.r1 = matchstate^^.next^^.next^^.ptr cx16.r2 = matchstate.ptr cx16.r3 = matchstate.next.next.ptr + cx16.r4 = matchstate.ptr^^ + cx16.r5 = matchstate.next.next.ptr^^ matchstate^^.ptr = 2222 matchstate^^.next^^.next^^.ptr = 2222 @@ -203,7 +207,7 @@ main { val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!! val st = result.compilerAst.entrypoint.statements - st.size shouldBe 11 + st.size shouldBe 13 val a0v = (st[2] as Assignment).value as PtrDereference a0v.identifier.nameInSource shouldBe listOf("matchstate") a0v.chain.size shouldBe 0 @@ -228,31 +232,98 @@ main { a3v.field shouldBe "ptr" a3v.derefPointerValue shouldBe false - val t0 = (st[6] as Assignment).target.pointerDereference!! + val a4v = (st[6] as Assignment).value as PtrDereference + a4v.identifier.nameInSource shouldBe listOf("matchstate") + a4v.chain shouldBe listOf("ptr") + a4v.field shouldBe null + a4v.derefPointerValue shouldBe true + + val a5v = (st[7] as Assignment).value as PtrDereference + a5v.identifier.nameInSource shouldBe listOf("matchstate") + a5v.chain shouldBe listOf("next", "next", "ptr") + a5v.field shouldBe null + a5v.derefPointerValue shouldBe true + + val t0 = (st[8] as Assignment).target.pointerDereference!! t0.derefPointerValue shouldBe false t0.identifier.nameInSource shouldBe listOf("matchstate") t0.chain.size shouldBe 0 t0.field shouldBe "ptr" - val t1 = (st[7] as Assignment).target.pointerDereference!! + val t1 = (st[9] as Assignment).target.pointerDereference!! t1.derefPointerValue shouldBe false t1.identifier.nameInSource shouldBe listOf("matchstate") t1.chain shouldBe listOf("next", "next") t1.field shouldBe "ptr" - val t2 = (st[8] as Assignment).target.pointerDereference!! + val t2 = (st[10] as Assignment).target.pointerDereference!! t2.derefPointerValue shouldBe false t2.identifier.nameInSource shouldBe listOf("matchstate") t2.chain.size shouldBe 0 t2.field shouldBe "ptr" - val t3 = (st[9] as Assignment).target.pointerDereference!! + val t3 = (st[11] as Assignment).target.pointerDereference!! t3.derefPointerValue shouldBe false t3.identifier.nameInSource shouldBe listOf("matchstate") t3.chain shouldBe listOf("next", "next") t3.field shouldBe "ptr" } + test("word size pointer indexing on pointers") { + val src=""" +%option enable_floats + +main { + + struct List { + ^^uword s + ubyte n + ^^List next + } + + sub start() { + ubyte[10] array + uword @shared wordptr + ^^bool @shared boolptr + ^^float @shared floatptr + ^^byte @shared byteptr + ^^ubyte @shared ubyteptr + ^^List @shared listptr + ^^List @shared listptr2 + + bool @shared zz + float @shared fl + byte @shared bb + + zz = boolptr[999] + fl = floatptr[999] + bb = byteptr[999] + cx16.r0L = ubyteptr[999] + cx16.r1L = wordptr[999] + cx16.r2L = array[9] + listptr2 = listptr[999] + } +}""" + val result = compileText(VMTarget(), false, src, outputDir, writeAssembly = false)!! + val st = result.compilerAst.entrypoint.statements + st.size shouldBe 28 + + val a_zz = (st[20] as Assignment).value + a_zz shouldBe instanceOf() + val a_fl = (st[21] as Assignment).value + a_fl shouldBe instanceOf() + val a_bb = (st[22] as Assignment).value + a_bb shouldBe instanceOf() + val a_r0 = (st[23] as Assignment).value + a_r0 shouldBe instanceOf() + val a_r1 = (st[24] as Assignment).value + a_r1 shouldBe instanceOf() + val a_r2 = (st[25] as Assignment).value + a_r2 shouldBe instanceOf() + val a_lptr2 = (st[25] as Assignment).value + a_lptr2 shouldBe instanceOf() + } + test("block scoping still parsed correctly") { val src=""" main { @@ -551,6 +622,9 @@ main { } sub start() { ^^List @shared l1 = List() + bool ss = l1.s[1] + ubyte ub = l1.n[1] + uword uw = l1.ptr[1] l1.s[1] = 4444 l1.n[1] = true l1.ptr[1] = 4444 @@ -559,10 +633,15 @@ main { val errors = ErrorReporterForTests() compileText(VMTarget(), false, src, outputDir, errors=errors) shouldBe null - errors.errors.size shouldBe 4 - errors.errors[0] shouldContain "cannot array index" + errors.errors.size shouldBe 8 + errors.errors[0] shouldContain "invalid assignment value" errors.errors[1] shouldContain "cannot array index" - errors.errors[2] shouldContain "out of range" + errors.errors[2] shouldContain "invalid assignment value" + errors.errors[3] shouldContain "cannot array index" + errors.errors[4] shouldContain "cannot array index" + errors.errors[5] shouldContain "cannot array index" + errors.errors[6] shouldContain "out of range" + errors.errors[7] shouldContain "cannot assign word to byte" } test("dereferences of ptr variables mark those as used in the callgraph") { @@ -604,24 +683,26 @@ main { } sub start() { ^^List l1 = List() - cx16.r0 = l1.s[0] - l1.s[0] = 4242 - cx16.r1 = l1.s^^ - ^^word @shared wptr + + cx16.r1 = l1.s^^ + cx16.r0 = l1.s[0] + cx16.r2 = l1^^.s^^ + l1.s[0] = 4242 + cx16.r1 = l1.s^^ + cx16.r0s = wptr[0] - cx16.r1s = wptr^^ - wptr[0] = 4242 + cx16.r1s = wptr^^ + wptr[0] = 4242 } - }""" val result = compileText(VMTarget(), true, src, outputDir, writeAssembly = false)!! val st = result.compilerAst.entrypoint.statements st.size shouldBe 11 - val dr0 = (st[2] as Assignment).value as PtrDereference - val dr1 = (st[3] as Assignment).target.pointerDereference!! - val dr2 = (st[4] as Assignment).value as PtrDereference + val dr0 = (st[4] as Assignment).value as PtrDereference + val dr1 = (st[5] as Assignment).target.pointerDereference!! + val dr2 = (st[6] as Assignment).value as PtrDereference val dr3 = (st[7] as Assignment).value as PtrDereference val dr4 = (st[8] as Assignment).value as PtrDereference diff --git a/compiler/test/ast/TestAstChecks.kt b/compiler/test/ast/TestAstChecks.kt index af5afabb0..dea6bc786 100644 --- a/compiler/test/ast/TestAstChecks.kt +++ b/compiler/test/ast/TestAstChecks.kt @@ -124,16 +124,17 @@ class TestAstChecks: FunSpec({ main { sub start() { &ubyte a = 10000 - uword @shared z = 500 - a[4] = (z % 3) as ubyte + cx16.r0L = a[4] + a[4] = cx16.r1L } } """ val errors = ErrorReporterForTests(keepMessagesAfterReporting = true) compileText(C64Target(), true, text, outputDir, writeAssembly = true, errors=errors) - errors.errors.size shouldBe 1 + errors.errors.size shouldBe 2 errors.warnings.size shouldBe 0 errors.errors[0] shouldContain "indexing requires" + errors.errors[1] shouldContain "indexing requires" } test("unicode in identifier names is working") { diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index 050ba735d..0a7e034dd 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -420,7 +420,8 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: } override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { - arrayIndexedExpression.arrayvar.accept(this) + arrayIndexedExpression.plainarrayvar?.accept(this) + arrayIndexedExpression.pointerderef?.accept(this) output("[") arrayIndexedExpression.indexer.indexExpr.accept(this) output("]") @@ -434,7 +435,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: assignTarget.identifier?.accept(this) assignTarget.arrayindexed?.accept(this) assignTarget.pointerDereference?.accept(this) - assignTarget.pointerIndexedDeref?.accept(this) val multi = assignTarget.multi if (multi != null) { multi.dropLast(1).forEach { target -> @@ -558,11 +558,6 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: output(".${deref.field}") } - override fun visit(idxderef: PtrIndexedDereference) { - idxderef.indexed.accept(this) - output("^^") - } - override fun visit(field: StructFieldRef) { throw FatalAstException("struct field ref shouldn't occur as part of the AST tree ") } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 7ebb2a3b5..e7ecd831c 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -402,9 +402,9 @@ private fun Assign_targetContext.toAst() : AssignTarget { ) is ArrayindexedTargetContext -> { val ax = arrayindexed() - val arrayvar = ax.scoped_identifier().toAst() + val plainarrayvar = ax.scoped_identifier().toAst() val index = ax.arrayindex().toAst() - val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition()) + val arrayindexed = ArrayIndexedExpression(plainarrayvar, null, index, ax.toPosition()) AssignTarget(null, arrayindexed, null, null, false, position = toPosition()) } is VoidTargetContext -> { @@ -412,11 +412,7 @@ private fun Assign_targetContext.toAst() : AssignTarget { } is PointerDereferenceTargetContext -> { val deref = this.pointerdereference().toAst() - AssignTarget(null, null, null, null, false, deref, null, deref.position) - } - is PointerIndexedDerefTargetContext -> { - val deref = this.pointerindexedderef().toAst() - AssignTarget(null, null, null, null, false, null, deref, deref.position) + AssignTarget(null, null, null, null, false, deref, deref.position) } else -> throw FatalAstException("weird assign target node $this") } @@ -602,9 +598,9 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi if(arrayindexed()!=null) { val ax = arrayindexed() - val identifier = ax.scoped_identifier().toAst() + val plainarrayvar = ax.scoped_identifier().toAst() val index = ax.arrayindex().toAst() - return ArrayIndexedExpression(identifier, index, ax.toPosition()) + return ArrayIndexedExpression(plainarrayvar, null, index, ax.toPosition()) } if(scoped_identifier()!=null) @@ -666,21 +662,10 @@ private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expressi val deref = pointerdereference()?.toAst() if(deref!=null) return deref - val indexedderef = pointerindexedderef()?.toAst() - if(indexedderef!=null) return indexedderef - throw FatalAstException(text) } -private fun PointerindexedderefContext.toAst(): PtrIndexedDereference { - val ax = arrayindexed() - val arrayvar = ax.scoped_identifier().toAst() - val index = ax.arrayindex().toAst() - val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition()) - return PtrIndexedDereference(arrayindexed, toPosition()) -} - private fun PointerdereferenceContext.toAst(): PtrDereference { val scopeprefix = prefix?.toAst() val derefchain = derefchain()!!.singlederef()!!.map { it.identifier().text } diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 52c4d7a7c..0994a34b3 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -40,10 +40,7 @@ sealed class Expression: Node { else other.left isSameAs left && other.right isSameAs right } - is ArrayIndexedExpression -> { - (other is ArrayIndexedExpression && other.arrayvar.nameInSource == arrayvar.nameInSource - && other.indexer isSameAs indexer) - } + is ArrayIndexedExpression -> isSameArrayIndexedAs(other) is DirectMemoryRead -> { (other is DirectMemoryRead && other.addressExpression isSameAs addressExpression) } @@ -242,9 +239,12 @@ class BinaryExpression( if (leftIdentfier != null) { // PTR . FIELD leftIdentfier.targetVarDecl()?.datatype?.subType as? StructDecl - } else if(leftIndexer!=null) { + } else if(leftIndexer!=null && rightIdentifier.nameInSource.size==1) { // ARRAY[x].NAME --> maybe it's a pointer dereference - leftIndexer.arrayvar.targetVarDecl()?.datatype?.subType as? StructDecl + val dt = leftIndexer.inferType(program).getOrUndef() + if(dt.isPointer) { + dt.dereference().subType as? StructDecl + } else null } else if(leftExpr!=null) { // SOMEEXPRESSION . NAME val leftDt = leftExpr.inferType(program) @@ -269,17 +269,18 @@ class BinaryExpression( } else if(rightIndexer!=null) { if(leftDt.isStructInstance) { // pointer[x].field[y] --> type is the dt of 'field' - var fieldDt = (leftDt.getOrUndef().subType as? StructDecl)?.getFieldType(rightIndexer.arrayvar.nameInSource.single()) - if (fieldDt == null) - InferredTypes.unknown() - else { - val struct = fieldDt.subType as StructDecl - fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) - if(fieldDt!=null) - if(fieldDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(fieldDt) - else - InferredTypes.unknown() - } + TODO("pointer[x].field[y] ?????") +// var fieldDt = (leftDt.getOrUndef().subType as? StructDecl)?.getFieldType(rightIndexer.arrayvar.nameInSource.single()) +// if (fieldDt == null) +// InferredTypes.unknown() +// else { +// val struct = fieldDt.subType as StructDecl +// fieldDt = struct.getFieldType(rightIndexer.arrayvar.nameInSource.single()) +// if(fieldDt!=null) +// if(fieldDt.isUndefined) InferredTypes.unknown() else InferredTypes.knownFor(fieldDt) +// else +// InferredTypes.unknown() +// } } else InferredTypes.unknown() // TODO("something.field[x] at ${right.position}") // TODO I don't think we can evaluate this type because it could end up in as a struct instance, which we don't support yet... rewrite or just give an error? @@ -386,21 +387,30 @@ class BinaryExpression( } } -class ArrayIndexedExpression(var arrayvar: IdentifierReference, +class ArrayIndexedExpression(var plainarrayvar: IdentifierReference?, + var pointerderef: PtrDereference?, val indexer: ArrayIndex, override val position: Position) : Expression() { override lateinit var parent: Node override fun linkParents(parent: Node) { this.parent = parent - arrayvar.linkParents(this) + plainarrayvar?.linkParents(this) + pointerderef?.linkParents(this) indexer.linkParents(this) } override val isSimple = indexer.indexExpr is NumericLiteral || indexer.indexExpr is IdentifierReference override fun replaceChildNode(node: Node, replacement: Node) { - when { - node===arrayvar -> arrayvar = replacement as IdentifierReference + when (replacement) { + is IdentifierReference -> { + plainarrayvar = replacement + pointerderef = null + } + is PtrDereference -> { + plainarrayvar = null + pointerderef = replacement + } else -> throw FatalAstException("invalid replace") } replacement.parent = this @@ -410,39 +420,58 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List) = arrayvar.referencesIdentifier(nameInSource) || indexer.referencesIdentifier(nameInSource) + override fun referencesIdentifier(nameInSource: List) = + plainarrayvar?.referencesIdentifier(nameInSource)==true || pointerderef?.referencesIdentifier(nameInSource)==true || indexer.referencesIdentifier(nameInSource) override fun inferType(program: Program): InferredTypes.InferredType { - val target = arrayvar.targetStatement(program.builtinFunctions) - if (target is VarDecl) { - return when { - target.datatype.isString || target.datatype.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) - target.datatype.isArray -> InferredTypes.knownFor(target.datatype.elementType()) - target.datatype.isPointer -> { - if(target.datatype.subType!=null) - InferredTypes.knownFor(DataType.structInstance(target.datatype.subType)) - else if(target.datatype.subTypeFromAntlr!=null) - InferredTypes.unknown() - else - InferredTypes.knownFor(target.datatype.sub!!) + if(plainarrayvar!=null) { + val target = plainarrayvar!!.targetStatement() + if(target is VarDecl) { + return when { + target.datatype.isString || target.datatype.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) + target.datatype.isArray -> InferredTypes.knownFor(target.datatype.elementType()) + target.datatype.isPointer -> InferredTypes.knownFor(target.datatype.dereference()) + else -> InferredTypes.knownFor(target.datatype) } - else -> InferredTypes.knownFor(target.datatype) - } - } else { - val dt = arrayvar.inferType(program).getOrUndef() - if(dt.isPointer) { - if(dt.sub!=null) - return InferredTypes.knownFor(dt.sub!!) + } else if(target is StructFieldRef) { + return InferredTypes.knownFor(target.type) + } else if(target==null) { + return InferredTypes.unknown() + } else + TODO("infer type from target $target") + } else if(pointerderef!=null) { + val dt= pointerderef!!.inferType(program).getOrUndef() + return when { + dt.isString || dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) + dt.isArray -> InferredTypes.knownFor(dt.elementType()) + dt.isPointer -> InferredTypes.knownFor(dt.dereference()) + else -> InferredTypes.unknown() } } return InferredTypes.unknown() } override fun toString(): String { - return "ArrayIndexed(ident=$arrayvar, idx=$indexer; pos=$position)" + return if(plainarrayvar!=null) + "ArrayIndexed(arrayvar=$plainarrayvar, idx=$indexer; pos=$position)" + else if(pointerderef!=null) + "ArrayIndexed(ptr=$pointerderef, idx=$indexer; pos=$position)" + else + "??????" + } + + override fun copy() = ArrayIndexedExpression(plainarrayvar?.copy(), pointerderef?.copy(), indexer.copy(), position) + + fun isSameArrayIndexedAs(other: Expression): Boolean { + if(other !is ArrayIndexedExpression || other.indexer!=indexer) + return false + if(plainarrayvar?.nameInSource != other.plainarrayvar?.nameInSource) + return false + if(pointerderef!=null) + return pointerderef!!.isSamePointerDeref(other.pointerderef) + return true } - override fun copy() = ArrayIndexedExpression(arrayvar.copy(), indexer.copy(), position) } class TypecastExpression(var expression: Expression, var type: DataType, val implicit: Boolean, override val position: Position) : Expression() { @@ -1618,46 +1647,6 @@ class IfExpression(var condition: Expression, var truevalue: Expression, var fal } } -class PtrIndexedDereference(val indexed: ArrayIndexedExpression, override val position: Position) : Expression() { - override lateinit var parent: Node - - override fun linkParents(parent: Node) { - this.parent = parent - indexed.linkParents(this) - } - - override val isSimple = false - override fun copy() = PtrIndexedDereference(indexed.copy(), position) - override fun constValue(program: Program): NumericLiteral? = null - override fun accept(visitor: IAstVisitor) = visitor.visit(this) - override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - override fun inferType(program: Program): InferredTypes.InferredType { - val parentExpr = parent as? BinaryExpression - if(parentExpr?.operator==".") { - TODO("cannot determine type of dereferenced indexed pointer(?) as part of a larger dereference expression") - } - val vardecl = indexed.arrayvar.targetVarDecl() - if(vardecl!=null &&vardecl.datatype.isPointer) - return InferredTypes.knownFor(vardecl.datatype.dereference()) - - if(parent is AssignTarget || parent is Assignment) { - val dt = indexed.arrayvar.traverseDerefChainForDt(null) - return when { - dt.isUndefined -> InferredTypes.unknown() - dt.isUnsignedWord -> InferredTypes.knownFor(BaseDataType.UBYTE) - dt.isPointer -> InferredTypes.knownFor(dt.dereference()) - else -> InferredTypes.unknown() - } - } - - return InferredTypes.unknown() - } - - override fun replaceChildNode(node: Node, replacement: Node) = - throw FatalAstException("can't replace here") - override fun referencesIdentifier(nameInSource: List) = indexed.referencesIdentifier(nameInSource) -} - class PtrDereference( val identifier: IdentifierReference, val chain: List, @@ -1666,6 +1655,7 @@ class PtrDereference( override val position: Position ) : Expression() { // TODO why both identifier and chain? + // TODO why both chain and field? field is just the last entry of chain? override lateinit var parent: Node @@ -1731,6 +1721,19 @@ class PtrDereference( override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") override fun referencesIdentifier(nameInSource: List) = identifier.referencesIdentifier(nameInSource) + fun isSamePointerDeref(other: Expression?): Boolean { + if(other==null || other !is PtrDereference) + return false + if(derefPointerValue != other.derefPointerValue) + return false + if(identifier.nameInSource != other.identifier.nameInSource) + return false + if(chain != other.chain) + return false + if(field != other.field) + return false + return true + } } fun invertCondition(cond: Expression, program: Program): Expression { diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index fc4de05f4..2b4536111 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -593,7 +593,6 @@ data class AssignTarget( val multi: List?, val void: Boolean, var pointerDereference: PtrDereference? = null, - var pointerIndexedDeref : PtrIndexedDereference? = null, override val position: Position ) : Node { override lateinit var parent: Node @@ -604,7 +603,6 @@ data class AssignTarget( arrayindexed?.linkParents(this) memoryAddress?.linkParents(this) pointerDereference?.linkParents(this) - pointerIndexedDeref?.linkParents(this) multi?.forEach { it.linkParents(this) } } @@ -614,22 +612,18 @@ data class AssignTarget( identifier = null arrayindexed = null pointerDereference = null - pointerIndexedDeref = null when (replacement) { is IdentifierReference -> identifier = replacement is PtrDereference -> pointerDereference = replacement - is PtrIndexedDereference -> pointerIndexedDeref = replacement else -> throw FatalAstException("invalid replacement for AssignTarget.identifier: $replacement") } } node === arrayindexed -> { identifier = null pointerDereference = null - pointerIndexedDeref = null arrayindexed = null memoryAddress = null when (replacement) { - is PtrIndexedDereference -> pointerIndexedDeref = replacement is ArrayIndexedExpression -> arrayindexed = replacement is DirectMemoryWrite -> memoryAddress = replacement is PtrDereference -> pointerDereference = replacement @@ -651,7 +645,6 @@ data class AssignTarget( multi?.toList(), void, pointerDereference?.copy(), - pointerIndexedDeref?.copy(), position ) override fun referencesIdentifier(nameInSource: List): Boolean = @@ -659,7 +652,6 @@ data class AssignTarget( arrayindexed?.referencesIdentifier(nameInSource)==true || memoryAddress?.referencesIdentifier(nameInSource)==true || pointerDereference?.referencesIdentifier(nameInSource)==true || - pointerIndexedDeref?.referencesIdentifier(nameInSource)==true || multi?.any { it.referencesIdentifier(nameInSource)}==true fun inferType(program: Program): InferredTypes.InferredType { @@ -672,7 +664,6 @@ data class AssignTarget( arrayindexed != null -> arrayindexed!!.inferType(program) memoryAddress != null -> InferredTypes.knownFor(BaseDataType.UBYTE) pointerDereference != null -> pointerDereference!!.inferType(program) - pointerIndexedDeref != null -> pointerIndexedDeref!!.inferType(program) else -> InferredTypes.unknown() // a multi-target has no 1 particular type } } @@ -685,7 +676,6 @@ data class AssignTarget( memoryAddress != null -> DirectMemoryRead(memoryAddress!!.addressExpression.copy(), memoryAddress!!.position) multi != null -> throw FatalAstException("cannot turn a multi-assign into a single source expression") pointerDereference != null -> pointerDereference!!.copy() - pointerIndexedDeref != null -> pointerIndexedDeref!!.copy() else -> throw FatalAstException("invalid assignment target") } } @@ -700,12 +690,7 @@ data class AssignTarget( false } identifier != null -> value is IdentifierReference && value.nameInSource == identifier!!.nameInSource - arrayindexed != null -> { - if(value is ArrayIndexedExpression && value.arrayvar.nameInSource == arrayindexed!!.arrayvar.nameInSource) - arrayindexed!!.indexer isSameAs value.indexer - else - false - } + arrayindexed != null -> value is ArrayIndexedExpression && arrayindexed!!.isSameArrayIndexedAs(value) multi != null -> false pointerDereference !=null -> { if(value is PtrDereference) { @@ -716,11 +701,6 @@ data class AssignTarget( } return false } - pointerIndexedDeref !=null -> { - if(value is PtrIndexedDereference) - return pointerIndexedDeref!!.indexed == value.indexed - return false - } else -> false } } @@ -736,20 +716,19 @@ data class AssignTarget( return addr1 != null && addr2 != null && addr1 == addr2 } this.arrayindexed != null && other.arrayindexed != null -> { - if (this.arrayindexed!!.arrayvar.nameInSource == other.arrayindexed!!.arrayvar.nameInSource) { + if(this.arrayindexed!!.plainarrayvar!=null && this.arrayindexed!!.plainarrayvar?.nameInSource == other.arrayindexed!!.plainarrayvar?.nameInSource) { val x1 = this.arrayindexed!!.indexer.constIndex() val x2 = other.arrayindexed!!.indexer.constIndex() return x1 != null && x2 != null && x1 == x2 } + else if(this.pointerDereference != null && other.pointerDereference != null && this.pointerDereference!!.isSamePointerDeref(other.pointerDereference)) + return true else return false } pointerDereference !=null && other.pointerDereference !=null -> { return pointerDereference!! isSameAs other.pointerDereference!! } - pointerIndexedDeref !=null && other.pointerIndexedDeref !=null -> { - return pointerIndexedDeref!! isSameAs other.pointerIndexedDeref!! - } this.multi != null && other.multi != null -> return this.multi == other.multi else -> return false } @@ -777,14 +756,18 @@ data class AssignTarget( } } arrayIdx != null -> { - val targetStmt = arrayIdx.arrayvar.targetVarDecl() - return if (targetStmt?.type == VarDeclType.MEMORY) { - val addr = targetStmt.value as? NumericLiteral - if (addr != null) - target.isIOAddress(addr.number.toUInt()) - else - false - } else false + if(arrayIdx.plainarrayvar!=null) { + val targetStmt = arrayIdx.plainarrayvar!!.targetVarDecl() + return if (targetStmt?.type == VarDeclType.MEMORY) { + val addr = targetStmt.value as? NumericLiteral + if (addr != null) + target.isIOAddress(addr.number.toUInt()) + else + false + } else false + } + // can't really tell for the other types... assume false. + return false } ident != null -> { val decl = ident.targetVarDecl() ?: throw FatalAstException("invalid identifier ${ident.nameInSource}") diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index d15a91cd6..5be8eda4d 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -106,7 +106,6 @@ abstract class AstWalker { open fun before(containment: ContainmentCheck, parent: Node): Iterable = noModifications open fun before(decl: VarDecl, parent: Node): Iterable = noModifications open fun before(deref: PtrDereference, parent: Node): Iterable = noModifications - open fun before(idxderef: PtrIndexedDereference, parent: Node): Iterable = noModifications open fun before(struct: StructDecl, parent: Node): Iterable = noModifications open fun before(field: StructFieldRef, parent: Node): Iterable = noModifications open fun before(directive: Directive, parent: Node): Iterable = noModifications @@ -156,7 +155,6 @@ abstract class AstWalker { open fun after(containment: ContainmentCheck, parent: Node): Iterable = noModifications open fun after(decl: VarDecl, parent: Node): Iterable = noModifications open fun after(deref: PtrDereference, parent: Node): Iterable = noModifications - open fun after(idxderef: PtrIndexedDereference, parent: Node): Iterable = noModifications open fun after(struct: StructDecl, parent: Node): Iterable = noModifications open fun after(field: StructFieldRef, parent: Node): Iterable = noModifications open fun after(directive: Directive, parent: Node): Iterable = noModifications @@ -438,7 +436,8 @@ abstract class AstWalker { fun visit(arrayIndexedExpression: ArrayIndexedExpression, parent: Node) { track(before(arrayIndexedExpression, parent), arrayIndexedExpression, parent) - arrayIndexedExpression.arrayvar.accept(this, arrayIndexedExpression) + arrayIndexedExpression.plainarrayvar?.accept(this, arrayIndexedExpression) + arrayIndexedExpression.pointerderef?.accept(this, arrayIndexedExpression) arrayIndexedExpression.indexer.accept(this) track(after(arrayIndexedExpression, parent), arrayIndexedExpression, parent) } @@ -449,7 +448,6 @@ abstract class AstWalker { assignTarget.identifier?.accept(this, assignTarget) assignTarget.memoryAddress?.accept(this, assignTarget) assignTarget.pointerDereference?.accept(this, assignTarget) - assignTarget.pointerIndexedDeref?.accept(this, assignTarget) assignTarget.multi?.forEach { it.accept(this, assignTarget) } track(after(assignTarget, parent), assignTarget, parent) } @@ -539,11 +537,5 @@ abstract class AstWalker { deref.identifier.accept(this, deref) track(after(deref, parent), deref, parent) } - - fun visit(idxderef: PtrIndexedDereference, parent: Node) { - track(before(idxderef, parent), idxderef, parent) - idxderef.indexed.accept(this, idxderef) - track(after(idxderef, parent), idxderef, parent) - } } diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 791ef6908..3d86cb032 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -152,7 +152,8 @@ interface IAstVisitor { } fun visit(arrayIndexedExpression: ArrayIndexedExpression) { - arrayIndexedExpression.arrayvar.accept(this) + arrayIndexedExpression.plainarrayvar?.accept(this) + arrayIndexedExpression.pointerderef?.accept(this) arrayIndexedExpression.indexer.accept(this) } @@ -161,7 +162,6 @@ interface IAstVisitor { assignTarget.identifier?.accept(this) assignTarget.memoryAddress?.accept(this) assignTarget.pointerDereference?.accept(this) - assignTarget.pointerIndexedDeref?.accept(this) assignTarget.multi?.forEach { it.accept(this) } } @@ -218,8 +218,4 @@ interface IAstVisitor { fun visit(deref: PtrDereference) { deref.identifier.accept(this) } - - fun visit(idxderef: PtrIndexedDereference) { - idxderef.indexed.accept(this) - } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 22a8f6cba..bdc30d0a0 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,8 @@ TODO ==== +Something changed in array/string/uword indexing codegen? Assem became bigger, rockrunner too. + STRUCTS and TYPED POINTERS -------------------------- @@ -56,8 +58,8 @@ STRUCTS and TYPED POINTERS - fix ptr problems in re.p8 and unit tests - add unit tests for expected AST elements for all syntaxes dealing with pointers, dereference(chain), derefs, and indexing (both as value and assigntargets) - clean up pointerdereference in the grammar, regarding dealing with final ^^ or not -- Can we now get rid of PtPointerIndexedDeref ? Both for expression (value) as assigntarget? All code for translate(idxderef: PtPointerIndexedDeref) in ExpressionGen? - why does PtrDereference have both identifier and chain property? what goes where? is the distinction needed? +- why does PtrDereference have both chain and field property? what goes where? is the distinction needed? - add unit tests for all changes (pointers and structs) - 6502 codegen: remove checks in checkForPointerTypesOn6502() - 6502 codegen should warn about writing to initialized struct instances when using romable code, like with arrays "can only be used as read-only in ROMable code" diff --git a/examples/test.p8 b/examples/test.p8 index c00db04cc..af3b3d961 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -2,15 +2,20 @@ main { struct List { ^^uword s ubyte n - ^^List next } sub start() { ^^List l1 = List() - ^^List l2 = List() - l1.s[2] = 1 - l2.n=10 + ^^word @shared wptr - ^^List l3 = List() - cx16.r0L = l3.next.n + cx16.r1 = l1.s^^ + cx16.r0 = l1.s[0] + cx16.r2 = l1^^.s^^ + l1.s[0] = 4242 + cx16.r1 = l1.s^^ + + cx16.r0s = wptr[0] + cx16.r1s = wptr^^ + wptr[0] = 4242 } + } diff --git a/parser/src/main/antlr/Prog8ANTLR.g4 b/parser/src/main/antlr/Prog8ANTLR.g4 index 5ac0acce7..e76accc06 100644 --- a/parser/src/main/antlr/Prog8ANTLR.g4 +++ b/parser/src/main/antlr/Prog8ANTLR.g4 @@ -187,7 +187,6 @@ assign_target: | arrayindexed #ArrayindexedTarget | directmemory #MemoryTarget | pointerdereference #PointerDereferenceTarget - | pointerindexedderef #PointerIndexedDerefTarget | VOID #VoidTarget ; @@ -225,7 +224,6 @@ expression : | expression typecast | if_expression | pointerdereference - | pointerindexedderef ; arrayindexed: @@ -339,9 +337,6 @@ derefchain : singlederef ('.' singlederef)* ; singlederef : identifier POINTER ; -pointerindexedderef : arrayindexed POINTER ; - - branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? ; branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ; diff --git a/simpleAst/src/prog8/code/ast/AstExpressions.kt b/simpleAst/src/prog8/code/ast/AstExpressions.kt index df4779be5..113bbabba 100644 --- a/simpleAst/src/prog8/code/ast/AstExpressions.kt +++ b/simpleAst/src/prog8/code/ast/AstExpressions.kt @@ -116,7 +116,6 @@ sealed class PtExpression(val type: DataType, position: Position) : PtNode(posit is PtRange -> true is PtString -> true is PtPointerDeref -> this.startpointer.isSimple() && this.field==null && this.chain.isEmpty() - is PtPointerIndexedDeref -> this.index.isSimple() is PtTypeCast -> value.isSimple() is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple() } @@ -418,16 +417,6 @@ class PtPointerDeref(type: DataType, val chain: List, val field: String? } } -class PtPointerIndexedDeref(type: DataType, position: Position) : PtExpression(type, position) { - val variable: PtIdentifier - get() = children[0] as PtIdentifier - val index: PtExpression - get() = children[1] as PtExpression - - init { - require(!type.isUndefined) - } -} // special node that isn't created from compiling user code, but used internally in the Intermediate Code class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position) diff --git a/simpleAst/src/prog8/code/ast/AstPrinter.kt b/simpleAst/src/prog8/code/ast/AstPrinter.kt index 4f0912787..ef6d95200 100644 --- a/simpleAst/src/prog8/code/ast/AstPrinter.kt +++ b/simpleAst/src/prog8/code/ast/AstPrinter.kt @@ -193,9 +193,6 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni val field = if(node.field==null) "" else ".${node.field}" "deref {child} $chain $field ${type(node.type)}" } - is PtPointerIndexedDeref -> { - "idxderef {child} ${type(node.type)}" - } } } diff --git a/simpleAst/src/prog8/code/ast/AstStatements.kt b/simpleAst/src/prog8/code/ast/AstStatements.kt index 00be69dfe..edc806aef 100644 --- a/simpleAst/src/prog8/code/ast/AstStatements.kt +++ b/simpleAst/src/prog8/code/ast/AstStatements.kt @@ -124,8 +124,6 @@ class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) { get() = children.single() as? PtMemoryByte val pointerDeref: PtPointerDeref? get() = children.single() as? PtPointerDeref - val pointerIndexedDeref: PtPointerIndexedDeref? - get() = children.single() as? PtPointerIndexedDeref val type: DataType get() { @@ -134,7 +132,6 @@ class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) { is PtArrayIndexer -> tgt.type is PtMemoryByte -> tgt.type is PtPointerDeref -> tgt.type - is PtPointerIndexedDeref -> tgt.type else -> throw AssemblyError("weird target $tgt") } }