From b7502c7eaa1e823581a5099730c60c47f519db31 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 28 Jul 2019 15:18:53 +0200 Subject: [PATCH] fixed some node update issues in Modifying Ast visitor --- .../prog8/ast/expressions/AstExpressions.kt | 13 +++- .../src/prog8/ast/processing/AstChecker.kt | 5 +- .../ast/processing/AstIdentifiersChecker.kt | 60 +++++++++------- .../ast/processing/IAstModifyingVisitor.kt | 46 ++++++++++--- .../src/prog8/ast/statements/AstStatements.kt | 51 ++++++++------ compiler/src/prog8/compiler/Main.kt | 4 +- .../c64/codegen2/AnonymousScopeCleanup.kt | 31 --------- .../c64/codegen2/AnonymousScopeVarsCleanup.kt | 68 +++++++++++++++++++ .../compiler/target/c64/codegen2/AsmGen2.kt | 65 ++++++++++-------- compiler/src/prog8/vm/astvm/AstVm.kt | 27 ++++---- examples/test.p8 | 39 ++++++++--- 11 files changed, 264 insertions(+), 145 deletions(-) delete mode 100644 compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeCleanup.kt create mode 100644 compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 4a78e07a1..c5a4d28e2 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -247,8 +247,8 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex } } -class ArrayIndexedExpression(val identifier: IdentifierReference, - var arrayspec: ArrayIndex, +class ArrayIndexedExpression(var identifier: IdentifierReference, + val arrayspec: ArrayIndex, override val position: Position) : Expression() { override lateinit var parent: Node override fun linkParents(parent: Node) { @@ -304,7 +304,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp } } -data class AddressOf(val identifier: IdentifierReference, override val position: Position) : Expression() { +data class AddressOf(var identifier: IdentifierReference, override val position: Position) : Expression() { override lateinit var parent: Node override fun linkParents(parent: Node) { @@ -753,6 +753,13 @@ data class IdentifierReference(val nameInSource: List, override val posi else -> throw FatalAstException("requires a reference value") } } + + fun withPrefixedName(nameprefix: String): IdentifierReference { + val prefixed = nameInSource.dropLast(1) + listOf(nameprefix+nameInSource.last()) + val new = IdentifierReference(prefixed, position) + new.parent = parent + return new + } } class FunctionCall(override var target: IdentifierReference, diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 7ba14c91e..738f70486 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -370,8 +370,9 @@ internal class AstChecker(private val program: Program, } val assignment = assignTarget.parent as Statement - if (assignTarget.identifier != null) { - val targetName = assignTarget.identifier.nameInSource + val targetIdentifier = assignTarget.identifier + if (targetIdentifier != null) { + val targetName = targetIdentifier.nameInSource val targetSymbol = program.namespace.lookup(targetName, assignment) when (targetSymbol) { null -> { diff --git a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt index ab0a64b26..89689539a 100644 --- a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt @@ -166,30 +166,32 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi checkResult.add(SyntaxError("register loop variables have a fixed implicit datatype", forLoop.position)) if(forLoop.loopRegister == Register.X) printWarning("writing to the X register is dangerous, because it's used as an internal pointer", forLoop.position) - } else if(forLoop.loopVar!=null) { - val varName = forLoop.loopVar.nameInSource.last() - if(forLoop.decltype!=null) { - val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first()) - if(existing==null) { - // create the local scoped for loop variable itself - val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, varName, null, null, - isArray = false, autogeneratedDontRemove = true, position = forLoop.loopVar.position) - vardecl.linkParents(forLoop.body) - forLoop.body.statements.add(0, vardecl) - forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' + } else { + val loopVar = forLoop.loopVar + if (loopVar != null) { + val varName = loopVar.nameInSource.last() + if (forLoop.decltype != null) { + val existing = if (forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(loopVar.nameInSource, forLoop.body.statements.first()) + if (existing == null) { + // create the local scoped for loop variable itself + val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, varName, null, null, + isArray = false, autogeneratedDontRemove = true, position = loopVar.position) + vardecl.linkParents(forLoop.body) + forLoop.body.statements.add(0, vardecl) + loopVar.parent = forLoop.body // loopvar 'is defined in the body' + } } - } - - if(forLoop.iterable !is RangeExpr) { - val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first()) - if(existing==null) { - // create loop iteration counter variable (without value, to avoid an assignment) - val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, null, ForLoop.iteratorLoopcounterVarname, null, null, - isArray = false, autogeneratedDontRemove = true, position = forLoop.loopVar.position) - vardecl.linkParents(forLoop.body) - forLoop.body.statements.add(0, vardecl) - forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' + if (forLoop.iterable !is RangeExpr) { + val existing = if (forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first()) + if (existing == null) { + // create loop iteration counter variable (without value, to avoid an assignment) + val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, null, ForLoop.iteratorLoopcounterVarname, null, null, + isArray = false, autogeneratedDontRemove = true, position = loopVar.position) + vardecl.linkParents(forLoop.body) + forLoop.body.statements.add(0, vardecl) + loopVar.parent = forLoop.body // loopvar 'is defined in the body' + } } } } @@ -233,8 +235,9 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi // a referencetype literal value that's not declared as a variable // we need to introduce an auto-generated variable for this to be able to refer to the value refLiteral.addToHeap(program.heap) - val variable = VarDecl.createAuto(refLiteral, program.heap) - addVarDecl(refLiteral.definingScope(), variable) + val scope = refLiteral.definingScope() + var variable = VarDecl.createAuto(refLiteral, program.heap) + variable = addVarDecl(scope, variable) // replace the reference literal by a identifier reference val identifier = IdentifierReference(listOf(variable.name), variable.position) identifier.parent = refLiteral.parent @@ -290,12 +293,17 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi return expr } - private fun addVarDecl(scope: INameScope, variable: VarDecl) { + private fun addVarDecl(scope: INameScope, variable: VarDecl): VarDecl { if(scope !in vardeclsToAdd) vardeclsToAdd[scope] = mutableListOf() val declList = vardeclsToAdd.getValue(scope) - if(declList.all{it.name!=variable.name}) + val existing = declList.singleOrNull { it.name==variable.name } + return if(existing!=null) { + existing + } else { declList.add(variable) + variable + } } } diff --git a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt b/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt index edf3eb728..ff382d69b 100644 --- a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt +++ b/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt @@ -2,6 +2,7 @@ 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.* @@ -36,7 +37,7 @@ interface IAstModifyingVisitor { fun visit(decl: VarDecl): Statement { decl.value = decl.value?.accept(this) - decl.arraysize?.accept(this) + decl.arraysize = decl.arraysize?.accept(this) return decl } @@ -49,6 +50,8 @@ interface IAstModifyingVisitor { val newtarget = functionCall.target.accept(this) if(newtarget is IdentifierReference) functionCall.target = newtarget + else + throw FatalAstException("cannot change class of function call target") functionCall.arglist = functionCall.arglist.map { it.accept(this) }.toMutableList() return functionCall } @@ -57,6 +60,8 @@ interface IAstModifyingVisitor { val newtarget = functionCallStatement.target.accept(this) if(newtarget is IdentifierReference) functionCallStatement.target = newtarget + else + throw FatalAstException("cannot change class of function call target") functionCallStatement.arglist = functionCallStatement.arglist.map { it.accept(this) }.toMutableList() return functionCallStatement } @@ -135,7 +140,12 @@ interface IAstModifyingVisitor { } fun visit(forLoop: ForLoop): Statement { - forLoop.loopVar?.accept(this) + val newloopvar = forLoop.loopVar?.accept(this) + when(newloopvar) { + 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 @@ -158,15 +168,24 @@ interface IAstModifyingVisitor { return returnStmt } - fun visit(arrayIndexedExpression: ArrayIndexedExpression): Expression { - arrayIndexedExpression.identifier.accept(this) + fun visit(arrayIndexedExpression: ArrayIndexedExpression): ArrayIndexedExpression { + val ident = arrayIndexedExpression.identifier.accept(this) + if(ident is IdentifierReference) + arrayIndexedExpression.identifier = ident + else + throw FatalAstException("can't change class of indexed identifier") arrayIndexedExpression.arrayspec.accept(this) return arrayIndexedExpression } fun visit(assignTarget: AssignTarget): AssignTarget { - assignTarget.arrayindexed?.accept(this) - assignTarget.identifier?.accept(this) + val ident = assignTarget.identifier?.accept(this) + when (ident) { + 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 } @@ -191,7 +210,11 @@ interface IAstModifyingVisitor { } fun visit(addressOf: AddressOf): Expression { - addressOf.identifier.accept(this) + 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 } @@ -212,14 +235,19 @@ interface IAstModifyingVisitor { } fun visit(whenStatement: WhenStatement): Statement { - whenStatement.condition.accept(this) + whenStatement.condition = whenStatement.condition.accept(this) whenStatement.choices.forEach { it.accept(this) } return whenStatement } fun visit(whenChoice: WhenChoice) { whenChoice.values?.forEach { it.accept(this) } - whenChoice.statements.accept(this) + val stmt = whenChoice.statements.accept(this) + if(stmt is AnonymousScope) + whenChoice.statements = stmt + else { + whenChoice.statements = AnonymousScope(mutableListOf(stmt), stmt.position) + } } fun visit(structDecl: StructDecl): Statement { diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index ff530d93a..f34e58138 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -198,7 +198,6 @@ class VarDecl(val type: VarDeclType, throw FatalAstException("can only create autovar for a ref lv that has a heapid $refLv") val autoVarName = "$autoHeapValuePrefix${refLv.heapId}" - return if(refLv.isArray) { val declaredType = ArrayElementTypes.getValue(refLv.type) val arraysize = ArrayIndex.forArray(refLv, heap) @@ -281,6 +280,12 @@ class VarDecl(val type: VarDeclType, structHasBeenFlattened = true return result } + + fun withPrefixedName(nameprefix: String): Statement { + val new = VarDecl(type, declaredDatatype, zeropage, arraysize, nameprefix+name, structName, value, isArray, autogeneratedDontRemove, position) + new.parent = parent + return new + } } class ArrayIndex(var index: Expression, override val position: Position) : Node { @@ -298,9 +303,11 @@ class ArrayIndex(var index: Expression, override val position: Position) : Node } } - fun accept(visitor: IAstModifyingVisitor) { + fun accept(visitor: IAstModifyingVisitor): ArrayIndex { index = index.accept(visitor) + return this } + fun accept(visitor: IAstVisitor) { index.accept(visitor) } @@ -337,9 +344,9 @@ class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, va : Assignment(target, aug_op, value, position) data class AssignTarget(val register: Register?, - val identifier: IdentifierReference?, - val arrayindexed: ArrayIndexedExpression?, - var memoryAddress: DirectMemoryWrite?, + var identifier: IdentifierReference?, + var arrayindexed: ArrayIndexedExpression?, + val memoryAddress: DirectMemoryWrite?, override val position: Position) : Node { override lateinit var parent: Node @@ -370,12 +377,12 @@ data class AssignTarget(val register: Register?, return DataType.UBYTE if(identifier!=null) { - val symbol = program.namespace.lookup(identifier.nameInSource, stmt) ?: return null + val symbol = program.namespace.lookup(identifier!!.nameInSource, stmt) ?: return null if (symbol is VarDecl) return symbol.datatype } if(arrayindexed!=null) { - val dt = arrayindexed.inferType(program) + val dt = arrayindexed!!.inferType(program) if(dt!=null) return dt } @@ -390,12 +397,12 @@ data class AssignTarget(val register: Register?, return when { this.memoryAddress!=null -> false this.register!=null -> value is RegisterExpr && value.register==register - this.identifier!=null -> value is IdentifierReference && value.nameInSource==identifier.nameInSource + this.identifier!=null -> value is IdentifierReference && value.nameInSource==identifier!!.nameInSource this.arrayindexed!=null -> value is ArrayIndexedExpression && - value.identifier.nameInSource==arrayindexed.identifier.nameInSource && + value.identifier.nameInSource==arrayindexed!!.identifier.nameInSource && value.arrayspec.size()!=null && - arrayindexed.arrayspec.size()!=null && - value.arrayspec.size()==arrayindexed.arrayspec.size() + arrayindexed!!.arrayspec.size()!=null && + value.arrayspec.size()==arrayindexed!!.arrayspec.size() else -> false } } @@ -406,16 +413,16 @@ data class AssignTarget(val register: Register?, if(this.register!=null && other.register!=null) return this.register==other.register if(this.identifier!=null && other.identifier!=null) - return this.identifier.nameInSource==other.identifier.nameInSource + return this.identifier!!.nameInSource==other.identifier!!.nameInSource if(this.memoryAddress!=null && other.memoryAddress!=null) { - val addr1 = this.memoryAddress!!.addressExpression.constValue(program) - val addr2 = other.memoryAddress!!.addressExpression.constValue(program) + val addr1 = this.memoryAddress.addressExpression.constValue(program) + val addr2 = other.memoryAddress.addressExpression.constValue(program) return addr1!=null && addr2!=null && addr1==addr2 } if(this.arrayindexed!=null && other.arrayindexed!=null) { - if(this.arrayindexed.identifier.nameInSource == other.arrayindexed.identifier.nameInSource) { - val x1 = this.arrayindexed.arrayspec.index.constValue(program) - val x2 = other.arrayindexed.arrayspec.index.constValue(program) + if(this.arrayindexed!!.identifier.nameInSource == other.arrayindexed!!.identifier.nameInSource) { + val x1 = this.arrayindexed!!.arrayspec.index.constValue(program) + val x2 = other.arrayindexed!!.arrayspec.index.constValue(program) return x1!=null && x2!=null && x1==x2 } } @@ -428,12 +435,12 @@ data class AssignTarget(val register: Register?, if(this.memoryAddress!=null) return false if(this.arrayindexed!=null) { - val targetStmt = this.arrayindexed.identifier.targetVarDecl(namespace) + val targetStmt = this.arrayindexed!!.identifier.targetVarDecl(namespace) if(targetStmt!=null) return targetStmt.type!= VarDeclType.MEMORY } if(this.identifier!=null) { - val targetStmt = this.identifier.targetVarDecl(namespace) + val targetStmt = this.identifier!!.targetVarDecl(namespace) if(targetStmt!=null) return targetStmt.type!= VarDeclType.MEMORY } @@ -684,7 +691,7 @@ class BranchStatement(var condition: BranchCondition, class ForLoop(val loopRegister: Register?, val decltype: DataType?, val zeropage: ZeropageWish, - val loopVar: IdentifierReference?, + var loopVar: IdentifierReference?, var iterable: Expression, var body: AnonymousScope, override val position: Position) : Statement() { @@ -742,7 +749,7 @@ class RepeatLoop(var body: AnonymousScope, override fun accept(visitor: IAstVisitor) = visitor.visit(this) } -class WhenStatement(val condition: Expression, +class WhenStatement(var condition: Expression, val choices: MutableList, override val position: Position): Statement() { override lateinit var parent: Node @@ -776,7 +783,7 @@ class WhenStatement(val condition: Expression, } class WhenChoice(val values: List?, // if null, this is the 'else' part - val statements: AnonymousScope, + var statements: AnonymousScope, override val position: Position) : Node { override lateinit var parent: Node diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index 5d3f299e4..76355c169 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -5,7 +5,7 @@ import prog8.ast.Program import prog8.ast.base.* import prog8.ast.statements.Directive import prog8.compiler.target.c64.MachineDefinition -import prog8.compiler.target.c64.codegen2.AnonymousScopeCleanup +import prog8.compiler.target.c64.codegen2.AnonymousScopeVarsCleanup import prog8.compiler.target.c64.codegen2.AsmGen2 import prog8.optimizer.constantFold import prog8.optimizer.optimizeStatements @@ -92,7 +92,7 @@ fun compileProgram(filepath: Path, if(writeAssembly) { // asm generation directly from the Ast, no need for intermediate code val zeropage = MachineDefinition.C64Zeropage(compilerOptions) - AnonymousScopeCleanup.moveVarsFromAnonymousScopesToSubroutines(programAst) + AnonymousScopeVarsCleanup.moveVarsToSubroutine(programAst) val assembly = AsmGen2(programAst, compilerOptions, zeropage).compileToAssembly(optimize) assembly.assemble(compilerOptions) programName = assembly.name diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeCleanup.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeCleanup.kt deleted file mode 100644 index cf493c1d9..000000000 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeCleanup.kt +++ /dev/null @@ -1,31 +0,0 @@ -package prog8.compiler.target.c64.codegen2 - -import prog8.ast.Program -import prog8.ast.processing.IAstVisitor -import prog8.ast.statements.AnonymousScope -import prog8.ast.statements.VarDecl - -class AnonymousScopeCleanup(val program: Program): IAstVisitor { - companion object { - fun moveVarsFromAnonymousScopesToSubroutines(programAst: Program) { - val cleanup = AnonymousScopeCleanup(programAst) - cleanup.visit(programAst) - - for((scope, decls) in cleanup.varsToMove) { - decls.forEach { scope.remove(it) } - val sub = scope.definingSubroutine()!! - sub.statements.addAll(0, decls) - decls.forEach { it.parent=sub } - } - } - } - - private val varsToMove: MutableMap> = mutableMapOf() - - override fun visit(scope: AnonymousScope) { - val vardecls = scope.statements.filterIsInstance() - varsToMove[scope] = vardecls - super.visit(scope) - } -} - diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt new file mode 100644 index 000000000..d373ebfe8 --- /dev/null +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt @@ -0,0 +1,68 @@ +package prog8.compiler.target.c64.codegen2 + +import prog8.ast.Program +import prog8.ast.base.FatalAstException +import prog8.ast.expressions.Expression +import prog8.ast.expressions.IdentifierReference +import prog8.ast.processing.IAstModifyingVisitor +import prog8.ast.statements.AnonymousScope +import prog8.ast.statements.Statement +import prog8.ast.statements.VarDecl + +class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor { + companion object { + fun moveVarsToSubroutine(programAst: Program) { + val cleanup = AnonymousScopeVarsCleanup(programAst) + cleanup.visit(programAst) + + for((scope, decls) in cleanup.varsToMove) { + decls.forEach { scope.remove(it) } + val sub = scope.definingSubroutine()!! + val existingVariables = sub.statements.filterIsInstance().map { it.name }.toSet() + sub.statements.addAll(0, decls) + decls.forEach { + it.parent=sub + if(it.name in existingVariables) { + throw FatalAstException("variable ${it.name} already exists in ${sub.name}") + } + } + } + } + } + + private val varsToMove: MutableMap> = mutableMapOf() + + override fun visit(scope: AnonymousScope): Statement { + val scope2 = super.visit(scope) as AnonymousScope + val vardecls = scope2.statements.filterIsInstance() + varsToMove[scope2] = vardecls + return scope2 + } + + private fun nameprefix(scope: AnonymousScope) = scope.name.replace("<", "").replace(">", "").replace("-", "") + "_" + + override fun visit(decl: VarDecl): Statement { + val decl2 = super.visit(decl) as VarDecl + val scope = decl2.definingScope() + if(scope is AnonymousScope) { + return decl2.withPrefixedName(nameprefix(scope)) + } + return decl2 + } + + override fun visit(identifier: IdentifierReference): Expression { + val ident = super.visit(identifier) + if(ident !is IdentifierReference) + return ident + + val scope = ident.definingScope() as? AnonymousScope ?: return ident + val vardecl = ident.targetVarDecl(program.namespace) + return if(vardecl!=null) { + // prefix the variable name reference + ident.withPrefixedName(nameprefix(scope)) + } else { + ident + } + } +} + diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index 473db39b9..ec7cd1e4a 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -548,7 +548,7 @@ internal class AsmGen2(val program: Program, } private fun translateSubroutineCall(stmt: IFunctionCall) { - val sub = stmt.target.targetSubroutine(program.namespace)!! + val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") if(Register.X in sub.asmClobbers) out(" stx c64.SCRATCH_ZPREGX") // we only save X for now (required! is the eval stack pointer), screw A and Y... @@ -1189,15 +1189,16 @@ internal class AsmGen2(val program: Program, } private fun assignEvalResult(target: AssignTarget) { + val targetIdent = target.identifier when { target.register!=null -> { if(target.register==Register.X) throw AssemblyError("can't pop into X register - use variable instead") out(" inx | ld${target.register.name.toLowerCase()} $ESTACK_LO_HEX,x ") } - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) - val targetDt = target.identifier.inferType(program)!! + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) + val targetDt = targetIdent.inferType(program)!! when(targetDt) { DataType.UBYTE, DataType.BYTE -> { out(" inx | lda $ESTACK_LO_HEX,x | sta $targetName") @@ -1222,7 +1223,7 @@ internal class AsmGen2(val program: Program, } } target.memoryAddress!=null -> { - val address = target.memoryAddress!!.addressExpression + val address = target.memoryAddress.addressExpression if(address is NumericLiteralValue) { out(" inx | lda $ESTACK_LO_HEX,x | sta ${address.number.toHex()}") } else { @@ -1237,9 +1238,10 @@ internal class AsmGen2(val program: Program, } private fun assignAddressOf(target: AssignTarget, name: IdentifierReference, scopedname: String) { + val targetIdent = target.identifier when { - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) val struct = name.memberOfStruct(program.namespace) if(struct!=null) { // take the address of the first struct member instead @@ -1271,9 +1273,10 @@ internal class AsmGen2(val program: Program, private fun assignWordVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) + val targetIdent = target.identifier when { - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(""" lda $sourceName ldy $sourceName+1 @@ -1287,9 +1290,10 @@ internal class AsmGen2(val program: Program, private fun assignFloatVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) + val targetIdent = target.identifier when { - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(""" lda $sourceName sta $targetName @@ -1309,12 +1313,13 @@ internal class AsmGen2(val program: Program, private fun assignByteVariable(target: AssignTarget, variable: IdentifierReference) { val sourceName = asmIdentifierName(variable) + val targetIdent = target.identifier when { target.register!=null -> { out(" ld${target.register.name.toLowerCase()} $sourceName") } - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(""" lda $sourceName sta $targetName @@ -1325,9 +1330,11 @@ internal class AsmGen2(val program: Program, } private fun assignRegister(target: AssignTarget, register: Register) { + val targetIdent = target.identifier + val targetArrayIdx = target.arrayindexed when { - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(" st${register.name.toLowerCase()} $targetName") } target.register!=null -> { @@ -1370,8 +1377,9 @@ internal class AsmGen2(val program: Program, } private fun assignWordConstant(target: AssignTarget, word: Int) { - if(target.identifier!=null) { - val targetName = asmIdentifierName(target.identifier) + val targetIdent = target.identifier + if(targetIdent!=null) { + val targetName = asmIdentifierName(targetIdent) if(word ushr 8 == word and 255) { // lsb=msb out(""" @@ -1393,12 +1401,13 @@ internal class AsmGen2(val program: Program, } private fun assignByteConstant(target: AssignTarget, byte: Short) { + val targetIdent = target.identifier when { target.register!=null -> { out(" ld${target.register.name.toLowerCase()} #${byte.toHex()}") } - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(" lda #${byte.toHex()} | sta $targetName ") } else -> TODO("assign byte $byte to $target") @@ -1406,10 +1415,11 @@ internal class AsmGen2(val program: Program, } private fun assignFloatConstant(target: AssignTarget, float: Double) { + val targetIdent = target.identifier if(float==0.0) { // optimized case for float zero - if (target.identifier != null) { - val targetName = asmIdentifierName(target.identifier) + if (targetIdent != null) { + val targetName = asmIdentifierName(targetIdent) out(""" lda #0 sta $targetName @@ -1424,8 +1434,8 @@ internal class AsmGen2(val program: Program, } else { // non-zero value val constFloat = getFloatConst(float) - if (target.identifier != null) { - val targetName = asmIdentifierName(target.identifier) + if (targetIdent != null) { + val targetName = asmIdentifierName(targetIdent) out(""" lda $constFloat sta $targetName @@ -1445,13 +1455,14 @@ internal class AsmGen2(val program: Program, } private fun assignMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) { + val targetIdent = target.identifier if(address!=null) { when { target.register!=null -> { out(" ld${target.register.name.toLowerCase()} ${address.toHex()}") } - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(""" lda ${address.toHex()} sta $targetName @@ -1474,8 +1485,8 @@ internal class AsmGen2(val program: Program, Register.Y -> out(" tay") } } - target.identifier!=null -> { - val targetName = asmIdentifierName(target.identifier) + targetIdent!=null -> { + val targetName = asmIdentifierName(targetIdent) out(""" ldy #0 lda ($sourceName),y diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 4428e9cc1..3f27aabc1 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -472,7 +472,7 @@ class AstVm(val program: Program) { loopvar = IdentifierReference(listOf(stmt.loopRegister.name), stmt.position) } else { loopvarDt = stmt.loopVar!!.inferType(program)!! - loopvar = stmt.loopVar + loopvar = stmt.loopVar!! } val iterator = iterable.iterator() for (loopvalue in iterator) { @@ -545,10 +545,12 @@ class AstVm(val program: Program) { } fun performAssignment(target: AssignTarget, value: RuntimeValue, contextStmt: Statement, evalCtx: EvalContext) { + val targetIdent = target.identifier + val targetArrayIndexed = target.arrayindexed when { - target.identifier != null -> { - val decl = contextStmt.definingScope().lookup(target.identifier.nameInSource, contextStmt) as? VarDecl - ?: throw VmExecutionException("can't find assignment target ${target.identifier}") + targetIdent != null -> { + val decl = contextStmt.definingScope().lookup(targetIdent.nameInSource, contextStmt) as? VarDecl + ?: throw VmExecutionException("can't find assignment target $targetIdent") if (decl.type == VarDeclType.MEMORY) { val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name) when (decl.datatype) { @@ -565,14 +567,14 @@ class AstVm(val program: Program) { runtimeVariables.set(decl.definingScope(), decl.name, value) } target.memoryAddress != null -> { - val address = evaluate(target.memoryAddress!!.addressExpression, evalCtx).wordval!! + val address = evaluate(target.memoryAddress.addressExpression, evalCtx).wordval!! evalCtx.mem.setUByte(address, value.byteval!!) } - target.arrayindexed != null -> { - val vardecl = target.arrayindexed.identifier.targetVarDecl(program.namespace)!! + targetArrayIndexed != null -> { + val vardecl = targetArrayIndexed.identifier.targetVarDecl(program.namespace)!! if(vardecl.type==VarDeclType.VAR) { - val array = evaluate(target.arrayindexed.identifier, evalCtx) - val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx) + val array = evaluate(targetArrayIndexed.identifier, evalCtx) + val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx) when (array.type) { DataType.ARRAY_UB -> { if (value.type != DataType.UBYTE) @@ -606,7 +608,7 @@ class AstVm(val program: Program) { val indexInt = index.integerValue() val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true) val newstr = array.str!!.replaceRange(indexInt, indexInt + 1, newchr) - val ident = contextStmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, contextStmt) as? VarDecl + val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl ?: throw VmExecutionException("can't find assignment target ${target.identifier}") val identScope = ident.definingScope() program.heap.update(array.heapId!!, newstr) @@ -615,8 +617,8 @@ class AstVm(val program: Program) { } else { val address = (vardecl.value as NumericLiteralValue).number.toInt() - val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx).integerValue() - val elementType = target.arrayindexed.inferType(program)!! + val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx).integerValue() + val elementType = targetArrayIndexed.inferType(program)!! when(elementType) { DataType.UBYTE -> mem.setUByte(address+index, value.byteval!!) DataType.BYTE -> mem.setSByte(address+index, value.byteval!!) @@ -952,4 +954,3 @@ class AstVm(val program: Program) { } } - diff --git a/examples/test.p8 b/examples/test.p8 index 5de06c7f5..d644fce01 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,18 +6,37 @@ sub start() { - float f1 = 1.1 - float f2 = 2.2 +; +; float f1 = 1.1 +; float f2 = 2.2 +; +; @(1024) = f1==f2 +; +; c64.CHROUT('\n') +; c64scr.print_ub(f1==f2) +; c64.CHROUT('\n') +; +; if f1 ==0.0 +; c64scr.print("error\n") +; else +; c64scr.print("ok\n") - @(1024) = f1==f2 + str s1 = "hello" + str s2 = "hello" + str s3 = "hello" + str s4 = "hello" - c64.CHROUT('\n') - c64scr.print_ub(f1==f2) - c64.CHROUT('\n') + if true { + ubyte ub1 = 33 + A=ub1 + c64scr.print("irmen") + } + + if true { + ubyte ub1 = 33 + A=ub1 + c64scr.print("irmen") + } - if f1 ==0.0 - c64scr.print("error\n") - else - c64scr.print("ok\n") } }