mirror of
https://github.com/irmen/prog8.git
synced 2025-11-01 22:16:16 +00:00
better error when trying to use a const pointer (which is not supported yet)
This commit is contained in:
@@ -938,7 +938,7 @@ internal class ProgramAndVarsGen(
|
|||||||
asmgen.out(" ${it.name} = ${it.address.toHex()}")
|
asmgen.out(" ${it.name} = ${it.address.toHex()}")
|
||||||
}
|
}
|
||||||
consts.sortedBy { it.name }.forEach {
|
consts.sortedBy { it.name }.forEach {
|
||||||
if(it.dt==BaseDataType.FLOAT)
|
if(it.dt.isFloat)
|
||||||
asmgen.out(" ${it.name} = ${it.value}")
|
asmgen.out(" ${it.name} = ${it.value}")
|
||||||
else
|
else
|
||||||
asmgen.out(" ${it.name} = ${it.value.toHex()}")
|
asmgen.out(" ${it.name} = ${it.value.toHex()}")
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ private fun convert(variable: StMemVar): IRStMemVar {
|
|||||||
|
|
||||||
|
|
||||||
private fun convert(constant: StConstant): IRStConstant {
|
private fun convert(constant: StConstant): IRStConstant {
|
||||||
val dt = DataType.forDt(constant.dt)
|
|
||||||
val scopedName = if('.' in constant.name) {
|
val scopedName = if('.' in constant.name) {
|
||||||
constant.name
|
constant.name
|
||||||
} else {
|
} else {
|
||||||
@@ -132,7 +131,7 @@ private fun convert(constant: StConstant): IRStConstant {
|
|||||||
constant.name
|
constant.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IRStConstant(scopedName, dt, constant.value)
|
return IRStConstant(scopedName, constant.dt, constant.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -874,9 +874,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
err("recursive var declaration")
|
err("recursive var declaration")
|
||||||
|
|
||||||
// CONST can only occur on simple types (byte, word, float)
|
// CONST can only occur on simple types (byte, word, float)
|
||||||
if(decl.type== VarDeclType.CONST) {
|
if(decl.type==VarDeclType.CONST) {
|
||||||
if (!decl.datatype.isNumericOrBool)
|
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?
|
// FLOATS enabled?
|
||||||
|
|||||||
@@ -27,45 +27,46 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
|||||||
if(valueType.isUnknown)
|
if(valueType.isUnknown)
|
||||||
return noModifications
|
return noModifications
|
||||||
val valueDt = valueType.getOrUndef()
|
val valueDt = valueType.getOrUndef()
|
||||||
when(decl.type) {
|
if(!(valueDt.isWord && decl.datatype.isPointer)) {
|
||||||
VarDeclType.VAR -> {
|
when(decl.type) {
|
||||||
if(decl.isArray) {
|
VarDeclType.VAR -> {
|
||||||
// using a array of words as initializer to a pointer array is fine
|
if(decl.isArray) {
|
||||||
if (!valueDt.isSplitWordArray || !decl.datatype.isPointerArray)
|
// using a array of words as initializer to a pointer array is fine
|
||||||
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
|
if (!valueDt.isSplitWordArray || !decl.datatype.isPointerArray)
|
||||||
} else if(!decl.datatype.isString) {
|
errors.err("value has incompatible type ($valueType) for the variable (${decl.datatype})", decl.value!!.position)
|
||||||
if (valueDt.largerSizeThan(decl.datatype)) {
|
} else if(!decl.datatype.isString) {
|
||||||
val constValue = decl.value?.constValue(program)
|
if (valueDt.largerSizeThan(decl.datatype)) {
|
||||||
if (constValue != null)
|
val constValue = decl.value?.constValue(program)
|
||||||
errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position)
|
if (constValue != null)
|
||||||
else
|
errors.err("value '$constValue' out of range for ${decl.datatype}", constValue.position)
|
||||||
errors.err("value out of range for ${decl.datatype}", decl.value!!.position)
|
else
|
||||||
|
errors.err("value out of range for ${decl.datatype}", decl.value!!.position)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
VarDeclType.CONST -> {
|
||||||
VarDeclType.CONST -> {
|
// change the vardecl type itself as well, but only if new type is smaller
|
||||||
// change the vardecl type itself as well, but only if new type is smaller
|
if(valueDt.largerSizeThan(decl.datatype)) {
|
||||||
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))
|
|
||||||
{
|
|
||||||
val constValue = decl.value!!.constValue(program)!!
|
val constValue = decl.value!!.constValue(program)!!
|
||||||
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
|
errors.err("value '${constValue.number}' out of range for ${decl.datatype}", constValue.position)
|
||||||
} else {
|
} else {
|
||||||
val changed = decl.copy(valueDt)
|
// don't make it signed if it was unsigned and vice versa, except when it is a long const declaration
|
||||||
return listOf(IAstModification.ReplaceNode(decl, changed, parent))
|
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
|
// check splitting of word arrays
|
||||||
|
|||||||
@@ -690,20 +690,28 @@ main {
|
|||||||
this.text = next as uword ; TODO fix type error; the cast should succeed
|
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="""
|
val src="""
|
||||||
main {
|
main {
|
||||||
sub start() {
|
sub start() {
|
||||||
^^uword @shared ptr = 7000
|
^^uword @shared ptr = 7000
|
||||||
const ^^uword cptr = 8000 ; TODO fix type error; loses pointer
|
const ^^uword cptr = 8000
|
||||||
ptr^^ = 12345
|
|
||||||
cptr^^ = 12345
|
;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") {
|
test("unknown field") {
|
||||||
|
|||||||
@@ -208,8 +208,8 @@ private fun makeSt(): SymbolTable {
|
|||||||
val sub12 = StNode("sub2", StNodeType.SUBROUTINE, astSub2)
|
val sub12 = StNode("sub2", StNodeType.SUBROUTINE, astSub2)
|
||||||
block1.add(sub11)
|
block1.add(sub11)
|
||||||
block1.add(sub12)
|
block1.add(sub12)
|
||||||
block1.add(StConstant("c1", BaseDataType.UWORD, 12345.0, astConstant1))
|
block1.add(StConstant("c1", DataType.UWORD, 12345.0, astConstant1))
|
||||||
block1.add(StConstant("blockc", BaseDataType.UWORD, 999.0, astConstant2))
|
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("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(StStaticVariable("v2", DataType.BYTE, null, null, null, ZeropageWish.DONTCARE, 0u, false, astSub1v2))
|
||||||
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))
|
sub11.add(StMemVar("v3", DataType.FLOAT, 12345u, null, astSub1v3))
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Future Things and Ideas
|
|||||||
- struct/ptr: optimize the float copying in assignIndexedPointer() (also word and long?)
|
- 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: 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: 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 @nosplit pointer arrays?
|
||||||
- struct/ptr: support pointer to pointer?
|
- struct/ptr: support pointer to pointer?
|
||||||
- struct/ptr: support for typed function pointers? (&routine could be typed by default as well then)
|
- struct/ptr: support for typed function pointers? (&routine could be typed by default as well then)
|
||||||
|
|||||||
149
examples/test.p8
149
examples/test.p8
@@ -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 {
|
main {
|
||||||
|
struct Node1 {
|
||||||
|
ubyte type
|
||||||
|
word ww
|
||||||
|
}
|
||||||
|
struct Node2 {
|
||||||
|
ubyte type
|
||||||
|
^^ubyte text
|
||||||
|
}
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
bytetest()
|
^^Node1 @shared next
|
||||||
wordtest()
|
^^Node2 @shared this
|
||||||
longtest()
|
^^ubyte ubptr
|
||||||
floattest() ; TODO fix invalid 6502 code gen /crash
|
|
||||||
}
|
|
||||||
|
|
||||||
sub bytetest() {
|
ubptr = next as ^^ubyte
|
||||||
ubyte[] foo = [11, 22, 33]
|
ubptr = 12345
|
||||||
ubyte i
|
ubptr = cx16.r0
|
||||||
txt.print("before:")
|
ubptr = next as uword ; TODO fix type error; the cast should succeed
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
sub wordtest() {
|
this.text = next as ^^ubyte
|
||||||
uword[] foo = [1111, 2222, 3333]
|
this.text = 12345
|
||||||
ubyte i
|
this.text = cx16.r0
|
||||||
txt.print("before:")
|
this.text = next as uword ; TODO fix type error; the cast should succeed
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ class IRFileWriter(private val irProgram: IRProgram, outfileOverride: Path?) {
|
|||||||
val value: String = when {
|
val value: String = when {
|
||||||
dt.isBool -> constant.value.toInt().toString()
|
dt.isBool -> constant.value.toInt().toString()
|
||||||
dt.isFloat -> constant.value.toString()
|
dt.isFloat -> constant.value.toString()
|
||||||
|
dt.isPointer -> TODO("constant pointer $constant")
|
||||||
dt.isInteger -> constant.value.toInt().toHex()
|
dt.isInteger -> constant.value.toInt().toHex()
|
||||||
else -> throw InternalCompilerException("weird dt")
|
else -> throw InternalCompilerException("weird dt")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
StNode(name, StNodeType.CONSTANT, astNode)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class SymbolTableMaker(private val program: PtProgram, private val options: Comp
|
|||||||
}
|
}
|
||||||
is PtConstant -> {
|
is PtConstant -> {
|
||||||
require(node.type.isNumericOrBool)
|
require(node.type.isNumericOrBool)
|
||||||
StConstant(node.name, node.type.base, node.value, node)
|
StConstant(node.name, node.type, node.value, node)
|
||||||
}
|
}
|
||||||
is PtLabel -> {
|
is PtLabel -> {
|
||||||
StNode(node.name, StNodeType.LABEL, node)
|
StNode(node.name, StNodeType.LABEL, node)
|
||||||
|
|||||||
Reference in New Issue
Block a user