mirror of
https://github.com/irmen/prog8.git
synced 2025-10-25 05:18:38 +00:00
cleaning up pointer indexing
This commit is contained in:
@@ -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<IRCodeChunkBase>()
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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<IRCodeChunkBase>()
|
||||
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<IRCodeChunkBase>()
|
||||
var actualDeref = deref
|
||||
|
||||
@@ -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]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,27 +424,26 @@ class ExpressionSimplifier(private val program: Program, private val errors: IEr
|
||||
}
|
||||
|
||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -216,12 +216,17 @@ _after:
|
||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||
// 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<IAstModification> {
|
||||
|
||||
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))
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,17 +428,21 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<ArrayIndexedExpression>()
|
||||
val a_fl = (st[21] as Assignment).value
|
||||
a_fl shouldBe instanceOf<ArrayIndexedExpression>()
|
||||
val a_bb = (st[22] as Assignment).value
|
||||
a_bb shouldBe instanceOf<ArrayIndexedExpression>()
|
||||
val a_r0 = (st[23] as Assignment).value
|
||||
a_r0 shouldBe instanceOf<DirectMemoryRead>()
|
||||
val a_r1 = (st[24] as Assignment).value
|
||||
a_r1 shouldBe instanceOf<DirectMemoryRead>()
|
||||
val a_r2 = (st[25] as Assignment).value
|
||||
a_r2 shouldBe instanceOf<ArrayIndexedExpression>()
|
||||
val a_lptr2 = (st[25] as Assignment).value
|
||||
a_lptr2 shouldBe instanceOf<ArrayIndexedExpression>()
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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 ")
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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<String>) = arrayvar.referencesIdentifier(nameInSource) || indexer.referencesIdentifier(nameInSource)
|
||||
override fun referencesIdentifier(nameInSource: List<String>) =
|
||||
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<String>) = indexed.referencesIdentifier(nameInSource)
|
||||
}
|
||||
|
||||
class PtrDereference(
|
||||
val identifier: IdentifierReference,
|
||||
val chain: List<String>,
|
||||
@@ -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<String>) = 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 {
|
||||
|
||||
@@ -593,7 +593,6 @@ data class AssignTarget(
|
||||
val multi: List<AssignTarget>?,
|
||||
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<String>): 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}")
|
||||
|
||||
@@ -106,7 +106,6 @@ abstract class AstWalker {
|
||||
open fun before(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(idxderef: PtrIndexedDereference, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun before(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications
|
||||
@@ -156,7 +155,6 @@ abstract class AstWalker {
|
||||
open fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(deref: PtrDereference, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(idxderef: PtrIndexedDereference, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(struct: StructDecl, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(field: StructFieldRef, parent: Node): Iterable<IAstModification> = noModifications
|
||||
open fun after(directive: Directive, parent: Node): Iterable<IAstModification> = 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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' ;
|
||||
|
||||
@@ -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<String>, 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)
|
||||
|
||||
@@ -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)}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user