allow integer range as when choice value

This commit is contained in:
Irmen de Jong
2025-03-17 22:26:27 +01:00
parent f04b97d890
commit 79cda544c8
5 changed files with 82 additions and 26 deletions

View File

@@ -319,4 +319,35 @@ _after:
}
return noModifications
}
override fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> {
// replace a range expression in a when by the actual list of numbers it represents
val values = whenChoice.values
if(values!=null && values.size==1) {
val conditionType = (whenChoice.parent as When).condition.inferType(program)
val intRange = (values[0] as? RangeExpression)?.toConstantIntegerRange()
if(conditionType.isKnown && intRange != null) {
if(intRange.count()>255)
errors.err("values list too long", values[0].position)
else {
val dt = conditionType.getOrUndef().base
val newValues = intRange.map {
val num = NumericLiteral(BaseDataType.LONG, it.toDouble(), values[0].position)
num.linkParents(whenChoice)
val cast = num.cast(dt, true)
if (cast.isValid) cast.valueOrZero() else null
}
if(null !in newValues) {
if(newValues.size>=10)
errors.warn("long list of values, checking will not be very efficient", values[0].position)
values.clear()
for(num in newValues)
values.add(num!!)
}
}
}
}
return noModifications
}
}

View File

@@ -4,6 +4,7 @@ import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
import io.kotest.engine.spec.tempdir
import io.kotest.matchers.comparables.shouldBeGreaterThan
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import io.kotest.matchers.string.shouldContain
@@ -684,6 +685,40 @@ main
errors.errors[0] shouldContain "use if"
}
test("when on range expressions is ok") {
val src="""
main {
sub start() {
when cx16.r0L {
21 to 29 step 2 -> cx16.r1L++
else -> cx16.r1L--
}
}
}"""
compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false).shouldNotBeNull()
}
test("when on range expressions outside value datatype is error") {
val src="""
main {
sub start() {
when cx16.r0L {
300 to 400 -> cx16.r1L++
else -> cx16.r1L--
}
}
}"""
val errors = ErrorReporterForTests()
compileText(VMTarget(), optimize=false, src, outputDir, writeAssembly=false, errors = errors) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain "values must be constant numbers"
}
test("sizeof number const evaluation in vardecl") {
val src="""
main {