fix crash when initializing string variable with a non-string value

This commit is contained in:
Irmen de Jong 2025-02-10 02:48:50 +01:00
parent cd2cc89e6a
commit c7f0ff11ac
5 changed files with 46 additions and 61 deletions

View File

@ -820,13 +820,30 @@ internal class AstChecker(private val program: Program,
val eltDt = decl.datatype.elementType()
if(!(iDt istype eltDt))
valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
} else {
} else if(!decl.datatype.isString) {
if(!(iDt.isBool && decl.datatype.isUnsignedByte || iDt issimpletype BaseDataType.UBYTE && decl.datatype.isBool))
valueerr("initialisation value has incompatible type ($iDt) for the variable (${decl.datatype})")
}
}
}
if(decl.datatype.isString) {
if(decl.value==null) {
// complain about uninitialized str, but only if it's a regular variable
val parameter = (decl.parent as? Subroutine)?.parameters?.singleOrNull{ it.name==decl.name }
if(parameter==null)
err("string var must be initialized with a string literal")
}
if(decl.value !is StringLiteral) {
if(decl.type==VarDeclType.MEMORY)
err("strings can't be memory mapped")
else
valueerr("string var must be initialized with a string literal")
}
return
}
// array length limits and constant lenghts
if(decl.isArray) {
@ -883,22 +900,6 @@ internal class AstChecker(private val program: Program,
err("memory mapped word arrays cannot be split, should have @nosplit")
}
if(decl.datatype.isString) {
if(decl.value==null) {
// complain about uninitialized str, but only if it's a regular variable
val parameter = (decl.parent as? Subroutine)?.parameters?.singleOrNull{ it.name==decl.name }
if(parameter==null)
err("string var must be initialized with a string literal")
}
if(decl.value !is StringLiteral) {
if(decl.type==VarDeclType.MEMORY)
err("strings can't be memory mapped")
else
valueerr("string var must be initialized with a string literal")
}
}
if(decl.datatype.isSplitWordArray) {
if (!decl.datatype.isWordArray) {
errors.err("split can only be used on word arrays", decl.position)

View File

@ -38,7 +38,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
if(decl.isArray) {
if(decl.datatype.isSplitWordArray)
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
} else {
} else if(!decl.datatype.isString) {
if (valueDt.largerSizeThan(decl.datatype)) {
val constValue = decl.value?.constValue(program)
if (constValue != null)

View File

@ -460,4 +460,25 @@ main {
errors.errors[0] shouldContain "too few values: expected 3 got 1"
errors.errors[1] shouldContain "too few values: expected 3 got 1"
}
test("correct errors for wrong string initialization value") {
val src="""
main {
sub start() {
str minString1 = 1234
str minString2 = func()
}
sub func() -> str {
return "zz"
}
}"""
val errors = ErrorReporterForTests()
compileText(Cx16Target(), optimize=false, src, writeAssembly=false, errors = errors) shouldBe null
errors.errors.size shouldBe 3
errors.errors[0] shouldContain "type of value uword doesn't match target str"
errors.errors[1] shouldContain "string var must be initialized with a string literal"
errors.errors[2] shouldContain "string var must be initialized with a string literal"
}
})

View File

@ -1,15 +1,6 @@
TODO
====
- fix string concatenation error
uword totalseconds = 3636
uword minutes
uword seconds
divmod(totalseconds, 60 as uword, minutes, seconds)
str minString = conv.str_uw(minutes)
str secString = conv.str_uw(seconds)
txt.print(minString + ":" + secString)
- Make neo and atari targets external via configs? They are very bare bones atm so easier to contribute to if they're configurable externally? What about the pet32 target
- add paypal donation button as well?

View File

@ -1,39 +1,11 @@
%address $A000
%memtop $C000
%output library
%import textio
main {
; Create a jump table as first thing in the library.
; uword[] @shared @nosplit jumptable = [
; ; NOTE: the compiler has inserted a single JMP instruction at the start of the 'main' block, that jumps to the start() routine.
; ; This is convenient because the rest of the jump table simply follows it,
; ; making the first jump neatly be the required initialization routine for the library (initializing variables and BSS region).
; ; btw, $4c = opcode for JMP.
; $4c00, &library.func1,
; $4c00, &library.func2,
; ]
%jmptable (
library.func1,
library.func2,
)
sub start() {
; has to be here for initialization
txt.print("lib initialized\n")
}
}
library {
sub func1() {
txt.print("lib func 1\n")
}
sub func2() {
txt.print("lib func 2\n")
str minString1 = 1234
str minString2 = func()
}
sub func() -> str {
return "zz"
}
}