improve error reporting from string encoders

This commit is contained in:
Irmen de Jong 2022-01-19 01:27:28 +01:00
parent 6b02f2eea0
commit 674295e800
8 changed files with 73 additions and 52 deletions

View File

@ -16,7 +16,7 @@ import prog8.compilerinterface.ICompilationTarget
object C128Target: ICompilationTarget {
override val name = "c128"
override val machine = C128MachineDefinition()
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
override fun encodeString(str: String, encoding: Encoding): List<UByte> { // TODO use Result
val coded = when(encoding) {
Encoding.PETSCII -> Petscii.encodePetscii(str, true)
Encoding.SCREENCODES -> Petscii.encodeScreencode(str, true)
@ -27,12 +27,16 @@ object C128Target: ICompilationTarget {
success = { it }
)
}
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
return when(encoding) {
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String { // TODO use Result
val decoded = when(encoding) {
Encoding.PETSCII -> Petscii.decodePetscii(bytes, true)
Encoding.SCREENCODES -> Petscii.decodeScreencode(bytes, true)
else -> throw FatalAstException("unsupported encoding $encoding")
}
return decoded.fold(
failure = { throw it },
success = { it }
)
}
override fun asmsubArgsEvalOrder(sub: Subroutine): List<Int> =

View File

@ -16,7 +16,7 @@ import prog8.compilerinterface.ICompilationTarget
object C64Target: ICompilationTarget {
override val name = "c64"
override val machine = C64MachineDefinition()
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
override fun encodeString(str: String, encoding: Encoding): List<UByte> { // TODO use Result
val coded = when(encoding) {
Encoding.PETSCII -> Petscii.encodePetscii(str, true)
Encoding.SCREENCODES -> Petscii.encodeScreencode(str, true)
@ -27,12 +27,16 @@ object C64Target: ICompilationTarget {
success = { it }
)
}
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
return when(encoding) {
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String { // TODO use Result
val decoded = when(encoding) {
Encoding.PETSCII -> Petscii.decodePetscii(bytes, true)
Encoding.SCREENCODES -> Petscii.decodeScreencode(bytes, true)
else -> throw FatalAstException("unsupported encoding $encoding")
}
return decoded.fold(
failure = { throw it },
success = { it }
)
}

View File

@ -17,7 +17,7 @@ import prog8.compilerinterface.ICompilationTarget
object Cx16Target: ICompilationTarget {
override val name = "cx16"
override val machine = CX16MachineDefinition()
override fun encodeString(str: String, encoding: Encoding): List<UByte> {
override fun encodeString(str: String, encoding: Encoding): List<UByte> { // TODO use Result
val coded = when(encoding) {
Encoding.PETSCII -> Petscii.encodePetscii(str, true)
Encoding.SCREENCODES -> Petscii.encodeScreencode(str, true)
@ -29,13 +29,17 @@ object Cx16Target: ICompilationTarget {
success = { it }
)
}
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String {
return when(encoding) {
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String { // TODO use Result
val decoded = when(encoding) {
Encoding.PETSCII -> Petscii.decodePetscii(bytes, true)
Encoding.SCREENCODES -> Petscii.decodeScreencode(bytes, true)
Encoding.ISO -> IsoEncoding.decode(bytes)
else -> throw FatalAstException("unsupported encoding $encoding")
}
return decoded.fold(
failure = { throw it },
success = { it }
)
}

View File

@ -14,8 +14,11 @@ object IsoEncoding {
}
}
fun decode(bytes: List<UByte>): String {
// TODO use Result
return String(bytes.map { it.toByte() }.toByteArray(), Charsets.ISO_8859_1)
fun decode(bytes: List<UByte>): Result<String, CharConversionException> {
return try {
Ok(String(bytes.map { it.toByte() }.toByteArray(), Charsets.ISO_8859_1))
} catch (ce: CharConversionException) {
Err(ce)
}
}
}

View File

@ -1095,13 +1095,17 @@ object Petscii {
}
}
fun decodePetscii(petscii: Iterable<UByte>, lowercase: Boolean = false): String {
return petscii.map {
val code = it.toInt()
if(code<0 || code>= decodingPetsciiLowercase.size)
throw CharConversionException("petscii $code out of range 0..${decodingPetsciiLowercase.size-1}") // TODO don't throw, use Result
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
}.joinToString("")
fun decodePetscii(petscii: Iterable<UByte>, lowercase: Boolean = false): Result<String, CharConversionException> {
return try {
Ok(petscii.map {
val code = it.toInt()
if(code<0 || code>= decodingPetsciiLowercase.size)
throw CharConversionException("petscii $code out of range 0..${decodingPetsciiLowercase.size-1}")
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
}.joinToString(""))
} catch(ce: CharConversionException) {
return Err(ce)
}
}
fun encodeScreencode(text: String, lowercase: Boolean = false): Result<List<UByte>, CharConversionException> {
@ -1134,13 +1138,17 @@ object Petscii {
}
}
fun decodeScreencode(screencode: Iterable<UByte>, lowercase: Boolean = false): String {
return screencode.map {
val code = it.toInt()
if(code<0 || code>= decodingScreencodeLowercase.size)
throw CharConversionException("screencode $code out of range 0..${decodingScreencodeLowercase.size-1}") // TODO don't throw, use Result
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
}.joinToString("")
fun decodeScreencode(screencode: Iterable<UByte>, lowercase: Boolean = false): Result<String, CharConversionException> {
return try {
Ok(screencode.map {
val code = it.toInt()
if(code<0 || code>= decodingScreencodeLowercase.size)
throw CharConversionException("screencode $code out of range 0..${decodingScreencodeLowercase.size-1}")
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
}.joinToString(""))
} catch(ce: CharConversionException) {
Err(ce)
}
}
fun petscii2scr(petscii_code: UByte, inverseVideo: Boolean): Result<UByte, CharConversionException> {

View File

@ -16,8 +16,8 @@ class TestStringEncodings: FunSpec({
test("testZero") {
Petscii.encodePetscii("\u0000", true) shouldBe Ok(listOf<UByte>(0u))
Petscii.encodePetscii("\u0000", false) shouldBe Ok(listOf<UByte>(0u))
Petscii.decodePetscii(listOf(0u), true) shouldBe "\u0000"
Petscii.decodePetscii(listOf(0u), false) shouldBe "\u0000"
Petscii.decodePetscii(listOf(0u), true) shouldBe Ok("\u0000")
Petscii.decodePetscii(listOf(0u), false) shouldBe Ok("\u0000")
}
test("testLowercase") {
@ -30,7 +30,7 @@ class TestStringEncodings: FunSpec({
Petscii.encodePetscii("", true) shouldBe Ok(listOf<UByte>(0xd3u))
}
Petscii.decodePetscii(listOf(72u, 0xd7u, 0x5cu, 0xfau, 0x12u), true) shouldBe "hW£✓\uF11A"
Petscii.decodePetscii(listOf(72u, 0xd7u, 0x5cu, 0xfau, 0x12u), true) shouldBe Ok("hW£✓\uF11A")
}
test("testUppercase") {
@ -43,7 +43,7 @@ class TestStringEncodings: FunSpec({
Petscii.encodePetscii("") shouldBe Ok(listOf<UByte>(250u))
}
Petscii.decodePetscii(listOf(72u, 0x5cu, 0xd3u, 0xffu)) shouldBe "H£♥π"
Petscii.decodePetscii(listOf(72u, 0x5cu, 0xd3u, 0xffu)) shouldBe Ok("H£♥π")
}
test("testScreencodeLowercase") {
@ -55,7 +55,7 @@ class TestStringEncodings: FunSpec({
Petscii.encodeScreencode("π", true) shouldBe Ok(listOf<UByte>(94u))
}
Petscii.decodeScreencode(listOf(0x08u, 0x57u, 0x1cu, 0x7au), true) shouldBe "hW£✓"
Petscii.decodeScreencode(listOf(0x08u, 0x57u, 0x1cu, 0x7au), true) shouldBe Ok("hW£✓")
}
test("testScreencodeUppercase") {
@ -69,7 +69,7 @@ class TestStringEncodings: FunSpec({
Petscii.encodeScreencode("") shouldBe Ok(listOf<UByte>(122u))
}
Petscii.decodeScreencode(listOf(0x17u, 0x1cu, 0x53u, 0x5eu)) shouldBe "W£♥π"
Petscii.decodeScreencode(listOf(0x17u, 0x1cu, 0x53u, 0x5eu)) shouldBe Ok("W£♥π")
}
test("testErrorCases") {
@ -154,24 +154,24 @@ class TestStringEncodings: FunSpec({
test("testBoxDrawingCharsDecoding") {
// ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL
Petscii.decodePetscii(listOf(195u), false).single() shouldBe '\uf13b' //"BOX DRAWINGS LIGHT HORIZONTAL ONE EIGHTH UP (CUS)"
Petscii.decodePetscii(listOf(195u), true).single() shouldBe 'C'
Petscii.decodePetscii(listOf(192u), false).single() shouldBe '─'
Petscii.decodePetscii(listOf(192u), true).single() shouldBe '─'
Petscii.decodeScreencode(listOf(67u), false).single() shouldBe '\uf13b' //"BOX DRAWINGS LIGHT HORIZONTAL ONE EIGHTH UP (CUS)"
Petscii.decodeScreencode(listOf(67u), true).single() shouldBe 'C'
Petscii.decodeScreencode(listOf(64u), false).single() shouldBe '─'
Petscii.decodeScreencode(listOf(64u), true).single() shouldBe '─'
Petscii.decodePetscii(listOf(195u), false).getOrElse { throw it }.single() shouldBe '\uf13b' //"BOX DRAWINGS LIGHT HORIZONTAL ONE EIGHTH UP (CUS)"
Petscii.decodePetscii(listOf(195u), true).getOrElse { throw it }.single() shouldBe 'C'
Petscii.decodePetscii(listOf(192u), false).getOrElse { throw it }.single() shouldBe '─'
Petscii.decodePetscii(listOf(192u), true).getOrElse { throw it }.single() shouldBe '─'
Petscii.decodeScreencode(listOf(67u), false).getOrElse { throw it }.single() shouldBe '\uf13b' //"BOX DRAWINGS LIGHT HORIZONTAL ONE EIGHTH UP (CUS)"
Petscii.decodeScreencode(listOf(67u), true).getOrElse { throw it }.single() shouldBe 'C'
Petscii.decodeScreencode(listOf(64u), false).getOrElse { throw it }.single() shouldBe '─'
Petscii.decodeScreencode(listOf(64u), true).getOrElse { throw it }.single() shouldBe '─'
// │ 0x62 -> BOX DRAWINGS LIGHT VERTICAL
Petscii.decodePetscii(listOf(125u), false).single() shouldBe '│'
Petscii.decodePetscii(listOf(125u), true).single() shouldBe '│'
Petscii.decodePetscii(listOf(221u), false).single() shouldBe '│'
Petscii.decodePetscii(listOf(221u), true).single() shouldBe '│'
Petscii.decodeScreencode(listOf(93u), false).single() shouldBe '│'
Petscii.decodeScreencode(listOf(93u), true).single() shouldBe '│'
Petscii.decodeScreencode(listOf(66u), false).single() shouldBe '\uf13c' // "BOX DRAWINGS LIGHT VERTICAL ONE EIGHTH LEFT (CUS)"
Petscii.decodeScreencode(listOf(66u), true).single() shouldBe 'B'
Petscii.decodePetscii(listOf(125u), false).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodePetscii(listOf(125u), true).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodePetscii(listOf(221u), false).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodePetscii(listOf(221u), true).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodeScreencode(listOf(93u), false).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodeScreencode(listOf(93u), true).getOrElse { throw it }.single() shouldBe '│'
Petscii.decodeScreencode(listOf(66u), false).getOrElse { throw it }.single() shouldBe '\uf13c' // "BOX DRAWINGS LIGHT VERTICAL ONE EIGHTH LEFT (CUS)"
Petscii.decodeScreencode(listOf(66u), true).getOrElse { throw it }.single() shouldBe 'B'
}
}

View File

@ -10,8 +10,8 @@ import prog8.ast.statements.Subroutine
interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String
val machine: IMachineDefinition
override fun encodeString(str: String, encoding: Encoding): List<UByte>
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String
override fun encodeString(str: String, encoding: Encoding): List<UByte> // TODO use Result
override fun decodeString(bytes: List<UByte>, encoding: Encoding): String // TODO use Result
fun asmsubArgsEvalOrder(sub: Subroutine): List<Int>
fun asmsubArgsHaveRegisterClobberRisk(args: List<Expression>,

View File

@ -4,8 +4,6 @@ TODO
For next compiler release (7.7)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- document new string encoding syntax
- fix petscii decode methods that still throw an exception rather than Result
Need help with