fix constvalue parent linkage for prefix and typecast

This commit is contained in:
Irmen de Jong 2021-11-20 00:15:04 +01:00
parent cedfb17b18
commit 87600b23db
3 changed files with 50 additions and 9 deletions

View File

@ -5,6 +5,7 @@ import io.kotest.assertions.withClue
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.types.instanceOf import io.kotest.matchers.types.instanceOf
import io.kotest.matchers.types.shouldBeSameInstanceAs import io.kotest.matchers.types.shouldBeSameInstanceAs
import prog8.ast.Program import prog8.ast.Program
@ -16,6 +17,7 @@ import prog8.ast.statements.*
import prog8.compiler.BeforeAsmGenerationAstChanger import prog8.compiler.BeforeAsmGenerationAstChanger
import prog8.compiler.target.C64Target import prog8.compiler.target.C64Target
import prog8.compilerinterface.* import prog8.compilerinterface.*
import prog8tests.helpers.*
import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyFunctions
import prog8tests.helpers.DummyMemsizer import prog8tests.helpers.DummyMemsizer
import prog8tests.helpers.DummyStringEncoder import prog8tests.helpers.DummyStringEncoder
@ -73,7 +75,7 @@ class TestOptimization: FunSpec({
} }
} }
test("generated constvalue inherits proper parent linkage") { test("generated constvalue from typecast inherits proper parent linkage") {
val number = NumericLiteralValue(DataType.UBYTE, 11.0, Position.DUMMY) val number = NumericLiteralValue(DataType.UBYTE, 11.0, Position.DUMMY)
val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY) val tc = TypecastExpression(number, DataType.BYTE, false, Position.DUMMY)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder) val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
@ -83,9 +85,24 @@ class TestOptimization: FunSpec({
tc shouldBeSameInstanceAs number.parent tc shouldBeSameInstanceAs number.parent
val constvalue = tc.constValue(program)!! val constvalue = tc.constValue(program)!!
constvalue shouldBe instanceOf<NumericLiteralValue>() constvalue shouldBe instanceOf<NumericLiteralValue>()
constvalue.number.toInt() shouldBe 11 constvalue.number shouldBe 11.0
constvalue.type shouldBe DataType.BYTE constvalue.type shouldBe DataType.BYTE
tc shouldBeSameInstanceAs constvalue.parent constvalue.parent shouldBeSameInstanceAs tc.parent
}
test("generated constvalue from prefixexpr inherits proper parent linkage") {
val number = NumericLiteralValue(DataType.UBYTE, 11.0, Position.DUMMY)
val pfx = PrefixExpression("-", number, Position.DUMMY)
val program = Program("test", DummyFunctions, DummyMemsizer, DummyStringEncoder)
pfx.linkParents(ParentSentinel)
pfx.parent shouldNotBe null
number.parent shouldNotBe null
pfx shouldBeSameInstanceAs number.parent
val constvalue = pfx.constValue(program)!!
constvalue shouldBe instanceOf<NumericLiteralValue>()
constvalue.number shouldBe -11.0
constvalue.type shouldBe DataType.BYTE
constvalue.parent shouldBeSameInstanceAs pfx.parent
} }
test("constantfolded and silently typecasted for initializervalues") { test("constantfolded and silently typecasted for initializervalues") {
@ -410,8 +427,8 @@ class TestOptimization: FunSpec({
main { main {
sub start() { sub start() {
ubyte @shared z1 = 1 ubyte @shared z1 = 1
ubyte @shared z2 = +1 ubyte @shared z2 = + 1
ubyte @shared z3 = ~1 ubyte @shared z3 = ~ 1
ubyte @shared z4 = not 1 ubyte @shared z4 = not 1
byte @shared z5 = - 1 byte @shared z5 = - 1
} }
@ -423,4 +440,19 @@ class TestOptimization: FunSpec({
stmts.filterIsInstance<VarDecl>().size shouldBe 5 stmts.filterIsInstance<VarDecl>().size shouldBe 5
stmts.filterIsInstance<Assignment>().size shouldBe 5 stmts.filterIsInstance<Assignment>().size shouldBe 5
} }
test("correctly process constant prefix numbers with type mismatch and give error") {
val src="""
main {
sub start() {
ubyte @shared z1 = - 1
}
}
"""
val errors = ErrorReporterForTests()
compileText(C64Target, optimize=true, src, writeAssembly=false, errors = errors).assertFailure()
errors.errors.size shouldBe 2
errors.errors[0] shouldContain "type of value BYTE doesn't match target UBYTE"
errors.errors[1] shouldContain "value '-1' out of range for unsigned byte"
}
}) })

View File

@ -96,7 +96,7 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
override fun copy() = PrefixExpression(operator, expression.copy(), position) override fun copy() = PrefixExpression(operator, expression.copy(), position)
override fun constValue(program: Program): NumericLiteralValue? { override fun constValue(program: Program): NumericLiteralValue? {
val constval = expression.constValue(program) ?: return null val constval = expression.constValue(program) ?: return null
return when(operator) { val converted = when(operator) {
"+" -> constval "+" -> constval
"-" -> when (constval.type) { "-" -> when (constval.type) {
in IntegerDatatypes -> NumericLiteralValue.optimalInteger(-constval.number.toInt(), constval.position) in IntegerDatatypes -> NumericLiteralValue.optimalInteger(-constval.number.toInt(), constval.position)
@ -113,6 +113,12 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
"not" -> NumericLiteralValue.fromBoolean(constval.number == 0.0, constval.position) "not" -> NumericLiteralValue.fromBoolean(constval.number == 0.0, constval.position)
else -> throw FatalAstException("invalid operator") else -> throw FatalAstException("invalid operator")
} }
return if(converted==null)
null
else {
converted.linkParents(this.parent)
converted
}
} }
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
@ -340,8 +346,11 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
override fun constValue(program: Program): NumericLiteralValue? { override fun constValue(program: Program): NumericLiteralValue? {
val cv = expression.constValue(program) ?: return null val cv = expression.constValue(program) ?: return null
val cast = cv.cast(type) val cast = cv.cast(type)
return if(cast.isValid) return if(cast.isValid) {
cast.valueOrZero() val newval = cast.valueOrZero()
newval.linkParents(parent)
return newval
}
else else
null null
} }

View File

@ -725,7 +725,7 @@ class TestProg8Parser: FunSpec( {
} }
xtest("assignment isAugmented correctness") { test("assignment isAugmented correctness") {
val src = SourceCode.Text(""" val src = SourceCode.Text("""
main { main {
sub start() { sub start() {