8.5 KiB
Implementation Plan: Remove ARRAY_POINTER from Type System
Overview
Goal: Remove the target-dependent ARRAY_POINTER type and replace it with ARRAY using a pointer element type, making the type system target-independent.
Current Problem: ARRAY_POINTER has different memory layouts on different targets (split word on 6502, regular long on m68k/virtual), requiring target checks throughout the codebase. This is described as "horrible" in todo.rst.
Solution: Use ARRAY(sub=POINTER, ...) with a new field to store the pointee base type, making the layout decision explicit at allocation/codegen time.
Decisions:
- Remove
ARRAY_POINTERentirely (no deprecated alias) - No backward compatibility for old
.p8irfiles - Implement incrementally, phase by phase with verification
New Type Representation
Current
DataType(ARRAY_POINTER, sub=UBYTE) // array of pointers to ubyte
DataType(ARRAY_POINTER, sub=STRUCT, subType=X) // array of pointers to struct X
New
DataType(ARRAY, sub=POINTER, pointeeSub=UBYTE) // array of pointers to ubyte
DataType(ARRAY, sub=POINTER, pointeeSub=STRUCT, subType=X) // array of pointers to struct X
Key Change: Add pointeeSub: BaseDataType? field to DataType to store what the pointers point to.
Phase 1: Core Type System Changes
File: codeCore/src/prog8/code/core/DataTypes.kt
Changes:
- Remove
ARRAY_POINTERfromBaseDataTypeenum (line 23) - Add
pointeeSub: BaseDataType?field toDataType(after line 196) - Update
DataTypeconstructor andcopy()method to include new field - Remove
arrayOfPointersTo()factory methods (lines 218-222) - replace with new versions that createARRAYwithPOINTERsubtype - Update
elementType()(line 252-259):- For
ARRAYwithsub=POINTER: returnDataType(POINTER, sub=pointeeSub, subType=subType)
- For
- Update
isSplitWordArray()(line 476-482):- Check
sub==POINTER && memsizer.POINTER_MEM_SIZE<=2uinstead ofbase==ARRAY_POINTER
- Check
- Remove
isPointerArrayalias fromBaseDataType(line 93) - Add
DataType.isPointerArrayextension property:isArray && sub==POINTER - Update
isAssignableTo()(lines 396-409):- Replace
ARRAY_POINTERcases withARRAY+sub=POINTERchecks
- Replace
- Update
toString()andsourceString()(lines 323-364):- Handle
ARRAYwithsub=POINTERto print as^^subtype[]
- Handle
Verification:
- Compile
codeCoremodule:gradle :codeCore:compileKotlin --console=plain - Run
codeCoretests:gradle :codeCore:test --console=plain
Phase 2: Type Creation
File: compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt
Line 232-233: Update parser to create ARRAY with POINTER subtype instead of ARRAY_POINTER
File: compilerAst/src/prog8/ast/expressions/AstExpressions.kt
Lines 1284-1292: Update array literal type inference to create ARRAY with POINTER subtype
Verification:
- Compile
compilerAstmodule:gradle :compilerAst:compileKotlin --console=plain
Phase 3: Type Checking and Validation
File: compiler/src/prog8/compiler/astprocessing/AstChecker.kt
8 references (lines 306, 992, 1050, 1146, 1258, 1525, 1688, 2540):
- Replace
isPointerArraychecks withdatatype.isPointerArray(using new extension property) - Or inline as
datatype.isArray && datatype.sub==POINTER
File: compiler/src/prog8/compiler/astprocessing/ImplicitForIteratorDecls.kt
Lines 61-62: Update for-loop iterator type checking
Verification:
- Compile
compilermodule:gradle :compiler:compileKotlin --console=plain
Phase 4: AST Transformations
File: compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt
Lines 132, 1015: Update prefix operator and struct dereference checks
File: compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt
Lines 34, 96, 145-152: Update type compatibility and @nosplit handling
File: compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVarsAndRecombineIdentifiers.kt
Line 88: Update struct field resolution for pointer arrays
Verification:
- Compile
compilermodule:gradle :compiler:compileKotlin --console=plain
Phase 5: Memory Sizing
File: codeCore/src/prog8/code/target/NormalMemSizer.kt
Lines 13-14: Update memory size calculation for ARRAY with POINTER subtype
File: codeCore/testFixtures/kotlin/prog8tests/helpers/Dummies.kt
Lines 15-16: Update test memory sizer
File: compiler/test/helpers/Dummies.kt
Lines 38-39: Update compiler test memory sizer
Verification:
- Compile and test
codeCore:gradle :codeCore:test --console=plain
Phase 6: IR Handling
File: intermediate/src/prog8/intermediate/Utils.kt
Lines 18-22: Update IR type string serialization
- Change
^^prefix format to regular array format with pointer subtype
File: intermediate/src/prog8/intermediate/IRFileReader.kt
Lines 601-611: Update IR file deserialization
- Parse new format and create
ARRAYwithPOINTERsubtype
Verification:
- Compile
intermediatemodule:gradle :intermediate:compileKotlin --console=plain - Run
intermediatetests if any
Phase 7: Code Generation
File: codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt
Lines 831-832: Update uninitialized pointer array emission for 6502
File: codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt
Lines 908-910: Update typecast to pointer array (currently TODO)
File: codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt
Line 752: Update for-loop iteration to use new isSplitWordArray logic
Verification:
- Compile codegen modules:
gradle :codeGenCpu6502:compileKotlin :codeGenIntermediate:compileKotlin --console=plain
Phase 8: VM Updates
File: virtualmachine/src/prog8/vm/VmProgramLoader.kt
Lines 245-247, 447-456: Update variable zeroing and array initialization
Verification:
- Compile
virtualmachinemodule:gradle :virtualmachine:compileKotlin --console=plain
Phase 9: Builtin Functions
File: codeCore/src/prog8/code/core/BuiltinFunctions.kt
Line 27: Update IterableDatatypes array (remove ARRAY_POINTER)
Phase 10: Tests and Documentation
Test Files:
codeCore/test/prog8tests/codecore/TestDataType.kt(lines 96, 110-112)compiler/test/ast/TestVariousCompilerAst.kt(line 1557)
Documentation:
docs/source/todo.rst(line 10): Remove TODO itemvm32.md(lines 133-142): Update dev notes
Verification:
- Run all tests:
gradle build --console=plain
Verification Strategy
After each phase:
- Compile the affected module(s)
- Run module-specific tests
- After all phases: run full build with
gradle build --console=plain
Manual Testing:
Create test programs with pointer arrays:
%zeropage basicsafe
%option no_sysinit
main {
^ubyte[3] ptrs
^structDef[2] structPtrs
sub start() {
; test pointer array operations
}
}
Compile for multiple targets:
prog8c -target cx16 test.p8prog8c -target virtual test.p8prog8c -target c64 test.p8
Risk Mitigation
- Incremental implementation: Complete and verify each phase before moving to next
- Type safety: Ensure
pointeeSubfield is properly propagated through all type operations - Memory layout: Verify split-word logic works correctly on all targets
Estimated Effort
- Phase 1-2: 2-3 hours (core type system)
- Phase 3-4: 2-3 hours (validation and transforms)
- Phase 5-6: 1-2 hours (memory and IR)
- Phase 7-8: 2-3 hours (codegen and VM)
- Phase 9-10: 1-2 hours (tests and docs)
- Total: 8-13 hours
Files Affected Summary
Total: ~18 Kotlin source files + 2 documentation files, ~60 reference points
By Category:
| Category | Files | References |
|---|---|---|
| Type system | DataTypes.kt | 15+ |
| AST validation | AstChecker.kt | 8 |
| AST transforms | CodeDesugarer.kt, VariousCleanups.kt, LiteralsToAutoVars.kt | 7 |
| IR handling | Utils.kt, IRFileReader.kt | 10 |
| Code generation | ProgramAndVarsGen.kt, ExpressionGen.kt, IRCodeGen.kt | 3 |
| VM | VmProgramLoader.kt | 2 |
| Memory sizing | NormalMemSizer.kt, Dummies.kt (2 files) | 3 |
| Type creation | Antlr2KotlinVisitor.kt, AstExpressions.kt | 2 |
| Builtin functions | BuiltinFunctions.kt | 1 |
| Tests | TestDataType.kt, TestVariousCompilerAst.kt | 3 |
| Documentation | todo.rst, vm32.md | 2 |