From 331e2b8f2b31250caae0fd077b425482f85d2eb3 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 29 Mar 2026 19:38:14 +0200 Subject: [PATCH] improve ast source position tracking --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 2 +- .../codegen/cpu6502/FunctionCallAsmGen.kt | 4 +-- .../codegen/cpu6502/ProgramAndVarsGen.kt | 12 ++++----- .../cpu6502/assignment/AssignmentAsmGen.kt | 2 +- .../assignment/AugmentableAssignmentAsmGen.kt | 4 +-- .../codegen/intermediate/AssignmentGen.kt | 4 +-- .../optimizer/ConstantIdentifierReplacer.kt | 2 +- .../astprocessing/BeforeAsmAstChanger.kt | 6 ++--- .../compiler/astprocessing/DeferProcessor.kt | 26 +++++++++---------- compiler/test/TestCompilerOnExamples.kt | 22 ++++++++-------- compilerAst/src/prog8/ast/AstToplevel.kt | 6 ++--- .../prog8/ast/expressions/AstExpressions.kt | 2 +- 12 files changed, 46 insertions(+), 46 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index f6754c99f..c8abc1f5e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -169,7 +169,7 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque functionCallsToPrefix.reversed().forEach { (parent, index) -> val node = parent.children[index] if(node is PtFunctionCall) { - val prefixedName = PtIdentifier(node.name, DataType.UNDEFINED, Position.DUMMY).prefix(parent, st) + val prefixedName = PtIdentifier(node.name, DataType.UNDEFINED, node.position).prefix(parent, st) val prefixedNode = node.withNewName(prefixedName.name) parent.children[index] = prefixedNode } else { diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt index 4427712ba..b5607d073 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/FunctionCallAsmGen.kt @@ -333,7 +333,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as // we need to sign extend the source, do this via temporary word variable asmgen.assignExpressionToVariable(value, "P8ZP_SCRATCH_W1", DataType.UBYTE) asmgen.signExtendVariableLsb("P8ZP_SCRATCH_W1", value.type.base) - asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, null, Position.DUMMY) + asmgen.assignVariableToRegister("P8ZP_SCRATCH_W1", register, null, value.position) } else { val scope = value.definingISub() val target: AsmAssignTarget = @@ -344,7 +344,7 @@ internal class FunctionCallAsmGen(private val program: PtProgram, private val as } val src = if(value.type.isPassByRef) { if(value is PtIdentifier) { - val addr = PtAddressOf(value.type.typeForAddressOf(false), false, Position.DUMMY) + val addr = PtAddressOf(value.type.typeForAddressOf(false), false, value.position) addr.add(value) addr.parent = scope as PtNode AsmAssignSource.fromAstSource(addr, program, asmgen).adjustSignedUnsigned(target) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt index ad043828e..11c33b7e4 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt @@ -742,7 +742,7 @@ internal class ProgramAndVarsGen( it.initializationStringValue!!.second, it.initializationStringValue!!.first ) - asmgen.romableError("string (${it.dt} ${it.name}) can only be used as read-only in ROMable code", Position.DUMMY, false) // TODO print warning with position of the var + asmgen.romableError("string (${it.dt} ${it.name}) can only be used as read-only in ROMable code", it.astNode?.position ?: Position.DUMMY, false) } alignedStrings.sortedBy { it.align }.forEach { outputStringvar( @@ -751,22 +751,22 @@ internal class ProgramAndVarsGen( it.initializationStringValue!!.second, it.initializationStringValue!!.first ) - asmgen.romableError("string (${it.dt} ${it.name}) can only be used as read-only in ROMable code", Position.DUMMY, false) // TODO print warning with position of the var + asmgen.romableError("string (${it.dt} ${it.name}) can only be used as read-only in ROMable code", it.astNode?.position ?: Position.DUMMY, false) } notAlignedOther.sortedBy { it.type }.forEach { staticVariable2asm(it) if(it.dt.isArray) - asmgen.romableError("array (${it.dt} ${it.name}) can only be used as read-only in ROMable code", Position.DUMMY, false) // TODO print warning with position of the var + asmgen.romableError("array (${it.dt} ${it.name}) can only be used as read-only in ROMable code", it.astNode?.position ?: Position.DUMMY, false) else - asmgen.romableError("inlined variable (${it.dt} ${it.name})", Position.DUMMY) // TODO print warning with position of the var + asmgen.romableError("inlined variable (${it.dt} ${it.name})", it.astNode?.position ?: Position.DUMMY) } alignedOther.sortedBy { it.align }.sortedBy { it.type }.forEach { staticVariable2asm(it) if(it.dt.isArray) - asmgen.romableError("array (${it.dt} ${it.name}) can only be used as read-only in ROMable code", Position.DUMMY, false) // TODO print warning with position of the var + asmgen.romableError("array (${it.dt} ${it.name}) can only be used as read-only in ROMable code", it.astNode?.position ?: Position.DUMMY, false) else - asmgen.romableError("inlined variable (${it.dt} ${it.name})", Position.DUMMY) // TODO print warning with position of the var + asmgen.romableError("inlined variable (${it.dt} ${it.name})", it.astNode?.position ?: Position.DUMMY) } } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 87c5f7aab..30e3daf4c 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -5434,7 +5434,7 @@ $endLabel""") internal fun assignVariableToRegister(asmVarName: String, register: RegisterOrPair, signed: Boolean, scope: IPtSubroutine?, pos: Position) { val tgt = AsmAssignTarget.fromRegisters(register, signed, pos, null, asmgen) val src = AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, tgt.datatype, variableAsmName = asmVarName) - val assign = AsmAssignment(src, listOf(tgt), program.memsizer, Position.DUMMY) + val assign = AsmAssignment(src, listOf(tgt), program.memsizer, pos) translateNormalAssignment(assign, scope) } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt index fcaa9a47f..1f5f4a35f 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AugmentableAssignmentAsmGen.kt @@ -1193,9 +1193,9 @@ internal class AugmentableAssignmentAsmGen(private val program: PtProgram, val assignValue = AsmAssignment(value, listOf( AsmAssignTarget(TargetStorageKind.REGISTER, asmgen, DataType.UBYTE, - address.definingISub(), Position.DUMMY, register = RegisterOrPair.A) + address.definingISub(), address.position, register = RegisterOrPair.A) ), - program.memsizer, Position.DUMMY) + program.memsizer, address.position) assignmentAsmGen.translateNormalAssignment(assignValue, address.definingISub()) // calculate value into A } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 507c0727f..a37551b2f 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -60,7 +60,7 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen // note: multi-value returns are passed throug A or AY (for the first value) then cx16.R15 down to R0 // (this allows unencumbered use of many Rx registers if you don't return that many values) val returntypes = BuiltinFunctions.getValue(thing.name).returnTypes - val signature = PtSubSignature(returntypes.map { DataType.forDt(it) }, Position.DUMMY) + val signature = PtSubSignature(returntypes.map { DataType.forDt(it) }, values.position) val returnregs = signature.returnsWhatWhere() assignmentTargets.zip(returnregs).forEach { val target = it.first as PtAssignTarget @@ -1479,4 +1479,4 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val exprGen } return result } -} \ No newline at end of file +} diff --git a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 121c898ae..7631b04c4 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -452,7 +452,7 @@ internal class ConstantIdentifierReplacer( if(targetDatatype.isArray) { val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.ARRAYLITERAL, targetDatatype.getOrUndef(), ZeropageWish.DONTCARE, SplitWish.NOSPLIT, null, "dummy", emptyList(), - assignment.value, false, 0u, false, Position.DUMMY) + assignment.value, false, 0u, false, assignment.value.position) val replaceValue = createConstArrayInitializerValue(decl) if(replaceValue!=null) { return listOf(IAstModification.ReplaceNode(assignment.value, replaceValue, assignment)) diff --git a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt index dd9a3e251..f1bd14aff 100644 --- a/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt +++ b/compiler/src/prog8/compiler/astprocessing/BeforeAsmAstChanger.kt @@ -56,7 +56,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co if(subroutine.returntypes.isNotEmpty()) errors.err("subroutine is missing a return statement with value(s)", subroutine.position) else { - val returnStmt = Return(arrayOf(), Position.DUMMY) + val returnStmt = Return(arrayOf(), subroutine.position) mods += IAstModification.InsertLast(returnStmt, subroutine) } } else { @@ -68,7 +68,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co // .... we cannot return this as an error, because that also breaks legitimate cases where the return is done from within a nested scope somewhere // errors.err("subroutine is missing a return statement with value(s)", subroutine.position) } else { - val returnStmt = Return(arrayOf(), Position.DUMMY) + val returnStmt = Return(arrayOf(), lastStatement?.position ?: subroutine.position) mods += IAstModification.InsertLast(returnStmt, subroutine) } } @@ -92,7 +92,7 @@ internal class BeforeAsmAstChanger(val program: Program, private val options: Co if(outerScope.returntypes.size>1 || !(outerScope.returntypes[0].isNumericOrBool || outerScope.returntypes[0].isPointer)) { errors.err("subroutine is missing a return statement to avoid falling through into nested subroutine", outerStatements[subroutineStmtIdx-1].position) } else { - val zero = defaultZero(outerScope.returntypes[0].base, Position.DUMMY) + val zero = defaultZero(outerScope.returntypes[0].base, outerStatements[subroutineStmtIdx-1].position) val returnStmt = Return(arrayOf(zero), outerStatements[subroutineStmtIdx - 1].position) mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope) } diff --git a/compiler/src/prog8/compiler/astprocessing/DeferProcessor.kt b/compiler/src/prog8/compiler/astprocessing/DeferProcessor.kt index 2f6beb619..f4b541ef6 100644 --- a/compiler/src/prog8/compiler/astprocessing/DeferProcessor.kt +++ b/compiler/src/prog8/compiler/astprocessing/DeferProcessor.kt @@ -170,33 +170,33 @@ internal object DeferProcessor { for( (sub, defers) in subdefers) { // create the routine that calls the enabled defers in reverse order - val defersRoutine = PtSub(invokeDefersRoutineName, emptyList(), emptyList(), Position.DUMMY) + val defersRoutine = PtSub(invokeDefersRoutineName, emptyList(), emptyList(), sub.position) defersRoutine.parent=sub for((idx, defer) in defers.reversed().withIndex()) { - val shift = PtAugmentedAssign(">>=", Position.DUMMY) - shift.add(PtAssignTarget(false, sub.position).also { - it.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, sub.position)) + val shift = PtAugmentedAssign(">>=", defer.position) + shift.add(PtAssignTarget(false, defer.position).also { + it.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, defer.position)) }) - shift.add(PtNumber(BaseDataType.UBYTE, 1.0, sub.position)) + shift.add(PtNumber(BaseDataType.UBYTE, 1.0, defer.position)) defersRoutine.add(shift) val skiplabel = "prog8_defer_skip_${idx+1}" - val branchcc = PtConditionalBranch(BranchCondition.CC, Position.DUMMY) + val branchcc = PtConditionalBranch(BranchCondition.CC, defer.position) branchcc.add(PtNodeGroup().also { - val jump = PtJump(Position.DUMMY) - jump.add(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.UBYTE, Position.DUMMY)) + val jump = PtJump(defer.position) + jump.add(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.UBYTE, defer.position)) it.add(jump) }) branchcc.add(PtNodeGroup()) defersRoutine.add(branchcc) transferChildren(defer, defersRoutine, true) - defersRoutine.add(PtLabel(skiplabel, Position.DUMMY)) + defersRoutine.add(PtLabel(skiplabel, defer.position)) } -// val printMask = PtFunctionCall("txt.print_ubbin", true, DataType.UNDEFINED, Position.DUMMY) -// printMask.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, Position.DUMMY)) -// printMask.add(PtBool(true, Position.DUMMY)) +// val printMask = PtFunctionCall("txt.print_ubbin", true, DataType.UNDEFINED, sub.position) +// printMask.add(PtIdentifier(sub.scopedName+"."+maskVarName, DataType.UBYTE, sub.position)) +// printMask.add(PtBool(true, sub.position)) // defersRoutine.add(printMask) - defersRoutine.add(PtReturn(Position.DUMMY)) + defersRoutine.add(PtReturn(sub.position)) sub.add(defersRoutine) } } diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index 8028a8129..097d4072a 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -332,17 +332,17 @@ class TestCompilerOnExamplesVirtual: FunSpec({ val onlyVirtual = cartesianProduct( listOf( - ExampleSizes("bouncegfx", virtualLineCountOptimized=890, virtualLineCountUnoptimized=3552), - ExampleSizes("bsieve", virtualLineCountOptimized=800, virtualLineCountUnoptimized=4486), - ExampleSizes("fountain", virtualLineCountOptimized=720, virtualLineCountUnoptimized=3397), - ExampleSizes("pixelshader", virtualLineCountOptimized=368, virtualLineCountUnoptimized=1216), - ExampleSizes("sincos", virtualLineCountOptimized=1075, virtualLineCountUnoptimized=3600), - ExampleSizes("pointers/animalgame", virtualLineCountOptimized=879, virtualLineCountUnoptimized=8556), - ExampleSizes("pointers/binarytree", virtualLineCountOptimized=1998, virtualLineCountUnoptimized=5657), - ExampleSizes("pointers/hashtable", virtualLineCountOptimized=2232, virtualLineCountUnoptimized=9107), - ExampleSizes("pointers/sortedlist", virtualLineCountOptimized=1102, virtualLineCountUnoptimized=6642), - ExampleSizes("pointers/fountain-virtual", virtualLineCountOptimized=757, virtualLineCountUnoptimized=3436), - ExampleSizes("pointers/sorting", virtualLineCountOptimized=1532, virtualLineCountUnoptimized=9329) + ExampleSizes("bouncegfx", virtualLineCountOptimized=916, virtualLineCountUnoptimized=3604), + ExampleSizes("bsieve", virtualLineCountOptimized=828, virtualLineCountUnoptimized=4546), + ExampleSizes("fountain", virtualLineCountOptimized=746, virtualLineCountUnoptimized=3449), + ExampleSizes("pixelshader", virtualLineCountOptimized=390, virtualLineCountUnoptimized=1260), + ExampleSizes("sincos", virtualLineCountOptimized=1103, virtualLineCountUnoptimized=3654), + ExampleSizes("pointers/animalgame", virtualLineCountOptimized=894, virtualLineCountUnoptimized=8629), + ExampleSizes("pointers/binarytree", virtualLineCountOptimized=2023, virtualLineCountUnoptimized=5732), + ExampleSizes("pointers/hashtable", virtualLineCountOptimized=2267, virtualLineCountUnoptimized=9178), + ExampleSizes("pointers/sortedlist", virtualLineCountOptimized=1117, virtualLineCountUnoptimized=6713), + ExampleSizes("pointers/fountain-virtual", virtualLineCountOptimized=786, virtualLineCountUnoptimized=3491), + ExampleSizes("pointers/sorting", virtualLineCountOptimized=1548, virtualLineCountUnoptimized=9401) ), listOf(false, true) ) diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index d0b871af2..8852f04af 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -229,8 +229,8 @@ interface INameScope: IStatementContainer, INamedStatement { return null if (idx == scopedName.size - 1) { // was last path element - val pointer = IdentifierReference(scopedName, Position.DUMMY) - val ref = StructFieldRef(pointer, struct as StructDecl, fieldDt, field, Position.DUMMY) + val pointer = IdentifierReference(scopedName, localSymbol.position) + val ref = StructFieldRef(pointer, struct as StructDecl, fieldDt, field, localSymbol.position) ref.linkParents(this as Node) return ref } @@ -451,4 +451,4 @@ fun defaultZero(dt: BaseDataType, position: Position) = when(dt) { else -> throw FatalAstException("can only determine default zero value for a numeric type, not for $dt at $position") } -fun defaultZero(idt: InferredTypes.InferredType, position: Position) = defaultZero(idt.getOrUndef().base, position) \ No newline at end of file +fun defaultZero(idt: InferredTypes.InferredType, position: Position) = defaultZero(idt.getOrUndef().base, position) diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 07bd4a3be..c0c966911 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -798,7 +798,7 @@ class NumericLiteral(val type: BaseDataType, // only numerical types allowed operator fun compareTo(other: NumericLiteral): Int = number.compareTo(other.number) class ValueAfterCast(val isValid: Boolean, val whyFailed: String?, private val value: NumericLiteral?) { - fun valueOrZero() = if(isValid) value!! else NumericLiteral(BaseDataType.UBYTE, 0.0, Position.DUMMY) + fun valueOrZero() = if(isValid) value!! else NumericLiteral(BaseDataType.UBYTE, 0.0, value?.position ?: Position.DUMMY) fun linkParent(parent: Node) { value?.linkParents(parent) }