diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 6d4c440a4..192100218 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -725,9 +725,9 @@ class VarDecl(val type: VarDeclType, private val declaredDatatype: DataType, val zeropage: Boolean, var arraysize: ArrayIndex?, - val isUnsizedArray: Boolean, val name: String, var value: IExpression?, + val isArray: Boolean, override val position: Position) : IStatement { override lateinit var parent: Node override val expensiveToInline @@ -735,7 +735,7 @@ class VarDecl(val type: VarDeclType, val datatypeErrors = mutableListOf() // don't crash at init time, report them in the AstChecker val datatype = - if (arraysize == null && !isUnsizedArray) declaredDatatype + if (!isArray) declaredDatatype else when (declaredDatatype) { DataType.UBYTE -> DataType.ARRAY_UB DataType.BYTE -> DataType.ARRAY_B @@ -759,7 +759,7 @@ class VarDecl(val type: VarDeclType, val scopedname: String by lazy { makeScopedName(name) } override fun toString(): String { - return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)" + return "VarDecl(name=$name, vartype=$type, datatype=$datatype, array=$isArray, value=$value, pos=$position)" } fun asDefaultValueDecl(parent: Node?): VarDecl { @@ -771,7 +771,7 @@ class VarDecl(val type: VarDeclType, DataType.FLOAT -> LiteralValue(DataType.FLOAT, floatvalue=0.0, position=position) else -> throw FatalAstException("can only set a default value for a numeric type") } - val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, isUnsizedArray, name, constValue, position) + val decl = VarDecl(type, declaredDatatype, zeropage, arraysize, name, constValue, isArray, position) if(parent!=null) decl.linkParents(parent) return decl @@ -2086,9 +2086,9 @@ private fun prog8Parser.StatementContext.toAst() : IStatement { it.datatype().toAst(), it.ZEROPAGE()!=null, it.arrayindex()?.toAst(), - it.ARRAYSIG()!=null, it.identifier().text, null, + it.ARRAYSIG()!=null || it.arrayindex()!=null, it.toPosition()) } @@ -2098,9 +2098,9 @@ private fun prog8Parser.StatementContext.toAst() : IStatement { vd.datatype().toAst(), vd.ZEROPAGE()!=null, vd.arrayindex()?.toAst(), - vd.ARRAYSIG()!=null, vd.identifier().text, it.expression().toAst(), + vd.ARRAYSIG()!=null || vd.arrayindex()!=null, it.toPosition()) } @@ -2111,9 +2111,9 @@ private fun prog8Parser.StatementContext.toAst() : IStatement { vd.datatype().toAst(), vd.ZEROPAGE()!=null, vd.arrayindex()?.toAst(), - vd.ARRAYSIG()!=null, vd.identifier().text, cvarinit.expression().toAst(), + vd.ARRAYSIG()!=null || vd.arrayindex()!=null, cvarinit.toPosition()) } @@ -2124,9 +2124,9 @@ private fun prog8Parser.StatementContext.toAst() : IStatement { vd.datatype().toAst(), vd.ZEROPAGE()!=null, vd.arrayindex()?.toAst(), - vd.ARRAYSIG()!=null, vd.identifier().text, mvarinit.expression().toAst(), + vd.ARRAYSIG()!=null || vd.arrayindex()!=null, mvarinit.toPosition()) } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 0df1d7f83..eb14d4d7d 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -504,7 +504,7 @@ private class AstChecker(private val program: Program, } // ARRAY without size specifier MUST have an iterable initializer value - if(decl.isUnsizedArray) { + if(decl.isArray && decl.arraysize==null) { if(decl.type==VarDeclType.MEMORY) checkResult.add(SyntaxError("memory mapped array must have a size specification", decl.position)) if(decl.value==null) { @@ -546,7 +546,7 @@ private class AstChecker(private val program: Program, } when { decl.value is RangeExpr -> { - if(!decl.isUnsizedArray) + if(decl.arraysize!=null) checkValueTypeAndRange(decl.datatype, decl.arraysize!!, decl.value as RangeExpr) } decl.value is LiteralValue -> { diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 9e04d20ee..e257c536c 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -134,7 +134,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro subroutine.parameters .filter { it.name !in allDefinedNames } .forEach { - val vardecl = VarDecl(VarDeclType.VAR, it.type, false, null, false, it.name, null, subroutine.position) + val vardecl = VarDecl(VarDeclType.VAR, it.type, false, null, it.name, null, false, subroutine.position) vardecl.linkParents(subroutine) subroutine.statements.add(0, vardecl) } @@ -172,7 +172,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first()) if(existing==null) { // create the local scoped for loop variable itself - val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, false, varName, null, forLoop.loopVar.position) + val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, varName, null, false, forLoop.loopVar.position) vardecl.linkParents(forLoop.body) forLoop.body.statements.add(0, vardecl) forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' @@ -184,7 +184,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first()) if(existing==null) { // create loop iteration counter variable (without value, to avoid an assignment) - val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, true, null, false, ForLoop.iteratorLoopcounterVarname, null, forLoop.loopVar.position) + val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, true, null, ForLoop.iteratorLoopcounterVarname, null, false, forLoop.loopVar.position) vardecl.linkParents(forLoop.body) forLoop.body.statements.add(0, vardecl) forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' @@ -232,7 +232,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro if(literalValue.heapId!=null && literalValue.parent !is VarDecl) { // a literal value that's not declared as a variable, which refers to something on the heap. // we need to introduce an auto-generated variable for this to be able to refer to the value! - val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, false, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, literalValue.position) + val variable = VarDecl(VarDeclType.VAR, literalValue.type, false, null, "$autoHeapValuePrefix${literalValue.heapId}", literalValue, false, literalValue.position) anonymousVariablesFromHeap[variable.name] = Pair(literalValue, variable) } return super.process(literalValue) diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index 94103b432..b83cf5760 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -414,7 +414,7 @@ private class VarInitValueAndAddressOfCreator(private val namespace: INameScope) pointerExpr.linkParents(arglist[argparam.first.index].parent) arglist[argparam.first.index] = pointerExpr // add a vardecl so that the autovar can be resolved in later lookups - val variable = VarDecl(VarDeclType.VAR, strvalue.type, false, null, false, autoVarName, strvalue, strvalue.position) + val variable = VarDecl(VarDeclType.VAR, strvalue.type, false, null, autoVarName, strvalue, false, strvalue.position) addVarDecl(strvalue.definingScope(), variable) } } diff --git a/compiler/src/prog8/astvm/VariablesCreator.kt b/compiler/src/prog8/astvm/VariablesCreator.kt index c0ee2bb78..40b7b0975 100644 --- a/compiler/src/prog8/astvm/VariablesCreator.kt +++ b/compiler/src/prog8/astvm/VariablesCreator.kt @@ -13,9 +13,9 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v runtimeVariables.define(program.namespace, Register.Y.name, RuntimeValue(DataType.UBYTE, 0)) val globalpos = Position("<>", 0, 0, 0) - val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.A.name, LiteralValue.optimalInteger(0, globalpos), globalpos) - val vdX = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.X.name, LiteralValue.optimalInteger(255, globalpos), globalpos) - val vdY = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, false, Register.Y.name, LiteralValue.optimalInteger(0, globalpos), globalpos) + val vdA = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, Register.A.name, LiteralValue.optimalInteger(0, globalpos), false, globalpos) + val vdX = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, Register.X.name, LiteralValue.optimalInteger(255, globalpos), false, globalpos) + val vdY = VarDecl(VarDeclType.VAR, DataType.UBYTE, false, null, Register.Y.name, LiteralValue.optimalInteger(0, globalpos), false, globalpos) vdA.linkParents(program.namespace) vdX.linkParents(program.namespace) vdY.linkParents(program.namespace) diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index db0ead88c..f33b73ccb 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -30,8 +30,6 @@ class ConstantFolding(private val program: Program) : IAstProcessor { return decl } - val result = super.process(decl) - if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) { val litval = decl.value as? LiteralValue if(litval!=null && litval.isArray && litval.heapId!=null) @@ -42,6 +40,8 @@ class ConstantFolding(private val program: Program) : IAstProcessor { if (litval != null && litval.type in IntegerDatatypes) { val newValue = LiteralValue(DataType.FLOAT, floatvalue = litval.asNumericValue!!.toDouble(), position = litval.position) decl.value = newValue + optimizationsDone++ + return decl } } DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { @@ -64,12 +64,21 @@ class ConstantFolding(private val program: Program) : IAstProcessor { .toTypedArray(), position=decl.value!!.position) } decl.value!!.linkParents(decl) + optimizationsDone++ + return decl } } if(litval?.type==DataType.FLOAT) errors.add(ExpressionError("arraysize requires only integers here", litval.position)) - if(decl.arraysize==null) + if(decl.arraysize==null) { + // see if we can deduce a proper arraysize + val arrayval = (decl.value as? LiteralValue)?.arrayvalue + if(arrayval!=null) { + decl.arraysize = ArrayIndex(LiteralValue.optimalInteger(arrayval.size, decl.position), decl.position) + optimizationsDone++ + } return decl + } val size = decl.arraysize!!.size() if ((litval==null || !litval.isArray) && size != null && rangeExpr==null) { // arraysize initializer is empty or a single int, and we know the size; create the arraysize. @@ -95,6 +104,8 @@ class ConstantFolding(private val program: Program) : IAstProcessor { } val heapId = program.heap.addIntegerArray(decl.datatype, Array(size) { IntegerOrAddressOf(fillvalue, null) }) decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position) + optimizationsDone++ + return decl } } DataType.ARRAY_F -> { @@ -109,13 +120,18 @@ class ConstantFolding(private val program: Program) : IAstProcessor { else { val heapId = program.heap.addDoublesArray(DoubleArray(size) { fillvalue }) decl.value = LiteralValue(DataType.ARRAY_F, heapId = heapId, position = litval?.position ?: decl.position) + optimizationsDone++ + return decl } } } - else -> return result + else -> { + // nothing to do for this type + } } } - return result + + return super.process(decl) } private fun fixupArrayTypeOnHeap(decl: VarDecl, litval: LiteralValue) { diff --git a/examples/test.p8 b/examples/test.p8 index 7e1ae1684..2a9246e62 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,52 +6,18 @@ ~ main { sub start() { - ; TODO array to heap ubyte[100] arr1 = 1 to 100 - ; TODO array to heap ubyte[100] arr2 = 101 to 200 + ubyte[10] arr1 = [1,2,3,4,5,6,7,8,9,10] + ubyte[] arr2 = [1,2,3,4,5,6,7,8,9,10] + ubyte[] arr1h = 1 to 10 + ubyte[10] arr2h = 1 to 10 - &ubyte m1 = $d020 - &uword mw1 = $c000 - ubyte[] arr1 = [1,2,3,4,5,6,7,8,9,10,11] - ubyte[] arr2 = [11,22,33,44,55,66,77,88,99,100,101] - - word w1 = 1111 - word w2 = 2222 - sum(arr2) - - if_cc goto start - if_cs goto start - if_eq goto start - if_mi goto start - if_ne goto start - if_neg goto start - if_nz goto start - if_pl goto start - if_pos goto start - if_vc goto start - if_vs goto start - if_z goto start - - - m1 = 0 - mw1 = 65535 - - Y = @($d020) - @($d020) = A - - ror(w1) - ror2(w1) - rol(w1) - rol2(w1) - lsr(w1) - lsl(w1) - - swap(w1, w2) - swap(A, Y) - swap(arr1[4], arr2[9]) - ; TODO swap(arr1[4], Y) - ; TODO swap(Y, arr2[9]) - swap(@($d020), @($d021)) +; swap(w1, w2) +; swap(A, Y) +; swap(arr1[4], arr2[9]) +; ; TODO swap(arr1[4], Y) +; ; TODO swap(Y, arr2[9]) +; swap(@($d020), @($d021)) } }