diff --git a/codeCore/src/prog8/code/target/NormalMemSizer.kt b/codeCore/src/prog8/code/target/NormalMemSizer.kt index 6762ad5f2..ac7994a3d 100644 --- a/codeCore/src/prog8/code/target/NormalMemSizer.kt +++ b/codeCore/src/prog8/code/target/NormalMemSizer.kt @@ -29,6 +29,7 @@ internal class NormalMemSizer(val floatsize: Int): IMemSizer { dt.isFloat -> floatsize * (numElements ?: 1) dt.isLong -> 4 * (numElements ?: 1) dt.isPointer -> 2 // pointer is just a uword + dt.isStructInstance -> dt.subType!!.memsize(this) dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size") else -> 2 * (numElements ?: 1) } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 1b52e8863..8231979a8 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -2367,8 +2367,12 @@ internal class AstChecker(private val program: Program, } else if(targetDatatype.isString && sourceDatatype.isUnsignedWord) errors.err("can't assign uword to str. If the source is a string pointer and you actually want to overwrite the target string, use an explicit strings.copy(src,tgt) instead.", position) - else if(targetDatatype.isStructInstance) - errors.err("assigning to struct instance not supported (use pointers)", position) + else if(targetDatatype.isStructInstance) { + if(sourceDatatype.isStructInstance && sourceDatatype != targetDatatype) + errors.err("value type $sourceDatatype doesn't match target type $targetDatatype", position) + else + errors.err("assigning to struct instance not supported (use pointers)", position) + } else errors.err("value type $sourceDatatype doesn't match target type $targetDatatype", position) diff --git a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt index e65bbe389..deb3932c5 100644 --- a/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt +++ b/compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt @@ -27,6 +27,7 @@ internal class CodeDesugarer(val program: Program, private val target: ICompilat // - convert on..goto/call to jumpaddr array and separate goto/call // - replace implicit pointer dereference chains (a.b.c.d) with explicit ones (a^^.b^^.c^^.d) // - replace ptr^^ by @(ptr) if ptr is just an uword. + // - replace p1^^ = p2^^ by memcopy. override fun after(alias: Alias, parent: Node): Iterable { return listOf(IAstModification.Remove(alias, parent as IStatementContainer)) @@ -556,4 +557,24 @@ _after: return noModifications } + + override fun after(assignment: Assignment, parent: Node): Iterable { + val targetDt = assignment.target.inferType(program) + val sourceDt = assignment.value.inferType(program) + if(targetDt.isStructInstance && sourceDt.isStructInstance) { + if(targetDt == sourceDt) { + val size = program.memsizer.memorySize(sourceDt.getOrUndef(), null) + require(program.memsizer.memorySize(targetDt.getOrUndef(), null)==size) + val sourcePtr = IdentifierReference((assignment.value as PtrDereference).chain, assignment.position) + val targetPtr = IdentifierReference(assignment.target.pointerDereference!!.chain, assignment.position) + val numBytes = NumericLiteral.optimalInteger(size, assignment.position) + val memcopy = FunctionCallStatement(IdentifierReference(listOf("sys", "memcopy"), assignment.position), + mutableListOf(sourcePtr, targetPtr, numBytes), + false, assignment.position) + return listOf(IAstModification.ReplaceNode(assignment, memcopy, parent)) + } + } + + return noModifications + } } diff --git a/compiler/test/TestPointers.kt b/compiler/test/TestPointers.kt index d5eaec807..1c6d4e245 100644 --- a/compiler/test/TestPointers.kt +++ b/compiler/test/TestPointers.kt @@ -11,6 +11,7 @@ import prog8.ast.expressions.ArrayIndexedExpression import prog8.ast.expressions.DirectMemoryRead import prog8.ast.expressions.PtrDereference import prog8.ast.statements.Assignment +import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.VarDecl import prog8.code.ast.PtAssignment import prog8.code.ast.PtReturn @@ -844,4 +845,71 @@ main { compileText(VMTarget(), true, src, outputDir) shouldNotBe null } + + test("assigning pointer dereferences via memcopy") { + val src=""" +%option enable_floats + +main { + sub start() { + struct List { + bool b + word w + float f + ^^List next + } + + struct Foo { + byte bb + } + + ^^List l1 = 2000 + ^^List l2 = 3000 + ^^Foo f1 = 4000 + + l1^^ = l2^^ + } +}""" + + val result = compileText(VMTarget(), false, src, outputDir)!! + val st = result.compilerAst.entrypoint.statements + st.size shouldBe 10 + (st[8] as FunctionCallStatement).target.nameInSource shouldBe listOf("sys", "memcopy") + } + + test("assigning pointer dereferences should be same type") { + val src=""" +%option enable_floats + +main { + sub start() { + struct List { + bool b + word w + float f + ^^List next + } + + struct Foo { + byte bb + } + + ^^List l1 = 2000 + ^^List l2 = 3000 + ^^Foo f1 = 4000 + ^^bool bptr = 5000 + + l1^^ = f1^^ + l1^^ = bptr^^ + l1^^ = 4242 + } +}""" + + val errors=ErrorReporterForTests() + compileText(VMTarget(), false, src, outputDir, errors=errors) + errors.errors.size shouldBe 3 + errors.errors[0] shouldContain "doesn't match" + errors.errors[1] shouldContain "assigning to struct instance not supported" + errors.errors[2] shouldContain "assigning to struct instance not supported" + } }) \ No newline at end of file diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 161d853b2..af02c2ae1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -57,10 +57,10 @@ STRUCTS and TYPED POINTERS - DONE: fix _msb/_lsb storage of the split-words pointer-arrays - DONE: what about static initialization of an array of struct pointers? -> impossible right now because the pointer values are not constants. - DONE: make typeForAddressOf() be even more specific about the typed pointers it returns for the address-of operator. -- allow list1^^ = list2^^ (value wise assignment of List structures) by replacing it with a sys.memcopy(list2, list1, sizeof(List)) call. +- DONE: allow list1^^ = list2^^ (value wise assignment of List structures) by replacing it with a sys.memcopy(list2, list1, sizeof(List)) call. - add unit tests for expected AST elements for all syntaxes dealing with pointers, dereference(chain), derefs, and indexing (both as value and assigntargets) -- fix parse error "barray[2]^^" where barray is ^^bool[10] - add unit tests for all changes (pointers and structs) +- fix parse error "barray[2]^^" where barray is ^^bool[10] - try to fix parse error l1^^.s[0] = 4242 (equivalent to l1.s[0]=4242 , which does parse correctly) - try to make sizeof(^^type) parse correctly (or maybe replace it immediately with sys.SIZEOF_POINTER) - 6502 codegen: remove checks in checkForPointerTypesOn6502() diff --git a/examples/test.p8 b/examples/test.p8 index c3b4734b3..8a48c24ae 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,13 +1,9 @@ -%option enable_floats +%import floats %import textio %zeropage basicsafe main { sub start() { - bool @shared b - float @shared f - word @shared w - const long ll = 9999999 struct List { bool b word w @@ -15,60 +11,39 @@ main { ^^List next } - ^^List @shared l1 - ^^float @shared fptr + struct Foo { + byte bb + } - txt.print_ub(sys.SIZEOF_BOOL) + ^^List l1 = 2000 + ^^List l2 = 3000 + ^^Foo f1 = 4000 + + l1.b = true + l1.w = 1111 + l1.f = 11.234 + + l2.b = false + l2.w = 2222 + l2.f = 222.222 + + txt.print_uwhex(l1, true) txt.spc() - txt.print_ub(sys.SIZEOF_WORD) + txt.print_bool(l1.b) txt.spc() - txt.print_ub(sys.SIZEOF_POINTER) + txt.print_w(l1.w) txt.spc() - txt.print_ub(sys.SIZEOF_LONG) - txt.spc() - txt.print_ub(sys.SIZEOF_FLOAT) + txt.print_f(l1.f) txt.nl() - txt.print_ub(sizeof(true)) + l1^^ = l2^^ + txt.print_uwhex(l1, true) txt.spc() - txt.print_ub(sizeof(1234)) + txt.print_bool(l1.b) txt.spc() - txt.print_ub(sizeof(12345678)) + txt.print_w(l1.w) txt.spc() - txt.print_ub(sizeof(9.999)) - txt.nl() - - txt.print_ub(sizeof(b)) - txt.spc() - txt.print_ub(sizeof(w)) - txt.spc() - txt.print_ub(sizeof(ll)) - txt.spc() - txt.print_ub(sizeof(f)) - txt.spc() - txt.print_ub(sizeof(l1)) - txt.spc() - txt.print_ub(sizeof(fptr^^)) - txt.spc() - txt.print_ub(sizeof(l1^^)) - txt.nl() - - txt.print_ub(sizeof(bool)) - txt.spc() - txt.print_ub(sizeof(word)) - txt.spc() - txt.print_ub(sizeof(long)) - txt.spc() - txt.print_ub(sizeof(float)) - txt.spc() - txt.print_ub(sizeof(List)) - txt.spc() - txt.print_ub(sizeof(&w)) - txt.spc() -; txt.print_ub(sizeof(^^float)) ; TODO parse this -; txt.spc() -; txt.print_ub(sizeof(^^List)) ; TODO parse this -; txt.spc() + txt.print_f(l1.f) txt.nl() } }