better error when trying to use a const pointer (which is not supported yet)

This commit is contained in:
Irmen de Jong
2025-10-30 20:58:21 +01:00
parent fc8727f81e
commit b1e07f3fdb
11 changed files with 75 additions and 174 deletions

View File

@@ -938,7 +938,7 @@ internal class ProgramAndVarsGen(
asmgen.out(" ${it.name} = ${it.address.toHex()}")
}
consts.sortedBy { it.name }.forEach {
if(it.dt==BaseDataType.FLOAT)
if(it.dt.isFloat)
asmgen.out(" ${it.name} = ${it.value}")
else
asmgen.out(" ${it.name} = ${it.value.toHex()}")

View File

@@ -122,7 +122,6 @@ private fun convert(variable: StMemVar): IRStMemVar {
private fun convert(constant: StConstant): IRStConstant {
val dt = DataType.forDt(constant.dt)
val scopedName = if('.' in constant.name) {
constant.name
} else {
@@ -132,7 +131,7 @@ private fun convert(constant: StConstant): IRStConstant {
constant.name
}
}
return IRStConstant(scopedName, dt, constant.value)
return IRStConstant(scopedName, constant.dt, constant.value)
}

View File

@@ -874,9 +874,9 @@ internal class AstChecker(private val program: Program,
err("recursive var declaration")
// CONST can only occur on simple types (byte, word, float)
if(decl.type== VarDeclType.CONST) {
if(decl.type==VarDeclType.CONST) {
if (!decl.datatype.isNumericOrBool)
err("const can only be used on numeric types or booleans")
err("const can only be used on numbers and booleans")
}
// FLOATS enabled?

View File

@@ -27,45 +27,46 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
if(valueType.isUnknown)
return noModifications
val valueDt = valueType.getOrUndef()
when(decl.type) {
VarDeclType.VAR -> {
if(decl.isArray) {
// using a array of words as initializer to a pointer array is fine
if (!valueDt.isSplitWordArray || !decl.datatype.isPointerArray)
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
} else if(!decl.datatype.isString) {
if (valueDt.largerSizeThan(decl.datatype)) {
val constValue = decl.value?.constValue(program)
if (constValue != null)
errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position)
else
errors.err("value out of range for ${decl.datatype}", decl.value!!.position)
if(!(valueDt.isWord && decl.datatype.isPointer)) {
when(decl.type) {
VarDeclType.VAR -> {
if(decl.isArray) {
// using a array of words as initializer to a pointer array is fine
if (!valueDt.isSplitWordArray || !decl.datatype.isPointerArray)
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
} else if(!decl.datatype.isString) {
if (valueDt.largerSizeThan(decl.datatype)) {
val constValue = decl.value?.constValue(program)
if (constValue != null)
errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position)
else
errors.err("value out of range for ${decl.datatype}", decl.value!!.position)
}
}
}
}
VarDeclType.CONST -> {
// change the vardecl type itself as well, but only if new type is smaller
if(valueDt.largerSizeThan(decl.datatype)) {
val constValue = decl.value!!.constValue(program)!!
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
} else {
// don't make it signed if it was unsigned and vice versa, except when it is a long const declaration
if(!decl.datatype.isLong &&
(valueDt.isSigned && decl.datatype.isUnsigned ||
valueDt.isUnsigned && decl.datatype.isSigned))
{
VarDeclType.CONST -> {
// change the vardecl type itself as well, but only if new type is smaller
if(valueDt.largerSizeThan(decl.datatype)) {
val constValue = decl.value!!.constValue(program)!!
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
} else {
val changed = decl.copy(valueDt)
return listOf(IAstModification.ReplaceNode(decl, changed, parent))
// don't make it signed if it was unsigned and vice versa, except when it is a long const declaration
if(!decl.datatype.isLong &&
(valueDt.isSigned && decl.datatype.isUnsigned ||
valueDt.isUnsigned && decl.datatype.isSigned))
{
val constValue = decl.value!!.constValue(program)!!
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
} else {
val changed = decl.copy(valueDt)
return listOf(IAstModification.ReplaceNode(decl, changed, parent))
}
}
}
VarDeclType.MEMORY -> if(!valueType.isWords && !valueType.isBytes)
throw FatalAstException("value type for a memory var should be word or byte (address)")
}
VarDeclType.MEMORY -> if(!valueType.isWords && !valueType.isBytes)
throw FatalAstException("value type for a memory var should be word or byte (address)")
}
}
// check splitting of word arrays

View File

@@ -690,20 +690,28 @@ main {
this.text = next as uword ; TODO fix type error; the cast should succeed
}
}"""
compileText(VMTarget(), false, src, outputDir, writeAssembly = false) shouldNotBe null
compileText(VMTarget(), false, src, outputDir) shouldNotBe null
compileText(C64Target(), false, src, outputDir) shouldNotBe null
}
xtest("const pointer") {
test("const pointer gives proper error") {
val src="""
main {
sub start() {
^^uword @shared ptr = 7000
const ^^uword cptr = 8000 ; TODO fix type error; loses pointer
ptr^^ = 12345
cptr^^ = 12345
const ^^uword cptr = 8000
;ptr^^ = 12345
;cptr^^ = 12345
cx16.r0 = cptr
cx16.r1 = ptr
}
}"""
compileText(VMTarget(), false, src, outputDir, writeAssembly = false) shouldNotBe null
val errors = ErrorReporterForTests()
compileText(VMTarget(), false, src, outputDir, errors=errors, writeAssembly = true) shouldBe null
errors.errors.size shouldBe 1
errors.errors[0] shouldContain("const can only be used on numbers and booleans")
}
test("unknown field") {

View File

@@ -208,8 +208,8 @@ private fun makeSt(): SymbolTable {
val sub12 = StNode("sub2", StNodeType.SUBROUTINE, astSub2)
block1.add(sub11)
block1.add(sub12)
block1.add(StConstant("c1", BaseDataType.UWORD, 12345.0, astConstant1))
block1.add(StConstant("blockc", BaseDataType.UWORD, 999.0, astConstant2))
block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1))
block1.add(StConstant("blockc", DataType.UWORD, 999.0, astConstant2))
sub11.add(StStaticVariable("v1", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub1v1))
sub11.add(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub1v2))
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))

View File

@@ -13,6 +13,7 @@ Future Things and Ideas
- struct/ptr: optimize the float copying in assignIndexedPointer() (also word and long?)
- struct/ptr: optimize augmented assignments to indexed pointer targets like sprptr[2]^^.y++ (these are now not performend in-place but as a regular assignment)
- struct/ptr: implement even more struct instance assignments (via memcopy) in CodeDesugarer (see the TODO) (add to documentation as well, paragraph 'Structs')
- struct/ptr: support const pointers (simple and struct types)
- struct/ptr: support @nosplit pointer arrays?
- struct/ptr: support pointer to pointer?
- struct/ptr: support for typed function pointers? (&routine could be typed by default as well then)

View File

@@ -1,135 +1,26 @@
;%zeropage basicsafe
;%import textio
;
;main {
; sub start() {
; ^^uword @shared ptr = 7000
; const ^^uword cptr = 8000 ; TODO fix type error; loses pointer
; ptr^^ = 12345
; cptr^^ = 12345
; txt.print_uw(peekw(7000))
; txt.spc()
; txt.print_uw(peekw(8000))
; }
;}
; TYPE CAST CRASH:
;%zeropage basicsafe
;%import strings
;%import textio
;
;main {
; struct Line {
; ^^Line prev
; ^^Line next
; ^^ubyte text
; }
; uword buffer = memory("buffer", 100*sizeof(Line), 1)
; ^^Line next = buffer
;
; sub start() {
; ^^Line line = next
; next += 1
; line.text = next as ^^ubyte ; TODO fix crash here
; next = (next as uword) + 81
; txt.print_uwhex(buffer, true) txt.nl()
; txt.print_uwhex(next, true) txt.nl()
; txt.print_uwhex(line, true) txt.nl()
; txt.print_uwhex(line.text, true) txt.nl()
; }
;}
%import floats
%import textio
%zeropage basicsafe
main {
struct Node1 {
ubyte type
word ww
}
struct Node2 {
ubyte type
^^ubyte text
}
sub start() {
bytetest()
wordtest()
longtest()
floattest() ; TODO fix invalid 6502 code gen /crash
}
^^Node1 @shared next
^^Node2 @shared this
^^ubyte ubptr
sub bytetest() {
ubyte[] foo = [11, 22, 33]
ubyte i
txt.print("before:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_ub(foo[i])
}
txt.nl()
foo[2] = foo[1]
foo[1] = foo[0]
foo[0] = 0
txt.print(" after:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_ub(foo[i])
}
txt.nl()
}
ubptr = next as ^^ubyte
ubptr = 12345
ubptr = cx16.r0
ubptr = next as uword ; TODO fix type error; the cast should succeed
sub wordtest() {
uword[] foo = [1111, 2222, 3333]
ubyte i
txt.print("before:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_uw(foo[i])
}
txt.nl()
foo[2] = foo[1]
foo[1] = foo[0]
foo[0] = 0
txt.print(" after:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_uw(foo[i])
}
txt.nl()
}
sub longtest() {
long[] foo = [111111, 222222, 333333]
ubyte i
txt.print("before:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_l(foo[i])
}
txt.nl()
foo[2] = foo[1]
foo[1] = foo[0]
foo[0] = 0
txt.print(" after:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_l(foo[i])
}
txt.nl()
}
sub floattest() {
float[] foo = [1.1, 2.2, 3.3]
ubyte i
txt.print("before:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_f(foo[i])
}
txt.nl()
foo[2] = foo[1]
foo[1] = foo[0]
foo[0] = 0
txt.print(" after:")
for i in 0 to 2 {
txt.chrout(' ')
txt.print_f(foo[i])
}
txt.nl()
this.text = next as ^^ubyte
this.text = 12345
this.text = cx16.r0
this.text = next as uword ; TODO fix type error; the cast should succeed
}
}

View File

@@ -270,6 +270,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
val value: String = when {
dt.isBool -> constant.value.toInt().toString()
dt.isFloat -> constant.value.toString()
dt.isPointer -> TODO("constant pointer $constant")
dt.isInteger -> constant.value.toInt().toHex()
else -> throw InternalCompilerException("weird dt")
}

View File

@@ -267,7 +267,7 @@ class StStaticVariable(name: String,
}
class StConstant(name: String, val dt: BaseDataType, val value: Double, astNode: PtNode?) :
class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode?) :
StNode(name, StNodeType.CONSTANT, astNode)

View File

@@ -48,7 +48,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
}
is PtConstant -> {
require(node.type.isNumericOrBool)
StConstant(node.name, node.type.base, node.value, node)
StConstant(node.name, node.type, node.value, node)
}
is PtLabel -> {
StNode(node.name, StNodeType.LABEL, node)