diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 7fbb8b30f..77adc6392 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -559,9 +559,11 @@ internal class AstChecker(private val program: Program, checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue) } else -> { - err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}") - super.visit(decl) - return + if(decl.type==VarDeclType.CONST) { + err("const declaration needs a compile-time constant initializer value, or range") + super.visit(decl) + return + } } } } diff --git a/compiler/src/prog8/ast/processing/AstVariousTransforms.kt b/compiler/src/prog8/ast/processing/AstVariousTransforms.kt index 3fbba6291..a9658f73e 100644 --- a/compiler/src/prog8/ast/processing/AstVariousTransforms.kt +++ b/compiler/src/prog8/ast/processing/AstVariousTransforms.kt @@ -12,6 +12,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker() override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { if(functionCallStatement.target.nameInSource == listOf("swap")) { + // TODO don't replace swap(), let the code generator figure this all out // if x and y are both just identifiers, do not rewrite (there should be asm generation for that) // otherwise: // rewrite swap(x,y) as follows: diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index 89f8e80d7..5810ad86e 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -71,23 +71,6 @@ internal class StatementReorderer(val program: Program) : AstWalker() { return noModifications } - override fun after(decl: VarDecl, parent: Node): Iterable { - val declValue = decl.value - if(declValue!=null && decl.type== VarDeclType.VAR && decl.datatype in NumericDatatypes) { - val declConstValue = declValue.constValue(program) - if(declConstValue==null) { - // move the vardecl (without value) to the scope and replace this with a regular assignment - decl.value = null - val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position) - val assign = Assignment(target, declValue, decl.position) - return listOf( - IAstModification.ReplaceNode(decl, assign, parent), - IAstModification.InsertFirst(decl, decl.definingScope() as Node) - ) - } - } - return noModifications - } override fun after(whenStatement: WhenStatement, parent: Node): Iterable { val choices = whenStatement.choiceValues(program).sortedBy { diff --git a/compiler/src/prog8/ast/processing/TypecastsAdder.kt b/compiler/src/prog8/ast/processing/TypecastsAdder.kt index 1c4c1136a..ebbf2d01b 100644 --- a/compiler/src/prog8/ast/processing/TypecastsAdder.kt +++ b/compiler/src/prog8/ast/processing/TypecastsAdder.kt @@ -18,6 +18,21 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke private val noModifications = emptyList() + override fun after(decl: VarDecl, parent: Node): Iterable { + val declValue = decl.value + if(decl.type==VarDeclType.VAR && declValue!=null && decl.struct==null) { + val valueDt = declValue.inferType(program) + if(!valueDt.istype(decl.datatype)) { + return listOf(IAstModification.ReplaceNode( + declValue, + TypecastExpression(declValue, decl.datatype, true, declValue.position), + decl + )) + } + } + return noModifications + } + override fun after(expr: BinaryExpression, parent: Node): Iterable { val leftDt = expr.left.inferType(program) val rightDt = expr.right.inferType(program) diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index bfb6eaf78..9c1048359 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -15,7 +15,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E private val noModifications = emptyList() override fun after(decl: VarDecl, parent: Node): Iterable { - if (decl.value == null && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) { + if (decl.value == null && !decl.autogeneratedDontRemove && decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) { // a numeric vardecl without an initial value is initialized with zero. decl.value = decl.zeroElementValue() } @@ -55,7 +55,8 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E } } if (!conflicts) { - val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes } + // move vardecls of the scope into the upper scope. Make sure the order remains the same! + val numericVarsWithValue = decls.filter { it.value != null && it.datatype in NumericDatatypes }.reversed() return numericVarsWithValue.map { val initValue = it.value!! // assume here that value has always been set by now it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt index e7e4b9769..ab517b5f4 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -160,6 +160,6 @@ internal class AsmAssignment(val source: AsmAssignSource, init { if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY)) - require(source.datatype==target.datatype) {"source and target datatype must be identical"} + require(source.datatype.memorySize() == target.datatype.memorySize()) { "source and target datatype must be same storage class" } } } diff --git a/examples/cube3d-gfx.p8 b/examples/cube3d-gfx.p8 index bd1e31fd4..3704f89d5 100644 --- a/examples/cube3d-gfx.p8 +++ b/examples/cube3d-gfx.p8 @@ -1,7 +1,6 @@ %import c64lib %import c64graphics - main { ; vertices @@ -78,11 +77,12 @@ main { const uword screen_width = 320 const ubyte screen_height = 200 + sub draw_lines() { ubyte @zp i for i in len(edgesFrom) -1 downto 0 { ubyte @zp vFrom = edgesFrom[i] - ubyte @zp vTo = edgesTo[i] + ubyte @zp vTo = edgesTo[i] ; TODO need compiler error for double declaration if also declared outside the for loop! word @zp persp1 = 256 + rotatedz[vFrom]/256 word @zp persp2 = 256 + rotatedz[vTo]/256 graphics.line(rotatedx[vFrom] / persp1 + screen_width/2 as uword, diff --git a/examples/test.p8 b/examples/test.p8 index c2e8a5a71..7295c4d5c 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,16 +6,30 @@ main { + struct Color { + ubyte red + ubyte green + ubyte blue + } sub start() { - ubyte ub =9 + ubyte ub = 9 uword yy = 9999 ; this is okay (no 0-initialization generated) but... the next: uword xx = ub ; TODO don't generate xx = 0 assignment if it's initialized with something else... + uword zz - ub++ - xx++ - yy++ + Color purple = [1,2,3] + + uword x1 + uword x2 + + word dx = x2 - x1 as word + + ;ub++ + ;xx++ + ;yy++ + ;zz++ ;asmsub clear_screen (ubyte char @ A, ubyte color @ Y) clobbers(A) { ...} ; TODO dont cause name conflict if we define sub or sub with param 'color' or even a var 'color' later.