diff --git a/codeCore/src/prog8/code/core/Enumerations.kt b/codeCore/src/prog8/code/core/Enumerations.kt index 3a0225ead..ef10e8fca 100644 --- a/codeCore/src/prog8/code/core/Enumerations.kt +++ b/codeCore/src/prog8/code/core/Enumerations.kt @@ -84,7 +84,11 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType } base==BaseDataType.STR -> require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" } base!=BaseDataType.POINTER -> require(sub == null) { "only string, array and pointer base types can have a subtype"} - else -> require(sub == null || (subType == null && subTypeFromAntlr == null)) { "sub and subtype can't both be set" } + else -> { + require(sub == null || (subType == null && subTypeFromAntlr == null)) { + "sub and subtype can't both be set" + } + } } } @@ -144,15 +148,21 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType } } - fun arrayOfPointersTo(sub: BaseDataType?, subType: ISubType?): DataType = - DataType(BaseDataType.ARRAY_POINTER, sub, subType) + fun arrayOfPointersTo(sub: BaseDataType): DataType = DataType(BaseDataType.ARRAY_POINTER, sub, null) + fun arrayOfPointersTo(structType: ISubType?): DataType = DataType(BaseDataType.ARRAY_POINTER, null, structType) fun arrayOfPointersFromAntlrTo(sub: BaseDataType?, identifier: List?): DataType = DataType(BaseDataType.ARRAY_POINTER, sub, null, identifier) fun pointer(base: BaseDataType): DataType = DataType(BaseDataType.POINTER, base, null) - fun pointerToType(type: ISubType): DataType = DataType(BaseDataType.POINTER, null, type) - fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, type) + fun pointer(dt: DataType): DataType { + if(dt.isBasic) + return DataType(BaseDataType.POINTER, dt.base, null) + else + return DataType(BaseDataType.POINTER, null, dt.subType, dt.subTypeFromAntlr) + } + fun pointer(structType: ISubType): DataType = DataType(BaseDataType.POINTER, null, structType, null) fun pointerFromAntlr(identifier: List): DataType = DataType(BaseDataType.POINTER, null, null, identifier) + fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, type) fun structInstanceFromAntlr(struct: List): DataType = DataType(BaseDataType.STRUCT_INSTANCE, null, null, subTypeFromAntlr = struct) } @@ -184,10 +194,10 @@ class DataType private constructor(val base: BaseDataType, val sub: BaseDataType return pointer(BaseDataType.UBYTE) val elementDt = elementType() require(elementDt.isBasic) - return pointer(elementDt.base) + return pointer(elementDt) } if (subType != null) - return pointerToType(subType!!) + return pointer(this) return UWORD } } diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt index 626e72c43..4ef58c2cd 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt @@ -98,25 +98,28 @@ internal class ExpressionGen(private val codeGen: IRCodeGen) { } private fun translate(idxderef: PtPointerIndexedDeref): ExpressionCodeResult { - val idx = idxderef.indexer 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() - val pointerTr = translateExpression(idx.variable) - result += pointerTr.chunks - val pointerReg = pointerTr.resultReg - val constIndex = idx.index.asConstInteger() + if(!idxderef.variable.type.isPointer) { + TODO("expression: indexing non-pointer field ${idxderef.variable}") + } + + TODO("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(idx.index) + val indexTr = translateExpression(idxderef.index) result += indexTr.chunks result += IRCodeChunk(null, null).also { val indexReg: Int - if (idx.index.type.isByte) { + 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) diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index 0b8ec8d1b..ff9b1a02a 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -108,21 +108,12 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro val type = idxderef.inferType(program).getOrElse { throw FatalAstException("unknown dt") } - require(type.isPointer || type.isUnsignedWord) - if(type.isUnsignedWord) { - if(idxderef.parent is AssignTarget) - TODO("as assignment target: indexing uword field $idxderef") // TODO hmm, wasn't there code elsewhere for this already? - else - TODO("as value: indexing uword field $idxderef") // TODO hmm, wasn't there code elsewhere for this already? - } else { - val deref = PtPointerIndexedDeref(DataType.forDt(type.sub!!), idxderef.position) - val indexer = PtArrayIndexer(DataType.forDt(type.sub!!), idxderef.position) - val identifier = PtIdentifier(idxderef.indexed.arrayvar.nameInSource.joinToString("."), type, idxderef.indexed.arrayvar.position) - indexer.add(identifier) - indexer.add(transformExpression(idxderef.indexed.indexer.indexExpr)) - deref.add(indexer) - return deref - } + 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 { @@ -411,8 +402,7 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro val call = if(targetStruct!=null) { // a call to a struct yields a pointer to a struct instance and means: allocate a statically initialized struct instance of that type - val pointertype = DataType.pointerToType(targetStruct) - PtBuiltinFunctionCall("structalloc", false, true, pointertype, srcCall.position) + PtBuiltinFunctionCall("structalloc", false, true, DataType.pointer(targetStruct), srcCall.position) } else { // regular function call val (target, _) = srcCall.target.targetNameAndType(program) diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 9d3721e69..3cbaf0808 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -84,7 +84,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, changeDataType = if(decl.datatype.isSplitWordArray) null else { val eltDt = decl.datatype.elementType() if(eltDt.isPointer) - DataType.arrayOfPointersTo(eltDt.base, eltDt.subType) + TODO("convert array of pointers to split words array type") else DataType.arrayFor(eltDt.base) } @@ -95,7 +95,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter, changeDataType = if(decl.datatype.isSplitWordArray) null else { val eltDt = decl.datatype.elementType() if(eltDt.isPointer) - DataType.arrayOfPointersTo(eltDt.base, eltDt.subType) + TODO("convert array of pointers to split words array type") else DataType.arrayFor(eltDt.base) } diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index d49de915b..9e66e208f 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -274,7 +274,7 @@ main { DataType.arrayFor(BaseDataType.UWORD, false).typeForAddressOf(true) shouldBe DataType.pointer(BaseDataType.UBYTE) DataType.arrayFor(BaseDataType.UWORD, true).typeForAddressOf(true) shouldBe DataType.pointer(BaseDataType.UBYTE) - DataType.pointerToType(Struct("struct")).typeForAddressOf(false) shouldBe DataType.UWORD + DataType.pointer(Struct("struct")).typeForAddressOf(false) shouldBe DataType.UWORD DataType.pointerFromAntlr(listOf("struct")).typeForAddressOf(false) shouldBe DataType.UWORD DataType.pointer(BaseDataType.BOOL).typeForAddressOf(false) shouldBe DataType.UWORD diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 2274153d6..d40cc9466 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -1093,7 +1093,10 @@ class ArrayLiteral(val type: InferredTypes.InferredType, // inferred because val unique = dts.toSet() if(unique.size==1) { val dt = unique.single() - return InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.sub, dt.subType)) + return if(dt.subType!=null) + InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.subType!!)) + else + InferredTypes.knownFor(DataType.arrayOfPointersTo(dt.sub!!)) } } return when { @@ -1474,7 +1477,7 @@ class FunctionCallExpression(override var target: IdentifierReference, } is StructDecl -> { // calling a struct is syntax for allocating a static instance, and returns a pointer to that (not the instance itself) - return InferredTypes.knownFor(DataType.pointerToType(stmt)) + return InferredTypes.knownFor(DataType.pointer(stmt)) } else -> return InferredTypes.unknown() } @@ -1691,7 +1694,7 @@ class PtrDereference(val identifier: IdentifierReference, val chain: List throw IllegalArgumentException("invalid sub type") } } - type.isPointerArray -> { - InferredType.known(DataType.arrayOfPointersTo(type.sub, type.subType)) - } - type.isArray -> { - InferredType.known(DataType.arrayFor(type.sub!!, false)) - } - type.isPointer -> { - if(type.subType!=null) - InferredType.known(DataType.pointerToType(type.subType!!)) - else if(type.sub!=null) - InferredType.known(DataType.pointer(type.sub!!)) - else - InferredType.known(DataType.pointerFromAntlr(type.subTypeFromAntlr!!)) - } - type.isPointerArray -> InferredType.known(DataType.arrayOfPointersTo(type.sub, type.subType)) - type.isStructInstance -> { - if(type.subType!=null) - InferredType.known(DataType.structInstance(type.subType!!)) - else - InferredType.known(DataType.structInstanceFromAntlr(type.subTypeFromAntlr!!)) - } + type.isPointerArray -> InferredType.known(type) + type.isArray -> InferredType.known(type) + type.isPointer -> InferredType.known(type) + type.isStructInstance -> InferredType.known(type) else -> throw IllegalArgumentException("invalid type $type") } } diff --git a/examples/test.p8 b/examples/test.p8 index a018097e8..6d5e0bddd 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,6 +6,9 @@ main { sub start() { ^^List l1 = List() cx16.r0= l1.s[2] - l1.s[10] = 2 + l1.s[2] = cx16.r1L + + + ; l1.s^^ = 2 TODO fix undefined symbol } } diff --git a/intermediate/src/prog8/intermediate/IRFileReader.kt b/intermediate/src/prog8/intermediate/IRFileReader.kt index 6ad33ff7d..34279aceb 100644 --- a/intermediate/src/prog8/intermediate/IRFileReader.kt +++ b/intermediate/src/prog8/intermediate/IRFileReader.kt @@ -617,14 +617,14 @@ class IRFileReader { if(isArray) { if(type[0]=='^') { return when(type.drop(1)) { - "bool" -> DataType.arrayOfPointersTo(BaseDataType.BOOL, null) - "byte" -> DataType.arrayOfPointersTo(BaseDataType.BYTE, null) - "ubyte", "str" -> DataType.arrayOfPointersTo(BaseDataType.UBYTE, null) - "word" -> DataType.arrayOfPointersTo(BaseDataType.WORD, null) - "uword" -> DataType.arrayOfPointersTo(BaseDataType.UWORD, null) - "float" -> DataType.arrayOfPointersTo(BaseDataType.FLOAT, null) - "long" -> DataType.arrayOfPointersTo(BaseDataType.LONG, null) - else -> DataType.arrayOfPointersTo(null, IRSubtypePlaceholder(type.drop(1))) + "bool" -> DataType.arrayOfPointersTo(BaseDataType.BOOL) + "byte" -> DataType.arrayOfPointersTo(BaseDataType.BYTE) + "ubyte", "str" -> DataType.arrayOfPointersTo(BaseDataType.UBYTE) + "word" -> DataType.arrayOfPointersTo(BaseDataType.WORD) + "uword" -> DataType.arrayOfPointersTo(BaseDataType.UWORD) + "float" -> DataType.arrayOfPointersTo(BaseDataType.FLOAT) + "long" -> DataType.arrayOfPointersTo(BaseDataType.LONG) + else -> DataType.arrayOfPointersTo(IRSubtypePlaceholder(type.drop(1))) } } return when(type) { @@ -651,7 +651,7 @@ class IRFileReader { "float" -> DataType.pointer(BaseDataType.FLOAT) "long" -> DataType.pointer(BaseDataType.LONG) // note: 'str' should not occur anymore in IR. Should be 'uword' - else -> DataType.pointerToType(IRSubtypePlaceholder(type.drop(1))) + else -> DataType.pointer(IRSubtypePlaceholder(type.drop(1))) } } return when(type) { diff --git a/simpleAst/src/prog8/code/ast/AstExpressions.kt b/simpleAst/src/prog8/code/ast/AstExpressions.kt index 2cfe52096..552466468 100644 --- a/simpleAst/src/prog8/code/ast/AstExpressions.kt +++ b/simpleAst/src/prog8/code/ast/AstExpressions.kt @@ -116,7 +116,7 @@ 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.indexer.isSimple() + is PtPointerIndexedDeref -> this.index.isSimple() is PtTypeCast -> value.isSimple() is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple() } @@ -415,8 +415,10 @@ class PtPointerDeref(type: DataType, val chain: List, val field: String? } class PtPointerIndexedDeref(type: DataType, position: Position) : PtExpression(type, position) { - val indexer: PtArrayIndexer - get() = children.single() as PtArrayIndexer + val variable: PtIdentifier + get() = children[0] as PtIdentifier + val index: PtExpression + get() = children[1] as PtExpression } // special node that isn't created from compiling user code, but used internally in the Intermediate Code