mirror of
https://github.com/irmen/prog8.git
synced 2024-11-23 07:32:10 +00:00
refactoring last of old Ast modification Api
This commit is contained in:
parent
5c771a91f7
commit
75ccac2f2c
@ -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)
|
||||
}
|
||||
|
@ -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<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)
|
||||
|
||||
@ -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<String>, 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)
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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<DirectiveArg>, 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<Statement>,
|
||||
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<Expression>?, // 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)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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<IAstModification>()
|
||||
|
||||
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {
|
||||
@ -35,9 +35,151 @@ internal class ConstantIdentifierReplacer(private val program: Program) : AstWal
|
||||
}
|
||||
}
|
||||
|
||||
override fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
// 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<IAstModification>()
|
||||
|
||||
override fun before(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
|
||||
@ -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<IAstModification> {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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())
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user