From a684ea46e4015065b70bc82d0744e875ab274c8c Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 29 Sep 2023 01:15:54 +0200 Subject: [PATCH] fix c64 zp test and improve error for text encoding problem --- .../prog8/code/target/cbm/PetsciiEncoding.kt | 10 ++++- .../compiler/astprocessing/AstExtensions.kt | 34 ++++++++++++--- compiler/test/TestZeropage.kt | 12 +++--- examples/test.p8 | 41 +------------------ 4 files changed, 44 insertions(+), 53 deletions(-) diff --git a/codeCore/src/prog8/code/target/cbm/PetsciiEncoding.kt b/codeCore/src/prog8/code/target/cbm/PetsciiEncoding.kt index 0a260850d..aed34febd 100644 --- a/codeCore/src/prog8/code/target/cbm/PetsciiEncoding.kt +++ b/codeCore/src/prog8/code/target/cbm/PetsciiEncoding.kt @@ -1076,7 +1076,10 @@ object PetsciiEncoding { } else -> { val case = if (lowercase) "lower" else "upper" - throw CharConversionException("no ${case}Petscii character for '${chr}' (${chr.code})") + if(chr.isISOControl()) + throw CharConversionException("no ${case}Petscii character for char #${chr.code}") + else + throw CharConversionException("no ${case}Petscii character for char #${chr.code} '${chr}'") } } } @@ -1119,7 +1122,10 @@ object PetsciiEncoding { } else -> { val case = if (lowercase) "lower" else "upper" - throw CharConversionException("no ${case}Screencode character for '${chr}' (${chr.code})") + if(chr.isISOControl()) + throw CharConversionException("no ${case}Screencode character for char #${chr.code}") + else + throw CharConversionException("no ${case}Screencode character for char #${chr.code} '${chr}'") } } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index e19074576..e0a4158d3 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -5,10 +5,12 @@ import prog8.ast.Program import prog8.ast.expressions.CharLiteral import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteral +import prog8.ast.expressions.StringLiteral import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstModification import prog8.code.core.* +import java.io.CharConversionException internal fun Program.checkValid(errors: IErrorReporter, compilerOptions: CompilationOptions) { @@ -63,13 +65,35 @@ internal fun Program.charLiteralsToUByteLiterals(target: ICompilationTarget, err errors.err("compilation target doesn't support this text encoding", char.position) return noModifications } - return listOf(IAstModification.ReplaceNode( - char, - NumericLiteral(DataType.UBYTE, target.encodeString(char.value.toString(), char.encoding)[0].toDouble(), char.position), - parent - )) + return try { + val encoded = target.encodeString(char.value.toString(), char.encoding) + listOf(IAstModification.ReplaceNode( + char, + NumericLiteral(DataType.UBYTE, encoded[0].toDouble(), char.position), + parent + )) + } catch (x: CharConversionException) { + errors.err(x.message ?: "can't encode character", char.position) + noModifications + } + } + + override fun after(string: StringLiteral, parent: Node): Iterable { + // this only *checks* for errors for string encoding. The actual encoding is done much later + require(string.encoding != Encoding.DEFAULT) + if(string.encoding != Encoding.DEFAULT && string.encoding !in target.supportedEncodings) { + errors.err("compilation target doesn't support this text encoding", string.position) + return noModifications + } + try { + target.encodeString(string.value, string.encoding) + } catch (x: CharConversionException) { + errors.err(x.message ?: "can't encode string", string.position) + } + return noModifications } } + walker.visit(this) walker.applyModifications() } diff --git a/compiler/test/TestZeropage.kt b/compiler/test/TestZeropage.kt index 5325ad795..b971e598f 100644 --- a/compiler/test/TestZeropage.kt +++ b/compiler/test/TestZeropage.kt @@ -118,11 +118,11 @@ class TestC64Zeropage: FunSpec({ test("testFreeSpacesBytes") { val zp1 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) - zp1.availableBytes() shouldBe 18 + zp1.availableBytes() shouldBe 17 val zp2 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FLOATSAFE, emptyList(), false, false, c64target, 999u)) - zp2.availableBytes() shouldBe 88 + zp2.availableBytes() shouldBe 87 val zp3 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.KERNALSAFE, emptyList(), false, false, c64target, 999u)) - zp3.availableBytes() shouldBe 97 + zp3.availableBytes() shouldBe 96 val zp4 = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.FULL, emptyList(), false, false, c64target, 999u)) zp4.availableBytes() shouldBe 207 zp4.allocate("test", DataType.UBYTE, null, null, errors) @@ -162,7 +162,7 @@ class TestC64Zeropage: FunSpec({ test("testBasicsafeAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) - zp.availableBytes() shouldBe 18 + zp.availableBytes() shouldBe 17 zp.hasByteAvailable() shouldBe true zp.hasWordAvailable() shouldBe true @@ -215,18 +215,18 @@ class TestC64Zeropage: FunSpec({ test("testEfficientAllocation") { val zp = C64Zeropage(CompilationOptions(OutputType.RAW, CbmPrgLauncherType.NONE, ZeropageType.BASICSAFE, emptyList(), true, false, c64target, 999u)) - zp.availableBytes() shouldBe 18 + zp.availableBytes() shouldBe 17 zp.allocate("", DataType.WORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x04u zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x06u zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0au zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9bu zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0x9eu - zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xa5u zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xb0u zp.allocate("", DataType.UWORD, null, null, errors).getOrElse{throw it}.address shouldBe 0xbeu zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x0eu zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x92u zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0x96u + zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xa6u zp.allocate("", DataType.UBYTE, null, null, errors).getOrElse{throw it}.address shouldBe 0xf9u zp.availableBytes() shouldBe 0 } diff --git a/examples/test.p8 b/examples/test.p8 index 216f17f09..26d3154a5 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,51 +7,12 @@ main { sub start() { - txt.print("\\r=") + txt.print("petscii \\r=") txt.print_ub('\r') txt.print(" and \\n=") txt.print_ub('\n') txt.nl() - ubyte[256] buf - - void diskio.delete("lines.txt") - if diskio.f_open_w("@:lines.txt") { - txt.print("writing...\n") - repeat 10 { - if not diskio.f_write("line\r", 5) { - diskio.f_close_w() - txt.print("write error\n") - break - } - } - diskio.f_close_w() - } - txt.print("\nwritten.\n\n") - - if diskio.f_open("lines.txt") { - txt.print("reading...\n") - repeat { - if diskio.f_readline(buf)==0 { - diskio.f_close() - txt.print("readline is 0\n") - break - } - if cbm.READST() { - txt.print(diskio.status()) - diskio.f_close() - break - } - txt.print(buf) - txt.nl() - } - diskio.f_close() - } else { - txt.print(diskio.status()) - } - - txt.print("\ndone.\n") - ; txt.print_uw(math.mul16_last_upper()) ; txt.nl() ; uword value1=5678