From d11386ef262e462eca05e5bded4fad16b2f26e40 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 4 May 2025 18:35:49 +0200 Subject: [PATCH] type check tuning --- codeCore/src/prog8/code/core/Enumerations.kt | 2 +- .../prog8/codegen/intermediate/IRCodeGen.kt | 6 +- .../compiler/astprocessing/AstChecker.kt | 101 ++++++++++++++---- .../compiler/astprocessing/VariousCleanups.kt | 11 +- compiler/test/codegeneration/TestVariables.kt | 4 +- .../src/prog8/ast/AstToSourceTextConverter.kt | 5 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 7 +- .../prog8/ast/expressions/AstExpressions.kt | 25 +++-- .../prog8/ast/expressions/InferredTypes.kt | 3 + .../src/prog8/ast/statements/AstStatements.kt | 2 +- docs/source/todo.rst | 18 ++-- examples/test.p8 | 69 +++++++----- 12 files changed, 172 insertions(+), 81 deletions(-) diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index b13303043..32c4f2a45 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -60,7 +60,7 @@ val BaseDataType.isStructInstance get() = this == BaseDataType.STRUCT_INSTANCE val BaseDataType.isPointerArray get() = this == BaseDataType.ARRAY_POINTER val BaseDataType.isStructArray get() = this == BaseDataType.ARRAY_STRUCT val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW -val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW, BaseDataType.ARRAY_POINTER, BaseDataType.POINTER) +val BaseDataType.isIterable get() = this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW, BaseDataType.ARRAY_POINTER) val BaseDataType.isPassByRef get() = this.isIterable && !this.isPointer val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 84a8aa057..cc9ae3b7b 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -493,10 +493,10 @@ class IRCodeGen( result += jumpChunk result += IRCodeChunk(endLabel, null) } - iterable.type.isSplitWordArray -> { - // iterate over lsb/msb split word array + iterable.type.isSplitWordArray || iterable.type.isPointerArray -> { + // iterate over lsb/msb split word/pointer array val elementDt = iterable.type.elementType() - if(!elementDt.isWord) + if(!elementDt.isWord && !elementDt.isPointer) throw AssemblyError("weird dt") addInstr(result, IRInstruction(Opcode.LOAD, IRDataType.BYTE, reg1=indexReg, immediate = 0), null) result += IRCodeChunk(loopLabel, null).also { diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 5b15748dd..8b7a5991c 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -206,43 +206,64 @@ internal class AstChecker(private val program: Program, if(loopvar==null || loopvar.type== VarDeclType.CONST) { errors.err("for loop requires a variable to loop with", forLoop.position) } else { - require(loopvar.datatype.isNumericOrBool) when (loopvar.datatype.base) { BaseDataType.UBYTE -> { - if(!iterableDt.isUnsignedByte && !iterableDt.isUnsignedByteArray && !iterableDt.isString) // TODO remove ubyte check? + if (!iterableDt.isUnsignedByte && !iterableDt.isUnsignedByteArray && !iterableDt.isString) // TODO remove ubyte check? errors.err("ubyte loop variable can only loop over unsigned bytes or strings", forLoop.position) checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) } + BaseDataType.BOOL -> { - if(!iterableDt.isBoolArray) + if (!iterableDt.isBoolArray) errors.err("bool loop variable can only loop over boolean array", forLoop.position) } + BaseDataType.UWORD -> { - if(!iterableDt.isUnsignedByte && !iterableDt.isUnsignedWord && !iterableDt.isString && // TODO remove byte and word check? - !iterableDt.isUnsignedByteArray && !iterableDt.isUnsignedWordArray && - !iterableDt.isSplitWordArray) + if (!iterableDt.isUnsignedByte && !iterableDt.isUnsignedWord && !iterableDt.isString && // TODO remove byte and word check? + !iterableDt.isUnsignedByteArray && !iterableDt.isUnsignedWordArray && + !iterableDt.isSplitWordArray + ) errors.err("uword loop variable can only loop over unsigned bytes, words or strings", forLoop.position) checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) } + BaseDataType.BYTE -> { - if(!iterableDt.isSignedByte && !iterableDt.isSignedByteArray) // TODO remove byte check? + if (!iterableDt.isSignedByte && !iterableDt.isSignedByteArray) // TODO remove byte check? errors.err("byte loop variable can only loop over bytes", forLoop.position) } + BaseDataType.WORD -> { - if(!iterableDt.isSignedByte && !iterableDt.isSignedWord && - !iterableDt.isSignedByteArray && !iterableDt.isUnsignedByteArray && - !iterableDt.isSignedWordArray && !iterableDt.isUnsignedWordArray) + if (!iterableDt.isSignedByte && !iterableDt.isSignedWord && + !iterableDt.isSignedByteArray && !iterableDt.isUnsignedByteArray && + !iterableDt.isSignedWordArray && !iterableDt.isUnsignedWordArray + ) errors.err("word loop variable can only loop over bytes or words", forLoop.position) } + BaseDataType.FLOAT -> { // Looping over float variables is very inefficient because the loopvar is going to // get copied over with new values all the time. We don't support this for now. // Loop with an integer index variable if you really need to... or write different code. errors.err("for loop only supports integers", forLoop.position) } - else -> errors.err("loop variable must be numeric type", forLoop.position) + + BaseDataType.POINTER -> { + if (!iterableDt.isUnsignedWord) { + if (iterableDt.isPointerArray) { + val elementDt = iterableDt.elementType() + if(loopvar.datatype != elementDt) + errors.err("loopvar type differs from the pointer types in the collection", forLoop.position) + } else + errors.err("pointer loop variable can only loop over pointers or unsigned words", forLoop.position) + } + + checkUnsignedLoopDownto0(forLoop.iterable as? RangeExpression) + } + + else -> errors.err("loop variable must be numeric or pointer type", forLoop.position) } + if(errors.noErrors()) { // check loop range values val range = forLoop.iterable as? RangeExpression @@ -885,19 +906,23 @@ internal class AstChecker(private val program: Program, if(declValue!=null && decl.type==VarDeclType.VAR) { val iDt = declValue.inferType(program) if (!(iDt istype decl.datatype)) { - if(decl.isArray) { + if(decl.datatype.isPointerArray) { + if(!iDt.getOrUndef().isWordArray) + valueerr("initialization value for pointer array must be a word array") + } + else if(decl.isArray) { val eltDt = decl.datatype.elementType() - if(!(iDt istype eltDt)) - valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") + if(!(iDt istype eltDt) && iDt.isKnown) + valueerr("initialization value has incompatible type ($iDt) for the variable (${decl.datatype})") } else if(!decl.datatype.isString) { if(!(iDt.isBool && decl.datatype.isUnsignedByte || iDt issimpletype BaseDataType.UBYTE && decl.datatype.isBool)) { // pointer variables can be initialized with a compatible pointer or with a uword if(decl.datatype.isPointer) { if (!iDt.isAssignableTo(decl.datatype)) - valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") + valueerr("initialization value has incompatible type ($iDt) for the variable (${decl.datatype})") } else - valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})") + valueerr("initialization value has incompatible type ($iDt) for the variable (${decl.datatype})") } } } @@ -993,6 +1018,11 @@ internal class AstChecker(private val program: Program, } } + if(decl.datatype.isPointerArray) { + if(decl.splitwordarray!= SplitWish.SPLIT) + errors.err("pointer arrays can only be @split", decl.position) + } + if (decl.dirty) { if(decl.datatype.isString) @@ -1165,11 +1195,13 @@ internal class AstChecker(private val program: Program, } val arrayspec = ArrayIndex.forArray(array) checkValueTypeAndRangeArray(array.type.getOrUndef(), arrayspec, array) + } else { + errors.err("undefined array type (multiple element types?)", array.position) } if(array.parent is VarDecl) { if (!array.value.all { it is NumericLiteral || it is AddressOf }) - errors.err("initialization list contains non-constant elements", array.value[0].position) + errors.err("initialization value contains non-constant elements", array.value[0].position) } else if(array.parent is ForLoop) { if (!array.value.all { it.constValue(program) != null }) errors.err("array literal for iteration must contain constants. Try using a separate array variable instead?", array.position) @@ -1214,6 +1246,12 @@ internal class AstChecker(private val program: Program, checkLongType(expr) val dt = expr.expression.inferType(program).getOrUndef() if(!dt.isUndefined) { + + if(dt.isPointerArray || dt.isPointer) { + errors.err("pointers don't support prefix operators", expr.position) + return + } + when (expr.operator) { "-" -> { if (!(dt.isSigned && dt.isNumeric)) { @@ -1266,6 +1304,9 @@ internal class AstChecker(private val program: Program, errors.err("defer cannot contain jumps or returns", defer.position) } + private val supportedPointerOperatorsVirtual: Set = emptySet() + private val supportedPointerOperators6502: Set = emptySet() + override fun visit(expr: BinaryExpression) { super.visit(expr) @@ -1353,6 +1394,20 @@ internal class AstChecker(private val program: Program, val leftDt = leftIDt.getOrUndef() val rightDt = rightIDt.getOrUndef() + // gate off non-functioning pointer arithmetic + if(compilerOptions.compTarget.name == VMTarget.NAME) { + if (expr.operator !in supportedPointerOperatorsVirtual) { + if (leftDt.isPointer || leftDt.isPointerArray || rightDt.isPointer || rightDt.isPointerArray) { + errors.err("pointer arithmetic operator '${expr.operator}' is not yet supported, will be added piecemeal", expr.position) + } + } + } + else if(expr.operator !in supportedPointerOperators6502) { + if (leftDt.isPointer || leftDt.isPointerArray || rightDt.isPointer || rightDt.isPointerArray) { + errors.err("pointer arithmetic operator '${expr.operator}' is not yet supported, will be added piecemeal", expr.position) + } + } + if(expr.operator=="+" || expr.operator=="-") { if(leftDt.isString || rightDt.isString || leftDt.isArray || rightDt.isArray) { errors.err("missing & (address-of) on the operand", expr.position) @@ -1728,14 +1783,14 @@ internal class AstChecker(private val program: Program, if(it is IdentifierReference) { val target = it.targetVarDecl() if(target!=null && target.datatype.isPointer) { - errors.err("a pointer variable cannot be used in a static initialization list because its value is only known at runtime (use 0 here, and assign it later manually)", it.position) + errors.err("a pointer variable cannot be used in a static initialization value because its value is only known at runtime (use 0 here, and assign it later manually)", it.position) } } } if (!args.all { it is NumericLiteral || it is AddressOf || (it is TypecastExpression && it.expression is NumericLiteral)}) - errors.err("initialization list contains non-constant elements", args[0].position) + errors.err("initialization value contains non-constant elements", args[0].position) if (target.fields.size != args.size) - errors.err("initialization list needs to be same number of values as the struct has fields: expected ${target.fields.size} or 0, got ${args.size}", args[0].position) + errors.err("initialization value needs to have same number of values as the struct has fields: expected ${target.fields.size} or 0, got ${args.size}", args[0].position) else target.fields.zip(args).withIndex().forEach { (index, fv) -> val (field, value) = fv @@ -1763,8 +1818,8 @@ internal class AstChecker(private val program: Program, checkLongType(arrayIndexedExpression) val target = arrayIndexedExpression.arrayvar.targetStatement(program) if(target is VarDecl) { - if(!target.datatype.isIterable && !target.datatype.isUnsignedWord) - errors.err("indexing requires an iterable or address uword variable", arrayIndexedExpression.position) + if(!target.datatype.isIterable && !target.datatype.isUnsignedWord && !target.datatype.isPointer) + errors.err("indexing requires an iterable, address uword, or pointer variable", arrayIndexedExpression.position) val indexVariable = arrayIndexedExpression.indexer.indexExpr as? IdentifierReference if(indexVariable!=null) { if(indexVariable.targetVarDecl()?.datatype?.isSigned==true) { @@ -2188,7 +2243,7 @@ internal class AstChecker(private val program: Program, } if (!correct) { if (value.parent is VarDecl && !value.value.all { it is NumericLiteral || it is AddressOf }) - errors.err("initialization list contains non-constant elements", value.value[0].position) + errors.err("initialization value contains non-constant elements", value.value[0].position) else errors.err("array element out of range for type $targetDt", value.position) } diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 15b9537e5..6ab404ade 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -24,10 +24,8 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, // check and possibly adjust value datatype vs decl datatype val valueType = decl.value?.inferType(program) if(valueType!=null && !valueType.istype(decl.datatype)) { - if(valueType.isUnknown) { - errors.err("value has incompatible type for ${decl.datatype}", decl.value!!.position) + if(valueType.isUnknown) return noModifications - } val valueDt = valueType.getOrUndef() when(decl.type) { VarDeclType.VAR -> { @@ -68,11 +66,12 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, } // check splitting of word arrays - if(!decl.datatype.isWordArray && decl.splitwordarray != SplitWish.DONTCARE) { + if(decl.splitwordarray != SplitWish.DONTCARE && !decl.datatype.isWordArray && !decl.datatype.isPointerArray) { if(decl.origin != VarDeclOrigin.ARRAYLITERAL) - errors.err("@split and @nosplit are for word arrays only", decl.position) + errors.err("@split and @nosplit are for word or pointer arrays only", decl.position) } - else if(decl.datatype.isWordArray) { + + if(decl.datatype.isWordArray) { var changeDataType: DataType? var changeSplit: SplitWish = decl.splitwordarray when(decl.splitwordarray) { diff --git a/compiler/test/codegeneration/TestVariables.kt b/compiler/test/codegeneration/TestVariables.kt index 203c192b9..1a893f4fd 100644 --- a/compiler/test/codegeneration/TestVariables.kt +++ b/compiler/test/codegeneration/TestVariables.kt @@ -100,8 +100,8 @@ class TestVariables: FunSpec({ val errors = ErrorReporterForTests() compileText(C64Target(), false, text, outputDir, writeAssembly = true, errors=errors) shouldBe null errors.errors.size shouldBe 2 - errors.errors[0] shouldContain "value has incompatible type" - errors.errors[1] shouldContain "value has incompatible type" + errors.errors[0] shouldContain "undefined array type" + errors.errors[1] shouldContain "undefined array type" } test("global var init with array lookup should sometimes be const") { diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index b0ee61440..89bfd3d70 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -353,13 +353,12 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program: override fun visit(assignment: Assignment) { val binExpr = assignment.value as? BinaryExpression - if(binExpr!=null && binExpr.left isSameAs assignment.target - && binExpr.operator !in ComparisonOperators) { - // we only support the inplace assignments of the form A = A + if(binExpr!=null && assignment.isAugmentable) { assignment.target.accept(this) output(" ${binExpr.operator}= ") binExpr.right.accept(this) } else { + val whyNot = assignment.isAugmentable assignment.target.accept(this) output(" = ") assignment.value.accept(this) diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 08503ec23..9b0b3b40f 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -874,11 +874,16 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl DataType.arrayFor(baseDt.base, split!=SplitWish.NOSPLIT) } + val splitWords = if(split==SplitWish.DONTCARE) { + if(dt.isPointerArray) SplitWish.SPLIT // pointer arrays are always @split by default + else split + } else split + return VarDecl( type, VarDeclOrigin.USERCODE, dt, zp, - split, + splitWords, arrayindex()?.toAst(), name, if(identifiers.size==1) emptyList() else identifiers, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 87191f322..f432e48ed 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -1054,7 +1054,7 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because return if(!loopvarDt.isNumericOrBool) InferredTypes.unknown() else - InferredTypes.InferredType.known(loopvarDt.getOrUndef().elementToArray()) + InferredTypes.knownFor(loopvarDt.getOrUndef().elementToArray()) } } @@ -1064,20 +1064,27 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because if(datatypesInArray.any{ it.isUnknown }) return InferredTypes.unknown() val dts = datatypesInArray.map { it.getOrUndef() } + if(dts.all { it.isPointer }) { + val unique = dts.toSet() + if(unique.size==1) { + val dt = unique.single() + return InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.sub, dt.subType)) + } + } return when { - dts.any { it.isFloat } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.FLOAT)) - dts.any { it.isString } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UWORD)) - dts.any { it.isSignedWord } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.WORD)) - dts.any { it.isUnsignedWord } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UWORD)) - dts.any { it.isSignedByte } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.BYTE)) + dts.any { it.isFloat } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.FLOAT)) + dts.any { it.isString } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.UWORD)) + dts.any { it.isSignedWord } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.WORD)) + dts.any { it.isUnsignedWord } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.UWORD)) + dts.any { it.isSignedByte } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.BYTE)) dts.any { it.isBool } -> { if(dts.all { it.isBool}) - InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.BOOL)) + InferredTypes.knownFor(DataType.arrayFor(BaseDataType.BOOL)) else InferredTypes.unknown() } - dts.any { it.isUnsignedByte } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UBYTE)) - dts.any { it.isArray } -> InferredTypes.InferredType.known(DataType.arrayFor(BaseDataType.UWORD)) + dts.any { it.isUnsignedByte } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.UBYTE)) + dts.any { it.isArray } -> InferredTypes.knownFor(DataType.arrayFor(BaseDataType.UWORD)) else -> InferredTypes.unknown() } } diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index 4ca3c5674..73fef0bd8 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -93,6 +93,9 @@ object InferredTypes { else -> throw IllegalArgumentException("invalid sub type") } } + type.isPointerArray -> { + InferredType.known(DataType.arrayOfPointersTo(type.sub, type.subType)) + } type.isArray -> { InferredType.known(DataType.arrayFor(type.sub!!, false)) } diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 7126ed0f1..9ac037ba0 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -668,7 +668,7 @@ data class AssignTarget( multi != null -> false pointerDereference !=null -> { if(value is PtrDereference) { - return if(pointerDereference!!.identifier!=value.identifier || pointerDereference!!.field!=value.field) + return if(!(pointerDereference!!.identifier isSameAs value.identifier) || pointerDereference!!.field!=value.field) false else pointerDereference!!.chain == value.chain diff --git a/docs/source/todo.rst b/docs/source/todo.rst index be519409a..607a30ea8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -28,24 +28,28 @@ STRUCTS and TYPED POINTERS - DONE (for basic types only): allow array syntax on pointers too: ptr[2] means ptr+sizeof()*2, ptr[0] just means ptr^^ . - DONE (?) allow array syntax on pointers to structs too, but what type will ptr[2] have? And it will require ptr[2].field to work as well now. Actually that will be the only thing to work for now. - DONE: allow multi-field declarations in structs -- static initialization of structs may be allowed only at block scope and then behaves like arrays; it won't reset to the original value when program is restarted, so beware. - Syntax could be: ^^Node ptr = Node(1,2,3,4) statically allocates a Node with fields set to 1,2,3,4 and puts the address in ptr. -- Node() without arguments could allocate a node in BSS variable space instead. -- What about static initialization of an array of struct pointers? -- support @dirty on pointer vars +- DONE: static initialization of structs. It behaves like arrays; it won't reset to the original value when program is restarted, so beware. + Syntax: ^^Node ptr = Node(1,2,3,4) statically allocates a Node with fields set to 1,2,3,4 and puts the address in ptr. + Node() without arguments allocates a node in BSS variable space instead that gets zeroed out at startup. +- DONE: pointer arrays are split-words only, enforce this (variable dt + initializer array dt) +- DONE: make an error message for all pointer expressions (prefixed, binary) so we can start implementing the ones we need one by one. +- start by making ptr.value++ work , and ptr.value = ptr.value+20, and ptr.value = cx16.r0L+20+ptr.value Likewise for -- DON'T FORGET C POINTER SEMANTICS +- fix actual _msb/_lsb storage of the split-words pointer-arrays +- support @dirty on pointer vars -> uninitialized pointer placed in BSS_noclear segment - pointer types in subroutine signatures (both normal and asm-subs) - support chaining pointer dereference on function calls that return a pointer. (type checking now fails on stuff like func().field and func().next.field) - are the ARRAY_POINTER and ARRAY_STRUCT data type enums realy needed? can't we just use ARRAY? - pointer arithmetic should follow C: ptr=ptr+10 adds 10*sizeof() instead of just 10. - fixing the pointer dereferencing issues (cursed hybrid beween IdentifierReference, PtrDereferece and PtrIndexedDereference) may require getting rid of scoped identifiers altogether and treat '.' as a "scope or pointer following operator" - add unit tests for all changes -- arrays of structs? No -> Just an array of uword pointers to said structs. Can even be @split as the only representation form because that's the default for word arrays. +- arrays of structs? No -> Just an array of uword pointers to said structs. - allow memory-mapped structs? Something like &Sprite sprite0 = $9000 basically behaves identically to a typed pointer, but the address is immutable as usual - existing STR and ARRAY remain unchanged (don't become typed pointers) so we can keep doing register-indexed addressing directly on them - rather than str or uword parameter types for routines with a string argument, use ^^str (or ^^ubyte maybe? these are more or less identical..?) - pointer-to-array syntax = TBD - what about pointers to subroutines? should these be typed as well now? -- asm symbol name prefixing should work for dereferences too. +- What about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not contants +- 6502 asm symbol name prefixing should work for dereferences too. Future Things and Ideas diff --git a/examples/test.p8 b/examples/test.p8 index 02577989f..b7a660a8c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,9 +4,8 @@ main { sub start() { - - uword buf = memory("buffer", 2000, 0) - sys.memset(buf, 2000, 0) +; uword buf = memory("buffer", 2000, 0) +; sys.memset(buf, 2000, 0) ; put 9 nodes into the buffer sequentially. ; each of the first 3 nodes points to the 4th, 5th, 6th. @@ -18,29 +17,49 @@ main { ^^Node next } + +; TODO (Borked:) + ^^Node @shared ptr = 2000 + ptr++ + ptr += 2 + ptr = cx16.r0 + ptr + ptr = cx16.r0 + ptr + 10 +; ptr.value++ +; ptr.value += 30 +; ptr.value = ptr.value + 20 +; ptr.value = cx16.r0L+20+ptr.value + ; static initializer syntax: - ^^Node @shared node0 = Node() ; no initialization (will be in BSS and zeroed out at startup) - ^^Node @shared node1 = Node( false, 11, 0 ) - ^^Node @shared node2 = Node( false, 22, 0 ) - ^^Node @shared node3 = Node( true, 33, 0 ) - - ; link up - node0.next = node1 - node1.next = node2 - node2.next = node3 - - ^^Node nptr = node0 - while nptr { - txt.print("node at ") - txt.print_uw(nptr) - txt.print("\n flag=") - txt.print_bool(nptr.flag) - txt.print("\n value=") - txt.print_ub(nptr.value) - txt.nl() - nptr = nptr.next - } - +; ^^Node @shared node0 = Node() ; no initialization (will be in BSS and zeroed out at startup) +; ^^Node @shared node1 = Node( false, 11, 0 ) +; ^^Node @shared node2 = Node( false, 22, 0 ) +; ^^Node @shared node3 = Node( true, 33, 0 ) +; +; ; list of pointers: (W.I.P.): +;; ^^Node[5] @shared nodes +;; for nptr in nodes { +;; txt.print_uw(nptr) +;; txt.spc() +;; } +;; txt.nl() +; +; ; link up +; node0.next = node1 +; node1.next = node2 +; node2.next = node3 +; +; ^^Node nptr = node0 +; while nptr { +; txt.print("node at ") +; txt.print_uw(nptr) +; txt.print("\n flag=") +; txt.print_bool(nptr.flag) +; txt.print("\n value=") +; txt.print_ub(nptr.value) +; txt.nl() +; nptr = nptr.next +; } +; ; ^^Node n0,n1,n2,n3,n4,n5,n6,n7,n8 ; ; n0 = buf + 0