From dad5b17ac8eb0132ba99289016de6e52c11bb22e Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 8 May 2022 13:45:11 +0200 Subject: [PATCH] fix regression compiler crash in string comparison --- .../astprocessing/LiteralsToAutoVars.kt | 6 ++- compiler/test/TestOptimization.kt | 2 - compiler/test/ast/TestVarious.kt | 54 +++++++++++++++++++ docs/source/todo.rst | 1 - 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt index e4cc8c8af..530ab7145 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt @@ -27,7 +27,11 @@ internal class LiteralsToAutoVars(private val program: Program, errors.err("compilation target doesn't support this text encoding", string.position) return noModifications } - if(string.parent !is VarDecl && string.parent !is WhenChoice && string.parent !is BinaryExpression) { + if(string.parent !is VarDecl && string.parent !is WhenChoice) { + val binExpr = string.parent as? BinaryExpression + if(binExpr!=null &&(binExpr.operator=="+" || binExpr.operator=="*")) + return noModifications // allow string concatenation or repeats later, based on just string literals + // replace the literal string by an identifier reference to the interned string val parentFunc = (string.parent as? IFunctionCall)?.target if(parentFunc!=null) { diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 292c3582a..f0244d6a0 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -3,7 +3,6 @@ package prog8tests import io.kotest.assertions.fail import io.kotest.assertions.withClue import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.collections.shouldStartWith import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.string.shouldContain @@ -753,7 +752,6 @@ class TestOptimization: FunSpec({ } }""" val result = compileText(C64Target(), optimize=true, src, writeAssembly=false)!! - printProgram(result.program) val stmts = result.program.entrypoint.statements stmts.size shouldBe 5 val ifStmt = stmts[4] as IfElse diff --git a/compiler/test/ast/TestVarious.kt b/compiler/test/ast/TestVarious.kt index 826fe7d7a..f3eb74adb 100644 --- a/compiler/test/ast/TestVarious.kt +++ b/compiler/test/ast/TestVarious.kt @@ -3,9 +3,15 @@ package prog8tests.ast import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe +import prog8.ast.IFunctionCall +import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.StringLiteral +import prog8.ast.statements.Assignment import prog8.ast.statements.InlineAssembly +import prog8.ast.statements.VarDecl import prog8.code.core.Position import prog8.code.target.C64Target +import prog8.compiler.printProgram import prog8tests.helpers.compileText class TestVarious: FunSpec({ @@ -61,5 +67,53 @@ main { }""" compileText(C64Target(), false, text, writeAssembly = false) shouldBe null } + + test("simple string comparison still works") { + val src=""" + main { + sub start() { + ubyte @shared value + str thing = "????" + + if thing=="name" { + value++ + } + + if thing!="name" { + value++ + } + } + }""" + val result = compileText(C64Target(), optimize=false, src, writeAssembly=true)!! + val stmts = result.program.entrypoint.statements + stmts.size shouldBe 6 + } + + test("string concatenation and repeats") { + val src=""" + main { + sub start() { + str @shared name = "part1" + "part2" + str @shared rept = "rep"*4 + const ubyte times = 3 + name = "xx1" + "xx2" + rept = "xyz" * (times+1) + } + }""" + val result = compileText(C64Target(), optimize=false, src, writeAssembly=true)!! + printProgram(result.program) + val stmts = result.program.entrypoint.statements + stmts.size shouldBe 6 + val name1 = stmts[0] as VarDecl + val rept1 = stmts[1] as VarDecl + (name1.value as StringLiteral).value shouldBe "part1part2" + (rept1.value as StringLiteral).value shouldBe "reprepreprep" + val name2strcopy = stmts[3] as IFunctionCall + val rept2strcopy = stmts[4] as IFunctionCall + val name2 = name2strcopy.args.first() as IdentifierReference + val rept2 = rept2strcopy.args.first() as IdentifierReference + (name2.targetVarDecl(result.program)!!.value as StringLiteral).value shouldBe "xx1xx2" + (rept2.targetVarDecl(result.program)!!.value as StringLiteral).value shouldBe "xyzxyzxyzxyz" + } }) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 0cf2cb3b8..70ce399d7 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,6 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- fix compiler crash when comparing strings - make it possible to inline non-asmsub routines that just contain a single statement (return, functioncall, assignment) Only if the arguments are simple expressions, and the inlined subroutine cannot contain further nested subroutines! This requires all identifiers in the inlined expression to be changed to fully scoped names (because their scope changes).