mirror of
https://github.com/irmen/prog8.git
synced 2025-02-13 18:31:04 +00:00
fix crash when initializing string variable with a non-string value
This commit is contained in:
parent
cd2cc89e6a
commit
c7f0ff11ac
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
}
|
||||
})
|
||||
|
@ -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?
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user