diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index ebf1e50b0..cac7b7bfe 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -21,6 +21,7 @@ object ParentSentinel : Node { } override fun copy(): Node = throw FatalAstException("should never duplicate a ParentSentinel") + override fun referencesIdentifier(nameInSource: List): Boolean = false } @@ -254,6 +255,7 @@ interface Node { fun replaceChildNode(node: Node, replacement: Node) fun copy(): Node + fun referencesIdentifier(nameInSource: List): Boolean } @@ -309,6 +311,8 @@ open class Module(final override var statements: MutableList, override fun copy(): Node = throw NotImplementedError("no support for duplicating a Module") override fun toString() = "Module(name=$name, pos=$position, lib=${isLibrary})" + override fun referencesIdentifier(nameInSource: List): Boolean = statements.any { it.referencesIdentifier(nameInSource) } + fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -336,6 +340,8 @@ class GlobalNamespace(val modules: Iterable): Node, INameScope { override fun replaceChildNode(node: Node, replacement: Node) { throw FatalAstException("cannot replace anything in the namespace") } + + override fun referencesIdentifier(nameInSource: List): Boolean = modules.any { it.referencesIdentifier(nameInSource) } } internal object BuiltinFunctionScopePlaceholder : INameScope { diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index 7dab41ce0..d82d6d1b3 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -21,7 +21,6 @@ sealed class Expression: Node { abstract fun constValue(program: Program): NumericLiteral? abstract fun accept(visitor: IAstVisitor) abstract fun accept(visitor: AstWalker, parent: Node) - abstract fun referencesIdentifier(nameInSource: List): Boolean abstract fun inferType(program: Program): InferredTypes.InferredType abstract val isSimple: Boolean @@ -307,7 +306,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List) = arrayvar.referencesIdentifier(nameInSource) + override fun referencesIdentifier(nameInSource: List) = arrayvar.referencesIdentifier(nameInSource) || indexer.referencesIdentifier(nameInSource) override fun inferType(program: Program): InferredTypes.InferredType { val target = arrayvar.targetStatement(program) @@ -835,7 +834,7 @@ class RangeExpression(var from: Expression, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List): Boolean = from.referencesIdentifier(nameInSource) || to.referencesIdentifier(nameInSource) + override fun referencesIdentifier(nameInSource: List): Boolean = from.referencesIdentifier(nameInSource) || to.referencesIdentifier(nameInSource) || step.referencesIdentifier(nameInSource) override fun inferType(program: Program): InferredTypes.InferredType { val fromDt=from.inferType(program) val toDt=to.inferType(program) @@ -898,7 +897,6 @@ class RangeExpression(var from: Expression, } } - data class IdentifierReference(val nameInSource: List, override val position: Position) : Expression() { override lateinit var parent: Node @@ -1062,7 +1060,6 @@ class FunctionCallExpression(override var target: IdentifierReference, } } - class ContainmentCheck(var element: Expression, var iterable: Expression, override val position: Position): Expression() { @@ -1114,11 +1111,7 @@ class ContainmentCheck(var element: Expression, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List): Boolean { - if(element is IdentifierReference) - return element.referencesIdentifier(nameInSource) - return iterable.referencesIdentifier(nameInSource) - } + override fun referencesIdentifier(nameInSource: List): Boolean = element.referencesIdentifier(nameInSource) || iterable.referencesIdentifier(nameInSource) override fun inferType(program: Program) = InferredTypes.knownFor(DataType.BOOL) @@ -1134,17 +1127,6 @@ class ContainmentCheck(var element: Expression, } } - -fun invertCondition(cond: Expression): BinaryExpression? { - if(cond is BinaryExpression) { - val invertedOperator = invertedComparisonOperator(cond.operator) - if (invertedOperator != null) - return BinaryExpression(cond.left, invertedOperator, cond.right, cond.position) - } - return null -} - - class BuiltinFunctionCall(override var target: IdentifierReference, override var args: MutableList, override val position: Position) : Expression(), IFunctionCall { @@ -1185,3 +1167,12 @@ class BuiltinFunctionCall(override var target: IdentifierReference, override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) || args.any{it.referencesIdentifier(nameInSource)} override fun inferType(program: Program) = program.builtinFunctions.returnType(name) } + +fun invertCondition(cond: Expression): BinaryExpression? { + if(cond is BinaryExpression) { + val invertedOperator = invertedComparisonOperator(cond.operator) + if (invertedOperator != null) + return BinaryExpression(cond.left, invertedOperator, cond.right, cond.position) + } + return null +} diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index d692fbdac..6fc26ca84 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -64,6 +64,7 @@ class BuiltinFunctionPlaceholder(override val name: String, override val positio } override fun copy() = throw NotImplementedError("no support for duplicating a BuiltinFunctionStatementPlaceholder") + override fun referencesIdentifier(nameInSource: List): Boolean = nameInSource.size==1 && name==nameInSource[0] } class Block(override val name: String, @@ -90,6 +91,7 @@ class Block(override val name: String, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "Block(name=$name, address=$address, ${statements.size} statements)" + override fun referencesIdentifier(nameInSource: List): Boolean = statements.any { it.referencesIdentifier(nameInSource) } fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet() } @@ -104,6 +106,7 @@ 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 copy() = Directive(directive, args.map { it.copy() }, position) + override fun referencesIdentifier(nameInSource: List): Boolean = false override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) } @@ -116,6 +119,7 @@ data class DirectiveArg(val str: String?, val name: String?, val int: UInt?, ove } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") override fun copy() = DirectiveArg(str, name, int, position) + override fun referencesIdentifier(nameInSource: List): Boolean = false } data class Label(override val name: String, override val position: Position) : Statement(), INamedStatement { @@ -127,6 +131,7 @@ data class Label(override val name: String, override val position: Position) : S override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") override fun copy() = Label(name, position) + override fun referencesIdentifier(nameInSource: List): Boolean = nameInSource.size==1 && nameInSource[0]==name override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString()= "Label(name=$name, pos=$position)" @@ -147,6 +152,7 @@ class Return(var value: Expression?, override val position: Position) : Statemen } override fun copy() = Return(value?.copy(), position) + override fun referencesIdentifier(nameInSource: List): Boolean = value?.referencesIdentifier(nameInSource)==true override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "Return($value, pos=$position)" @@ -160,6 +166,7 @@ class Break(override val position: Position) : Statement() { } override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") + override fun referencesIdentifier(nameInSource: List): Boolean = false override fun copy() = Break(position) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -277,6 +284,10 @@ class VarDecl(val type: VarDeclType, .asSequence() .filterIsInstance() .singleOrNull { it.origin==AssignmentOrigin.VARINIT && it.target.identifier?.targetVarDecl(program) === this } + + override fun referencesIdentifier(nameInSource: List): Boolean = + value?.referencesIdentifier(nameInSource)==true || + this.arraysize?.referencesIdentifier(nameInSource)==true } class ArrayIndex(var indexExpr: Expression, @@ -309,6 +320,7 @@ class ArrayIndex(var indexExpr: Expression, infix fun isSameAs(other: ArrayIndex): Boolean = indexExpr isSameAs other.indexExpr override fun copy() = ArrayIndex(indexExpr.copy(), position) + override fun referencesIdentifier(nameInSource: List): Boolean = indexExpr.referencesIdentifier(nameInSource) } enum class AssignmentOrigin { @@ -340,6 +352,7 @@ class Assignment(var target: AssignTarget, var value: Expression, var origin: As override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "Assignment(target: $target, value: $value, pos=$position)" + override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) || value.referencesIdentifier(nameInSource) /** * Is the assigment value an expression that references the assignment target itself? @@ -429,6 +442,10 @@ data class AssignTarget(var identifier: IdentifierReference?, fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun copy() = AssignTarget(identifier?.copy(), arrayindexed?.copy(), memoryAddress?.copy(), position) + override fun referencesIdentifier(nameInSource: List): Boolean = + identifier?.referencesIdentifier(nameInSource)==true || + arrayindexed?.referencesIdentifier(nameInSource)==true || + memoryAddress?.referencesIdentifier(nameInSource)==true fun inferType(program: Program): InferredTypes.InferredType { if (identifier != null) { @@ -554,6 +571,7 @@ class PostIncrDecr(var target: AssignTarget, val operator: String, override val replacement.parent = this } + override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) override fun copy() = PostIncrDecr(target.copy(), operator, position) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -581,6 +599,7 @@ class Jump(var address: UInt?, override fun copy() = Jump(address, identifier?.copy(), generatedLabel, position) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = identifier?.referencesIdentifier(nameInSource)==true override fun toString() = "Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)" @@ -613,6 +632,7 @@ class FunctionCallStatement(override var target: IdentifierReference, replacement.parent = this } + override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) || args.any { it.referencesIdentifier(nameInSource) } override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "FunctionCallStatement(target=$target, pos=$position)" @@ -630,6 +650,7 @@ class InlineAssembly(val assembly: String, val isIR: Boolean, override val posit override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here") override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = false fun hasReturnOrRts(): Boolean { return if(isIR) { @@ -671,6 +692,7 @@ class AnonymousScope(override var statements: MutableList, replacement.parent = this } + override fun referencesIdentifier(nameInSource: List): Boolean = statements.any { it.referencesIdentifier(nameInSource) } override fun copy() = AnonymousScope(statements.map { it.copy() }.toMutableList(), position) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) @@ -717,6 +739,10 @@ class Subroutine(override val name: String, } } + override fun referencesIdentifier(nameInSource: List): Boolean = + statements.any { it.referencesIdentifier(nameInSource) } || + parameters.any { it.referencesIdentifier(nameInSource) } + override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = @@ -738,6 +764,7 @@ open class SubroutineParameter(val name: String, override fun copy() = SubroutineParameter(name, type, position) override fun toString() = "Param($type:$name)" + override fun referencesIdentifier(nameInSource: List): Boolean = nameInSource.size==1 && name==nameInSource[0] } class IfElse(var condition: Expression, @@ -767,7 +794,10 @@ class IfElse(var condition: Expression, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - + override fun referencesIdentifier(nameInSource: List): Boolean = + condition.referencesIdentifier(nameInSource) || + truepart.referencesIdentifier(nameInSource) || + elsepart.referencesIdentifier(nameInSource) } class ConditionalBranch(var condition: BranchCondition, @@ -795,7 +825,8 @@ class ConditionalBranch(var condition: BranchCondition, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - + override fun referencesIdentifier(nameInSource: List): Boolean = + truepart.referencesIdentifier(nameInSource) || elsepart.referencesIdentifier(nameInSource) } class ForLoop(var loopVar: IdentifierReference, @@ -826,6 +857,10 @@ class ForLoop(var loopVar: IdentifierReference, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "ForLoop(loopVar: $loopVar, iterable: $iterable, pos=$position)" + override fun referencesIdentifier(nameInSource: List): Boolean = + loopVar.referencesIdentifier(nameInSource) || + iterable.referencesIdentifier(nameInSource) || + body.referencesIdentifier(nameInSource) fun loopVarDt(program: Program) = loopVar.inferType(program) } @@ -854,6 +889,8 @@ class WhileLoop(var condition: Expression, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = + condition.referencesIdentifier(nameInSource) || body.referencesIdentifier(nameInSource) } class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override val position: Position) : Statement() { @@ -878,6 +915,8 @@ class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = + iterations?.referencesIdentifier(nameInSource)==true || body.referencesIdentifier(nameInSource) } class UnrollLoop(val iterations: Int, var body: AnonymousScope, override val position: Position) : Statement() { @@ -898,6 +937,7 @@ class UnrollLoop(val iterations: Int, var body: AnonymousScope, override val pos override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = body.referencesIdentifier(nameInSource) } class UntilLoop(var body: AnonymousScope, @@ -923,6 +963,8 @@ class UntilLoop(var body: AnonymousScope, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = + condition.referencesIdentifier(nameInSource) || body.referencesIdentifier(nameInSource) } class When(var condition: Expression, @@ -967,6 +1009,8 @@ class When(var condition: Expression, override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = + condition.referencesIdentifier(nameInSource) || choices.any { it.referencesIdentifier(nameInSource) } } class WhenChoice(var values: MutableList?, // if null, this is the 'else' part @@ -999,6 +1043,8 @@ class WhenChoice(var values: MutableList?, // if null, th fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) + override fun referencesIdentifier(nameInSource: List): Boolean = + values?.any { it.referencesIdentifier(nameInSource) }==true || statements.referencesIdentifier(nameInSource) } class DirectMemoryWrite(var addressExpression: Expression, override val position: Position) : Node { @@ -1019,6 +1065,7 @@ class DirectMemoryWrite(var addressExpression: Expression, override val position fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun copy() = DirectMemoryWrite(addressExpression.copy(), position) + override fun referencesIdentifier(nameInSource: List): Boolean = addressExpression.referencesIdentifier(nameInSource) } @@ -1047,6 +1094,7 @@ class BuiltinFunctionCallStatement(override var target: IdentifierReference, replacement.parent = this } + override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) || args.any { it.referencesIdentifier(nameInSource) } override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun toString() = "BuiltinFunctionCallStatement(name=$name, pos=$position)" diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 04a93209c..e96a98b81 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,7 @@ TODO For next minor release ^^^^^^^^^^^^^^^^^^^^^^ - when a loopvariable of a forloop is *only* referenced in the for loop as loopvariable, and the number of iterations is known, replace the loop by a repeatloop (and remove the vardecl) - but we have no efficient way right now to see if the body references a variable. (what about ReferencesIdentifier? - only on Expressions now) + but we have no efficient way right now to see if the body references a variable. (what about ReferencesIdentifier?) ...