From 75ccac2f2cf1e79d2c62608ba80cea71ef79b3e0 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 15 Jun 2020 22:29:08 +0200 Subject: [PATCH] refactoring last of old Ast modification Api --- compiler/src/prog8/ast/AstToplevel.kt | 2 - .../prog8/ast/expressions/AstExpressions.kt | 18 +- .../ast/processing/AstVariousTransforms.kt | 4 +- .../ast/processing/IAstModifyingVisitor.kt | 267 ----------- .../src/prog8/ast/statements/AstStatements.kt | 33 -- compiler/src/prog8/compiler/Main.kt | 2 +- .../optimizer/ConstantFoldingOptimizer.kt | 447 +++++++++--------- compiler/src/prog8/optimizer/Extensions.kt | 25 +- examples/test.p8 | 57 ++- 9 files changed, 264 insertions(+), 591 deletions(-) delete mode 100644 compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt diff --git a/compiler/src/prog8/ast/AstToplevel.kt b/compiler/src/prog8/ast/AstToplevel.kt index 6f52e2a54..2d8e91340 100644 --- a/compiler/src/prog8/ast/AstToplevel.kt +++ b/compiler/src/prog8/ast/AstToplevel.kt @@ -4,7 +4,6 @@ import prog8.ast.base.* import prog8.ast.expressions.Expression import prog8.ast.expressions.IdentifierReference import prog8.ast.processing.AstWalker -import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstVisitor import prog8.ast.statements.* import prog8.functions.BuiltinFunctions @@ -264,7 +263,6 @@ class Module(override val name: String, override fun toString() = "Module(name=$name, pos=$position, lib=$isLibraryModule)" - fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index ee834b104..b4d507d19 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -4,7 +4,6 @@ import prog8.ast.* import prog8.ast.antlr.escape import prog8.ast.base.* import prog8.ast.processing.AstWalker -import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstVisitor import prog8.ast.statements.* import prog8.compiler.target.CompilationTarget @@ -20,7 +19,6 @@ val associativeOperators = setOf("+", "*", "&", "|", "^", "or", "and", "xor", "= sealed class Expression: Node { abstract fun constValue(program: Program): NumericLiteralValue? - abstract fun accept(visitor: IAstModifyingVisitor): Expression abstract fun accept(visitor: IAstVisitor) abstract fun accept(visitor: AstWalker, parent: Node) abstract fun referencesIdentifiers(vararg name: String): Boolean // todo: remove this and add identifier usage tracking into CallGraph instead @@ -65,7 +63,6 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -123,7 +120,6 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex // binary expression should actually have been optimized away into a single value, before const value was requested... override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -237,7 +233,6 @@ class ArrayIndexedExpression(var identifier: IdentifierReference, } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -274,7 +269,6 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -309,7 +303,6 @@ data class AddressOf(var identifier: IdentifierReference, override val position: override fun constValue(program: Program): NumericLiteralValue? = null override fun referencesIdentifiers(vararg name: String) = false override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.UWORD) - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) } @@ -328,7 +321,6 @@ class DirectMemoryRead(var addressExpression: Expression, override val position: replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -388,7 +380,6 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed override fun referencesIdentifiers(vararg name: String) = false override fun constValue(program: Program) = this - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -479,7 +470,6 @@ class StructLiteralValue(var values: List, } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -510,7 +500,6 @@ class StringLiteralValue(val value: String, override fun referencesIdentifiers(vararg name: String) = false override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -546,12 +535,11 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be override fun referencesIdentifiers(vararg name: String) = value.any { it.referencesIdentifiers(*name) } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun toString(): String = "$value" - override fun inferType(program: Program): InferredTypes.InferredType = if(type.isUnknown) type else guessDatatype(program) + override fun inferType(program: Program): InferredTypes.InferredType = if(type.isKnown) type else guessDatatype(program) operator fun compareTo(other: ArrayLiteralValue): Int = throw ExpressionError("cannot order compare arrays", position) override fun hashCode(): Int = Objects.hash(value, type) @@ -640,7 +628,6 @@ class RangeExpr(var from: Expression, } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -720,7 +707,6 @@ class RegisterExpr(val register: Register, override val position: Position) : Ex } override fun constValue(program: Program): NumericLiteralValue? = null - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -768,7 +754,6 @@ data class IdentifierReference(val nameInSource: List, override val posi return "IdentifierRef($nameInSource)" } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) @@ -854,7 +839,6 @@ class FunctionCall(override var target: IdentifierReference, return "FunctionCall(target=$target, pos=$position)" } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) diff --git a/compiler/src/prog8/ast/processing/AstVariousTransforms.kt b/compiler/src/prog8/ast/processing/AstVariousTransforms.kt index 0c3fbacdc..1c5d0ef67 100644 --- a/compiler/src/prog8/ast/processing/AstVariousTransforms.kt +++ b/compiler/src/prog8/ast/processing/AstVariousTransforms.kt @@ -95,7 +95,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker() val arrayDt = array.type if(!arrayDt.istype(vardecl.datatype)) { val cast = array.cast(vardecl.datatype) - if (cast != null) + if (cast != null && cast!=array) return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl)) } } else { @@ -103,7 +103,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker() if(arrayDt.isKnown) { // this array literal is part of an expression, turn it into an identifier reference val litval2 = array.cast(arrayDt.typeOrElse(DataType.STRUCT)) - if(litval2!=null) { + if(litval2!=null && litval2!=array) { val vardecl = VarDecl.createAuto(litval2) val identifier = IdentifierReference(listOf(vardecl.name), vardecl.position) return listOf( diff --git a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt b/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt deleted file mode 100644 index b51aa54c4..000000000 --- a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt +++ /dev/null @@ -1,267 +0,0 @@ -package prog8.ast.processing - -import prog8.ast.Module -import prog8.ast.Program -import prog8.ast.base.FatalAstException -import prog8.ast.expressions.* -import prog8.ast.statements.* - -// TODO replace all occurrences of this with AstWalker (currently only ConstantFoldingOptimizer remaining) -interface IAstModifyingVisitor { - fun visit(program: Program) { - program.modules.forEach { it.accept(this) } - } - - fun visit(module: Module) { - module.statements = module.statements.map { it.accept(this) }.toMutableList() - } - - fun visit(expr: PrefixExpression): Expression { - expr.expression = expr.expression.accept(this) - return expr - } - - fun visit(expr: BinaryExpression): Expression { - expr.left = expr.left.accept(this) - expr.right = expr.right.accept(this) - return expr - } - - fun visit(directive: Directive): Statement { - return directive - } - - fun visit(block: Block): Statement { - block.statements = block.statements.map { it.accept(this) }.toMutableList() - return block - } - - fun visit(decl: VarDecl): Statement { - decl.value = decl.value?.accept(this) - decl.arraysize?.accept(this) - return decl - } - - fun visit(subroutine: Subroutine): Statement { - subroutine.statements = subroutine.statements.map { it.accept(this) }.toMutableList() - return subroutine - } - - fun visit(functionCall: FunctionCall): Expression { - val newtarget = functionCall.target.accept(this) - if(newtarget is IdentifierReference) - functionCall.target = newtarget - else - throw FatalAstException("cannot change class of function call target") - functionCall.args = functionCall.args.map { it.accept(this) }.toMutableList() - return functionCall - } - - fun visit(functionCallStatement: FunctionCallStatement): Statement { - val newtarget = functionCallStatement.target.accept(this) - if(newtarget is IdentifierReference) - functionCallStatement.target = newtarget - else - throw FatalAstException("cannot change class of function call target") - functionCallStatement.args = functionCallStatement.args.map { it.accept(this) }.toMutableList() - return functionCallStatement - } - - fun visit(identifier: IdentifierReference): Expression { - // note: this is an identifier that is used in an expression. - // other identifiers are simply part of the other statements (such as jumps, subroutine defs etc) - return identifier - } - - fun visit(jump: Jump): Statement { - if(jump.identifier!=null) { - val ident = jump.identifier.accept(this) - if(ident is IdentifierReference && ident!==jump.identifier) { - return Jump(null, ident, null, jump.position) - } - } - return jump - } - - fun visit(ifStatement: IfStatement): Statement { - ifStatement.condition = ifStatement.condition.accept(this) - ifStatement.truepart = ifStatement.truepart.accept(this) as AnonymousScope - ifStatement.elsepart = ifStatement.elsepart.accept(this) as AnonymousScope - return ifStatement - } - - fun visit(branchStatement: BranchStatement): Statement { - branchStatement.truepart = branchStatement.truepart.accept(this) as AnonymousScope - branchStatement.elsepart = branchStatement.elsepart.accept(this) as AnonymousScope - return branchStatement - } - - fun visit(range: RangeExpr): Expression { - range.from = range.from.accept(this) - range.to = range.to.accept(this) - range.step = range.step.accept(this) - return range - } - - fun visit(label: Label): Statement { - return label - } - - fun visit(literalValue: NumericLiteralValue): NumericLiteralValue { - return literalValue - } - - fun visit(stringLiteral: StringLiteralValue): Expression { - return stringLiteral - } - - fun visit(arrayLiteral: ArrayLiteralValue): Expression { - for(av in arrayLiteral.value.withIndex()) { - val newvalue = av.value.accept(this) - arrayLiteral.value[av.index] = newvalue - } - return arrayLiteral - } - - fun visit(assignment: Assignment): Statement { - assignment.target = assignment.target.accept(this) - assignment.value = assignment.value.accept(this) - return assignment - } - - fun visit(postIncrDecr: PostIncrDecr): Statement { - postIncrDecr.target = postIncrDecr.target.accept(this) - return postIncrDecr - } - - fun visit(contStmt: Continue): Statement { - return contStmt - } - - fun visit(breakStmt: Break): Statement { - return breakStmt - } - - fun visit(forLoop: ForLoop): Statement { - when(val newloopvar = forLoop.loopVar?.accept(this)) { - is IdentifierReference -> forLoop.loopVar = newloopvar - null -> forLoop.loopVar = null - else -> throw FatalAstException("can't change class of loopvar") - } - forLoop.iterable = forLoop.iterable.accept(this) - forLoop.body = forLoop.body.accept(this) as AnonymousScope - return forLoop - } - - fun visit(whileLoop: WhileLoop): Statement { - whileLoop.condition = whileLoop.condition.accept(this) - whileLoop.body = whileLoop.body.accept(this) as AnonymousScope - return whileLoop - } - - fun visit(foreverLoop: ForeverLoop): Statement { - foreverLoop.body = foreverLoop.body.accept(this) as AnonymousScope - return foreverLoop - } - - fun visit(repeatLoop: RepeatLoop): Statement { - repeatLoop.untilCondition = repeatLoop.untilCondition.accept(this) - repeatLoop.body = repeatLoop.body.accept(this) as AnonymousScope - return repeatLoop - } - - fun visit(returnStmt: Return): Statement { - returnStmt.value = returnStmt.value?.accept(this) - return returnStmt - } - - fun visit(arrayIndexedExpression: ArrayIndexedExpression): ArrayIndexedExpression { - val ident = arrayIndexedExpression.identifier.accept(this) - if(ident is IdentifierReference) - arrayIndexedExpression.identifier = ident - arrayIndexedExpression.arrayspec.accept(this) - return arrayIndexedExpression - } - - fun visit(assignTarget: AssignTarget): AssignTarget { - when (val ident = assignTarget.identifier?.accept(this)) { - is IdentifierReference -> assignTarget.identifier = ident - null -> assignTarget.identifier = null - else -> throw FatalAstException("can't change class of assign target identifier") - } - assignTarget.arrayindexed = assignTarget.arrayindexed?.accept(this) - assignTarget.memoryAddress?.let { visit(it) } - return assignTarget - } - - fun visit(scope: AnonymousScope): Statement { - scope.statements = scope.statements.map { it.accept(this) }.toMutableList() - return scope - } - - fun visit(typecast: TypecastExpression): Expression { - typecast.expression = typecast.expression.accept(this) - return typecast - } - - fun visit(memread: DirectMemoryRead): Expression { - memread.addressExpression = memread.addressExpression.accept(this) - return memread - } - - fun visit(memwrite: DirectMemoryWrite) { - memwrite.addressExpression = memwrite.addressExpression.accept(this) - } - - fun visit(addressOf: AddressOf): Expression { - val ident = addressOf.identifier.accept(this) - if(ident is IdentifierReference) - addressOf.identifier = ident - else - throw FatalAstException("can't change class of addressof identifier") - return addressOf - } - - fun visit(inlineAssembly: InlineAssembly): Statement { - return inlineAssembly - } - - fun visit(registerExpr: RegisterExpr): Expression { - return registerExpr - } - - fun visit(builtinFunctionStatementPlaceholder: BuiltinFunctionStatementPlaceholder): Statement { - return builtinFunctionStatementPlaceholder - } - - fun visit(nopStatement: NopStatement): Statement { - return nopStatement - } - - fun visit(whenStatement: WhenStatement): Statement { - whenStatement.condition = whenStatement.condition.accept(this) - whenStatement.choices.forEach { it.accept(this) } - return whenStatement - } - - fun visit(whenChoice: WhenChoice) { - whenChoice.values = whenChoice.values?.map { it.accept(this) } - val stmt = whenChoice.statements.accept(this) - if(stmt is AnonymousScope) - whenChoice.statements = stmt - else { - whenChoice.statements = AnonymousScope(mutableListOf(stmt), stmt.position) - whenChoice.statements.linkParents(whenChoice) - } - } - - fun visit(structDecl: StructDecl): Statement { - structDecl.statements = structDecl.statements.map{ it.accept(this) }.toMutableList() - return structDecl - } - - fun visit(structLv: StructLiteralValue): Expression { - structLv.values = structLv.values.map { it.accept(this) } - return structLv - } -} diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index db5675223..22e81c2e9 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -4,12 +4,10 @@ import prog8.ast.* import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.processing.AstWalker -import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstVisitor sealed class Statement : Node { - abstract fun accept(visitor: IAstModifyingVisitor) : Statement abstract fun accept(visitor: IAstVisitor) abstract fun accept(visitor: AstWalker, parent: Node) @@ -44,7 +42,6 @@ sealed class Statement : Node { class BuiltinFunctionStatementPlaceholder(val name: String, override val position: Position) : Statement() { override var parent: Node = ParentSentinel override fun linkParents(parent: Node) {} - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun definingScope(): INameScope = BuiltinFunctionScopePlaceholder @@ -77,7 +74,6 @@ class Block(override val name: String, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -98,7 +94,6 @@ data class Directive(val directive: String, val args: List, overri } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -121,7 +116,6 @@ data class Label(val name: String, override val position: Position) : Statement( } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -145,7 +139,6 @@ open class Return(var value: Expression?, override val position: Position) : Sta replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -155,7 +148,6 @@ open class Return(var value: Expression?, override val position: Position) : Sta } class ReturnFromIrq(override val position: Position) : Return(null, position) { - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun toString(): String { @@ -173,7 +165,6 @@ class Continue(override val position: Position) : Statement() { } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -187,7 +178,6 @@ class Break(override val position: Position) : Statement() { } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -281,7 +271,6 @@ open class VarDecl(val type: VarDeclType, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -338,9 +327,6 @@ class ArrayIndex(var index: Expression, override val position: Position) : Node } } - fun accept(visitor: IAstModifyingVisitor) { - index = index.accept(visitor) - } fun accept(visitor: IAstVisitor) = index.accept(visitor) fun accept(visitor: AstWalker, parent: Node) = index.accept(visitor, this) @@ -371,7 +357,6 @@ open class Assignment(var target: AssignTarget, var aug_op : String?, var value: replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -427,7 +412,6 @@ data class AssignTarget(val register: Register?, replacement.parent = this } - fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -538,7 +522,6 @@ class PostIncrDecr(var target: AssignTarget, val operator: String, override val replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -560,7 +543,6 @@ class Jump(val address: Int?, } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -593,7 +575,6 @@ class FunctionCallStatement(override var target: IdentifierReference, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -611,7 +592,6 @@ class InlineAssembly(val assembly: String, override val position: Position) : St } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -644,7 +624,6 @@ class AnonymousScope(override var statements: MutableList, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -658,7 +637,6 @@ class NopStatement(override val position: Position): Statement() { } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -708,7 +686,6 @@ class Subroutine(override val name: String, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -765,7 +742,6 @@ class IfStatement(var condition: Expression, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -794,7 +770,6 @@ class BranchStatement(var condition: BranchCondition, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -825,7 +800,6 @@ class ForLoop(val loopRegister: Register?, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -861,7 +835,6 @@ class WhileLoop(var condition: Expression, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -881,7 +854,6 @@ class ForeverLoop(var body: AnonymousScope, override val position: Position) : S replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -907,7 +879,6 @@ class RepeatLoop(var body: AnonymousScope, replacement.parent = this } - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -952,7 +923,6 @@ class WhenStatement(var condition: Expression, } override fun accept(visitor: IAstVisitor) = visitor.visit(this) - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -978,7 +948,6 @@ class WhenChoice(var values: List?, // if null, this is t } fun accept(visitor: IAstVisitor) = visitor.visit(this) - fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -1006,7 +975,6 @@ class StructDecl(override val name: String, get() = this.statements.size override fun accept(visitor: IAstVisitor) = visitor.visit(this) - override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) fun nameOfFirstMember() = (statements.first() as VarDecl).name @@ -1031,6 +999,5 @@ class DirectMemoryWrite(var addressExpression: Expression, override val position } fun accept(visitor: IAstVisitor) = visitor.visit(this) - fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 651399b41..60cf1205b 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -193,7 +193,7 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir: programAst.processAstBeforeAsmGeneration(errors) errors.handle() - // printAst(programAst) + printAst(programAst) // TODO weg val assembly = CompilationTarget.asmGenerator( programAst, diff --git a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 13126549a..2c188864c 100644 --- a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -6,14 +6,14 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.processing.AstWalker import prog8.ast.processing.IAstModification -import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.statements.* import prog8.compiler.target.CompilationTarget -// First thing to do is replace all constant identifiers with their actual value. -// this is needed because further constant optimizations depend on this. -internal class ConstantIdentifierReplacer(private val program: Program) : AstWalker() { +// First thing to do is replace all constant identifiers with their actual value, +// and the array var initializer values and sizes. +// This is needed because further constant optimizations depend on those. +internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter) : AstWalker() { private val noModifications = emptyList() override fun after(identifier: IdentifierReference, parent: Node): Iterable { @@ -35,9 +35,151 @@ internal class ConstantIdentifierReplacer(private val program: Program) : AstWal } } + override fun before(decl: VarDecl, parent: Node): Iterable { + // the initializer value can't refer to the variable itself (recursive definition) + // TODO: use call graph for this? + if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) { + errors.err("recursive var declaration", decl.position) + return noModifications + } + + if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) { + if(decl.isArray){ + if(decl.arraysize==null) { + // for arrays that have no size specifier (or a non-constant one) attempt to deduce the size + val arrayval = decl.value as? ArrayLiteralValue + if(arrayval!=null) { + return listOf(IAstModification.SetExpression( + { decl.arraysize = ArrayIndex(it, decl.position) }, + NumericLiteralValue.optimalInteger(arrayval.value.size, decl.position), + decl + )) + } + } + else if(decl.arraysize?.size()==null) { + val size = decl.arraysize!!.index.constValue(program) + if(size!=null) { + return listOf(IAstModification.SetExpression( + { decl.arraysize = ArrayIndex(it, decl.position) }, + size, decl + )) + } + } + } + + when(decl.datatype) { + DataType.FLOAT -> { + // vardecl: for scalar float vars, promote constant integer initialization values to floats + val litval = decl.value as? NumericLiteralValue + if (litval!=null && litval.type in IntegerDatatypes) { + val newValue = NumericLiteralValue(DataType.FLOAT, litval.number.toDouble(), litval.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { + val numericLv = decl.value as? NumericLiteralValue + val rangeExpr = decl.value as? RangeExpr + if(rangeExpr!=null) { + // convert the initializer range expression to an actual array + val declArraySize = decl.arraysize?.size() + if(declArraySize!=null && declArraySize!=rangeExpr.size()) + errors.err("range expression size doesn't match declared array size", decl.value?.position!!) + val constRange = rangeExpr.toConstantIntegerRange() + if(constRange!=null) { + val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE) + val newValue = if(eltType in ByteDatatypes) { + ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), + constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + } else { + ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), + constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + } + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + if(numericLv!=null && numericLv.type==DataType.FLOAT) + errors.err("arraysize requires only integers here", numericLv.position) + val size = decl.arraysize?.size() ?: return noModifications + if (rangeExpr==null && numericLv!=null) { + // arraysize initializer is empty or a single int, and we know the size; create the arraysize. + val fillvalue = numericLv.number.toInt() + when(decl.datatype){ + DataType.ARRAY_UB -> { + if(fillvalue !in 0..255) + errors.err("ubyte value overflow", numericLv.position) + } + DataType.ARRAY_B -> { + if(fillvalue !in -128..127) + errors.err("byte value overflow", numericLv.position) + } + DataType.ARRAY_UW -> { + if(fillvalue !in 0..65535) + errors.err("uword value overflow", numericLv.position) + } + DataType.ARRAY_W -> { + if(fillvalue !in -32768..32767) + errors.err("word value overflow", numericLv.position) + } + else -> {} + } + // create the array itself, filled with the fillvalue. + val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayElementTypes.getValue(decl.datatype), it, numericLv.position) as Expression}.toTypedArray() + val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) + } + } + DataType.ARRAY_F -> { + val size = decl.arraysize?.size() ?: return noModifications + val litval = decl.value as? NumericLiteralValue + val rangeExpr = decl.value as? RangeExpr + if(rangeExpr!=null) { + // convert the initializer range expression to an actual array of floats + val declArraySize = decl.arraysize?.size() + if(declArraySize!=null && declArraySize!=rangeExpr.size()) + errors.err("range expression size doesn't match declared array size", decl.value?.position!!) + val constRange = rangeExpr.toConstantIntegerRange() + if(constRange!=null) { + val newValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), + constRange.map { NumericLiteralValue(DataType.FLOAT, it.toDouble(), decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, newValue, decl)) + } + } + if(rangeExpr==null && litval!=null) { + // arraysize initializer is a single int, and we know the size. + val fillvalue = litval.number.toDouble() + if (fillvalue < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.machine.FLOAT_MAX_POSITIVE) + errors.err("float value overflow", litval.position) + else { + // create the array itself, filled with the fillvalue. + val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray() + val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = litval.position) + return listOf(IAstModification.ReplaceNode(decl.value!!, refValue, decl)) + } + } + } + else -> { + // nothing to do for this type + // this includes strings and structs + } + } + } + + val declValue = decl.value + if(declValue!=null && decl.type==VarDeclType.VAR + && declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) { + // cast the numeric literal to the appropriate datatype of the variable + return listOf(IAstModification.ReplaceNode(decl.value!!, declValue.cast(decl.datatype), decl)) + } + + return noModifications + } } -internal class ConstantFoldingOptimizer2(private val program: Program, private val errors: ErrorReporter) : AstWalker() { + +internal class ConstantFoldingOptimizer(private val program: Program, private val errors: ErrorReporter) : AstWalker() { private val noModifications = emptyList() override fun before(memread: DirectMemoryRead, parent: Node): Iterable { @@ -150,9 +292,8 @@ internal class ConstantFoldingOptimizer2(private val program: Program, private v val arrayDt = array.guessDatatype(program) if(arrayDt.isKnown) { val newArray = array.cast(arrayDt.typeOrElse(DataType.STRUCT)) - if(newArray!=null && newArray != array) { + if(newArray!=null && newArray != array) return listOf(IAstModification.ReplaceNode(array, newArray, parent)) - } } return noModifications @@ -167,6 +308,69 @@ internal class ConstantFoldingOptimizer2(private val program: Program, private v noModifications } + override fun after(forLoop: ForLoop, parent: Node): Iterable { + fun adjustRangeDt(rangeFrom: NumericLiteralValue, targetDt: DataType, rangeTo: NumericLiteralValue, stepLiteral: NumericLiteralValue?, range: RangeExpr): RangeExpr { + val newFrom: NumericLiteralValue + val newTo: NumericLiteralValue + try { + newFrom = rangeFrom.cast(targetDt) + newTo = rangeTo.cast(targetDt) + } catch (x: ExpressionError) { + return range + } + val newStep: Expression = try { + stepLiteral?.cast(targetDt)?: range.step + } catch(ee: ExpressionError) { + range.step + } + return RangeExpr(newFrom, newTo, newStep, range.position) + } + + // adjust the datatype of a range expression in for loops to the loop variable. + val iterableRange = forLoop.iterable as? RangeExpr ?: return noModifications + val rangeFrom = iterableRange.from as? NumericLiteralValue + val rangeTo = iterableRange.to as? NumericLiteralValue + if(rangeFrom==null || rangeTo==null) return noModifications + + val loopvar = forLoop.loopVar?.targetVarDecl(program.namespace) + if(loopvar!=null) { + val stepLiteral = iterableRange.step as? NumericLiteralValue + when(loopvar.datatype) { + DataType.UBYTE -> { + if(rangeFrom.type!= DataType.UBYTE) { + // attempt to translate the iterable into ubyte values + val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) + } + } + DataType.BYTE -> { + if(rangeFrom.type!= DataType.BYTE) { + // attempt to translate the iterable into byte values + val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) + } + } + DataType.UWORD -> { + if(rangeFrom.type!= DataType.UWORD) { + // attempt to translate the iterable into uword values + val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) + } + } + DataType.WORD -> { + if(rangeFrom.type!= DataType.WORD) { + // attempt to translate the iterable into word values + val newIter = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) + return listOf(IAstModification.ReplaceNode(forLoop.iterable, newIter, forLoop)) + } + } + else -> throw FatalAstException("invalid loopvar datatype $loopvar") + } + } + + return noModifications + } + private class ShuffleOperands(val expr: BinaryExpression, val exprOperator: String?, val subExpr: BinaryExpression, @@ -377,233 +581,4 @@ internal class ConstantFoldingOptimizer2(private val program: Program, private v } } - // TODO conversion from below -} - -// ----------------------------------------------------------- - -internal class ConstantFoldingOptimizer(private val program: Program, private val errors: ErrorReporter) : IAstModifyingVisitor { - var optimizationsDone: Int = 0 - - override fun visit(decl: VarDecl): Statement { - // the initializer value can't refer to the variable itself (recursive definition) - // TODO: use call graph for this? - if(decl.value?.referencesIdentifiers(decl.name) == true || decl.arraysize?.index?.referencesIdentifiers(decl.name) == true) { - errors.err("recursive var declaration", decl.position) - return decl - } - - if(decl.type==VarDeclType.CONST || decl.type==VarDeclType.VAR) { - if(decl.isArray){ - if(decl.arraysize==null) { - // for arrays that have no size specifier (or a non-constant one) attempt to deduce the size - val arrayval = decl.value as? ArrayLiteralValue - if(arrayval!=null) { - decl.arraysize = ArrayIndex(NumericLiteralValue.optimalInteger(arrayval.value.size, decl.position), decl.position) - optimizationsDone++ - } - } - else if(decl.arraysize?.size()==null) { - val size = decl.arraysize!!.index.accept(this) - if(size is NumericLiteralValue) { - decl.arraysize = ArrayIndex(size, decl.position) - optimizationsDone++ - } - } - } - - when(decl.datatype) { - DataType.FLOAT -> { - // vardecl: for scalar float vars, promote constant integer initialization values to floats - val litval = decl.value as? NumericLiteralValue - if (litval!=null && litval.type in IntegerDatatypes) { - val newValue = NumericLiteralValue(DataType.FLOAT, litval.number.toDouble(), litval.position) - decl.value = newValue - optimizationsDone++ - return super.visit(decl) - } - } - DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { - val numericLv = decl.value as? NumericLiteralValue - val rangeExpr = decl.value as? RangeExpr - if(rangeExpr!=null) { - // convert the initializer range expression to an actual array - val declArraySize = decl.arraysize?.size() - if(declArraySize!=null && declArraySize!=rangeExpr.size()) - errors.err("range expression size doesn't match declared array size", decl.value?.position!!) - val constRange = rangeExpr.toConstantIntegerRange() - if(constRange!=null) { - val eltType = rangeExpr.inferType(program).typeOrElse(DataType.UBYTE) - if(eltType in ByteDatatypes) { - decl.value = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), - position = decl.value!!.position) - } else { - decl.value = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), - constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(), - position = decl.value!!.position) - } - decl.value!!.linkParents(decl) - optimizationsDone++ - return super.visit(decl) - } - } - if(numericLv!=null && numericLv.type== DataType.FLOAT) - errors.err("arraysize requires only integers here", numericLv.position) - val size = decl.arraysize?.size() ?: return decl - if (rangeExpr==null && numericLv!=null) { - // arraysize initializer is empty or a single int, and we know the size; create the arraysize. - val fillvalue = numericLv.number.toInt() - when(decl.datatype){ - DataType.ARRAY_UB -> { - if(fillvalue !in 0..255) - errors.err("ubyte value overflow", numericLv.position) - } - DataType.ARRAY_B -> { - if(fillvalue !in -128..127) - errors.err("byte value overflow", numericLv.position) - } - DataType.ARRAY_UW -> { - if(fillvalue !in 0..65535) - errors.err("uword value overflow", numericLv.position) - } - DataType.ARRAY_W -> { - if(fillvalue !in -32768..32767) - errors.err("word value overflow", numericLv.position) - } - else -> {} - } - // create the array itself, filled with the fillvalue. - val array = Array(size) {fillvalue}.map { NumericLiteralValue(ArrayElementTypes.getValue(decl.datatype), it, numericLv.position) as Expression}.toTypedArray() - val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), array, position = numericLv.position) - decl.value = refValue - refValue.parent=decl - optimizationsDone++ - return super.visit(decl) - } - } - DataType.ARRAY_F -> { - val size = decl.arraysize?.size() ?: return decl - val litval = decl.value as? NumericLiteralValue - if(litval==null) { - // there's no initialization value, but the size is known, so we're ok. - return super.visit(decl) - } else { - // arraysize initializer is a single int, and we know the size. - val fillvalue = litval.number.toDouble() - if (fillvalue < CompilationTarget.machine.FLOAT_MAX_NEGATIVE || fillvalue > CompilationTarget.machine.FLOAT_MAX_POSITIVE) - errors.err("float value overflow", litval.position) - else { - // create the array itself, filled with the fillvalue. - val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray() - val refValue = ArrayLiteralValue(InferredTypes.InferredType.known(DataType.ARRAY_F), array, position = litval.position) - decl.value = refValue - refValue.parent=decl - optimizationsDone++ - return super.visit(decl) - } - } - } - else -> { - // nothing to do for this type - // this includes strings and structs - } - } - } - - val declValue = decl.value - if(declValue!=null && decl.type==VarDeclType.VAR - && declValue is NumericLiteralValue && !declValue.inferType(program).istype(decl.datatype)) { - // cast the numeric literal to the appropriate datatype of the variable - decl.value = declValue.cast(decl.datatype) - } - - return super.visit(decl) - } - - override fun visit(forLoop: ForLoop): Statement { - - fun adjustRangeDt(rangeFrom: NumericLiteralValue, targetDt: DataType, rangeTo: NumericLiteralValue, stepLiteral: NumericLiteralValue?, range: RangeExpr): RangeExpr { - val newFrom: NumericLiteralValue - val newTo: NumericLiteralValue - try { - newFrom = rangeFrom.cast(targetDt) - newTo = rangeTo.cast(targetDt) - } catch (x: ExpressionError) { - return range - } - val newStep: Expression = try { - stepLiteral?.cast(targetDt)?: range.step - } catch(ee: ExpressionError) { - range.step - } - return RangeExpr(newFrom, newTo, newStep, range.position) - } - - val forLoop2 = super.visit(forLoop) as ForLoop - - // check if we need to adjust an array literal to the loop variable's datatype - val array = forLoop2.iterable as? ArrayLiteralValue - if(array!=null) { - val loopvarDt: DataType = when { - forLoop.loopVar!=null -> forLoop.loopVar!!.inferType(program).typeOrElse(DataType.UBYTE) - forLoop.loopRegister!=null -> DataType.UBYTE - else -> throw FatalAstException("weird for loop") - } - - val arrayType = when(loopvarDt) { - DataType.UBYTE -> DataType.ARRAY_UB - DataType.BYTE -> DataType.ARRAY_B - DataType.UWORD -> DataType.ARRAY_UW - DataType.WORD -> DataType.ARRAY_W - DataType.FLOAT -> DataType.ARRAY_F - else -> throw FatalAstException("invalid array elt type") - } - val array2 = array.cast(arrayType) - if(array2!=null && array2!==array) { - forLoop2.iterable = array2 - array2.linkParents(forLoop2) - } - } - - // adjust the datatype of a range expression in for loops to the loop variable. - val iterableRange = forLoop2.iterable as? RangeExpr ?: return forLoop2 - val rangeFrom = iterableRange.from as? NumericLiteralValue - val rangeTo = iterableRange.to as? NumericLiteralValue - if(rangeFrom==null || rangeTo==null) return forLoop2 - - val loopvar = forLoop2.loopVar?.targetVarDecl(program.namespace) - if(loopvar!=null) { - val stepLiteral = iterableRange.step as? NumericLiteralValue - when(loopvar.datatype) { - DataType.UBYTE -> { - if(rangeFrom.type!= DataType.UBYTE) { - // attempt to translate the iterable into ubyte values - forLoop2.iterable = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) - } - } - DataType.BYTE -> { - if(rangeFrom.type!= DataType.BYTE) { - // attempt to translate the iterable into byte values - forLoop2.iterable = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) - } - } - DataType.UWORD -> { - if(rangeFrom.type!= DataType.UWORD) { - // attempt to translate the iterable into uword values - forLoop2.iterable = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) - } - } - DataType.WORD -> { - if(rangeFrom.type!= DataType.WORD) { - // attempt to translate the iterable into word values - forLoop2.iterable = adjustRangeDt(rangeFrom, loopvar.datatype, rangeTo, stepLiteral, iterableRange) - } - } - else -> throw FatalAstException("invalid loopvar datatype $loopvar") - } - } - return forLoop2 - } - } diff --git a/compiler/src/prog8/optimizer/Extensions.kt b/compiler/src/prog8/optimizer/Extensions.kt index 76ae42afb..7f151a36f 100644 --- a/compiler/src/prog8/optimizer/Extensions.kt +++ b/compiler/src/prog8/optimizer/Extensions.kt @@ -5,22 +5,21 @@ import prog8.ast.base.ErrorReporter internal fun Program.constantFold(errors: ErrorReporter) { - val replacer = ConstantIdentifierReplacer(this) + val replacer = ConstantIdentifierReplacer(this, errors) replacer.visit(this) - replacer.applyModifications() + if(errors.isEmpty()) { + replacer.applyModifications() - val optimizer_old = ConstantFoldingOptimizer(this, errors) - optimizer_old.visit(this) - - while(errors.isEmpty() && optimizer_old.optimizationsDone>0) { - optimizer_old.optimizationsDone = 0 - optimizer_old.visit(this) - } - - val optimizer = ConstantFoldingOptimizer2(this, errors) - optimizer.visit(this) - while(errors.isEmpty() && optimizer.applyModifications() > 0) { + val optimizer = ConstantFoldingOptimizer(this, errors) optimizer.visit(this) + while (errors.isEmpty() && optimizer.applyModifications() > 0) { + optimizer.visit(this) + } + + if(errors.isEmpty()) { + replacer.visit(this) + replacer.applyModifications() + } } if(errors.isEmpty()) diff --git a/examples/test.p8 b/examples/test.p8 index adcbd883d..3fabb5a07 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -27,29 +27,46 @@ blabla: } sub start() { - ubyte[] array = [1, 1+1, -33, -2.222] + ubyte[] a1 = 3 to 20 - const ubyte q = 123 - byte bbb +; ubyte[18] a2 = 3 to 20 +; float[18] floats2 = 3 to 20 +; ubyte[11] bytes = 22 +; float[11] floats = 3.33 +; +; float[] array = [1, 1+1, -33] +; byte[] array2 = [1, 1+1, -33, -2] - str sss = "zzz" - str x = "zxcvzxcv" + ; float[] array2 = 42 ; TODO nice error + ;ubyte[len(array)] bytesE = 22 ; TODO fix error + ;float[len(array2)] floatsE = 3.33 ; TODO fix error - float ff = 1234.44 + 99.0 - float ff2 = -3.3333 - ff=ff2*2 - A = 123+22+11 - bbb = -99 - - A = q - A = func(1+q) - func(1+q) - - Y=99 - A = func2(1+q) - func2(1+q) - - x = @(&sss) +; const ubyte q = 123 +; byte bbb +; float ff +; +; A = bytes[1] +; ff = array[1] +; A = len(array) +; A = len(array2) +; str sss = "zzz" +; str x = "zxcvzxcv" +; +; ff = 1234.44 + 99.0 +; float ff2 = -3.3333 +; ff=ff2*2 +; A = 123+22+11 +; bbb = -99 +; +; A = q +; A = func(1+q) +; func(1+q) +; +; Y=99 +; A = func2(1+q) +; func2(1+q) +; +; x = @(&sss) } }