mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 19:29:50 +00:00
(7.2) cleanup Petscii converter errorhandling, add unit tests for error scenarios
This commit is contained in:
parent
dd5abae721
commit
4d5094a517
@ -4,9 +4,6 @@ import com.github.michaelbull.result.fold
|
|||||||
import prog8.ast.IMemSizer
|
import prog8.ast.IMemSizer
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
import prog8.ast.expressions.IdentifierReference
|
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
|
||||||
import prog8.ast.statements.AssignTarget
|
|
||||||
import prog8.compiler.CompilationOptions
|
import prog8.compiler.CompilationOptions
|
||||||
import prog8.compiler.IErrorReporter
|
import prog8.compiler.IErrorReporter
|
||||||
import prog8.compiler.IStringEncoding
|
import prog8.compiler.IStringEncoding
|
||||||
@ -15,7 +12,6 @@ import prog8.compiler.target.c64.C64MachineDefinition
|
|||||||
import prog8.compiler.target.cbm.Petscii
|
import prog8.compiler.target.cbm.Petscii
|
||||||
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
import prog8.compiler.target.cpu6502.codegen.AsmGen
|
||||||
import prog8.compiler.target.cx16.CX16MachineDefinition
|
import prog8.compiler.target.cx16.CX16MachineDefinition
|
||||||
import java.io.CharConversionException
|
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
@ -38,11 +34,7 @@ internal object C64Target: ICompilationTarget {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
||||||
try {
|
|
||||||
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||||
} catch (x: CharConversionException) {
|
|
||||||
throw CharConversionException("can't decode string: ${x.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun memorySize(dt: DataType): Int {
|
override fun memorySize(dt: DataType): Int {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
@ -66,11 +58,7 @@ internal object Cx16Target: ICompilationTarget {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
override fun decodeString(bytes: List<Short>, altEncoding: Boolean) =
|
||||||
try {
|
|
||||||
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
if (altEncoding) Petscii.decodeScreencode(bytes, true) else Petscii.decodePetscii(bytes, true)
|
||||||
} catch (x: CharConversionException) {
|
|
||||||
throw CharConversionException("can't decode string: ${x.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun memorySize(dt: DataType): Int {
|
override fun memorySize(dt: DataType): Int {
|
||||||
return when(dt) {
|
return when(dt) {
|
||||||
|
@ -1098,12 +1098,9 @@ object Petscii {
|
|||||||
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
|
fun decodePetscii(petscii: Iterable<Short>, lowercase: Boolean = false): String {
|
||||||
return petscii.map {
|
return petscii.map {
|
||||||
val code = it.toInt()
|
val code = it.toInt()
|
||||||
try {
|
if(code<0 || code>=decodingPetsciiLowercase.size)
|
||||||
|
throw CharConversionException("petscii $code out of range 0..${decodingPetsciiLowercase.size-1}")
|
||||||
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
|
if(lowercase) decodingPetsciiLowercase[code] else decodingPetsciiUppercase[code]
|
||||||
} catch(x: CharConversionException) {
|
|
||||||
// TODO this CharConversionException can never occur?? also clean up ICompilationTarget.decodeString?
|
|
||||||
if(lowercase) decodingPetsciiUppercase[code] else decodingPetsciiLowercase[code]
|
|
||||||
}
|
|
||||||
}.joinToString("")
|
}.joinToString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1140,17 +1137,15 @@ object Petscii {
|
|||||||
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {
|
fun decodeScreencode(screencode: Iterable<Short>, lowercase: Boolean = false): String {
|
||||||
return screencode.map {
|
return screencode.map {
|
||||||
val code = it.toInt()
|
val code = it.toInt()
|
||||||
try {
|
if(code<0 || code>=decodingScreencodeLowercase.size)
|
||||||
|
throw CharConversionException("screencode $code out of range 0..${decodingScreencodeLowercase.size-1}")
|
||||||
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
|
if (lowercase) decodingScreencodeLowercase[code] else decodingScreencodeUppercase[code]
|
||||||
} catch (x: CharConversionException) {
|
|
||||||
// TODO this CharConversionException can never occur?? also clean up ICompilationTarget.decodeString?
|
|
||||||
if (lowercase) decodingScreencodeUppercase[code] else decodingScreencodeLowercase[code]
|
|
||||||
}
|
|
||||||
}.joinToString("")
|
}.joinToString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Result<Short, CharConversionException> {
|
fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Result<Short, CharConversionException> {
|
||||||
val code = when {
|
val code = when {
|
||||||
|
petscii_code < 0 -> return Err(CharConversionException("petscii code out of range"))
|
||||||
petscii_code <= 0x1f -> petscii_code + 128
|
petscii_code <= 0x1f -> petscii_code + 128
|
||||||
petscii_code <= 0x3f -> petscii_code.toInt()
|
petscii_code <= 0x3f -> petscii_code.toInt()
|
||||||
petscii_code <= 0x5f -> petscii_code - 64
|
petscii_code <= 0x5f -> petscii_code - 64
|
||||||
@ -1168,6 +1163,7 @@ object Petscii {
|
|||||||
|
|
||||||
fun scr2petscii(screencode: Short): Result<Short, CharConversionException> {
|
fun scr2petscii(screencode: Short): Result<Short, CharConversionException> {
|
||||||
val petscii = when {
|
val petscii = when {
|
||||||
|
screencode < 0 -> return Err(CharConversionException("screencode out of range"))
|
||||||
screencode <= 0x1f -> screencode + 64
|
screencode <= 0x1f -> screencode + 64
|
||||||
screencode <= 0x3f -> screencode.toInt()
|
screencode <= 0x3f -> screencode.toInt()
|
||||||
screencode <= 0x5d -> screencode +123
|
screencode <= 0x5d -> screencode +123
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package prog8tests
|
package prog8tests
|
||||||
|
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.expectError
|
||||||
import org.hamcrest.MatcherAssert.assertThat
|
import org.hamcrest.MatcherAssert.assertThat
|
||||||
import org.hamcrest.Matchers.equalTo
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.base.DataType
|
|
||||||
import prog8.ast.base.Position
|
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
|
||||||
import prog8.ast.expressions.StringLiteralValue
|
|
||||||
import prog8.compiler.target.cbm.Petscii
|
import prog8.compiler.target.cbm.Petscii
|
||||||
|
import java.io.CharConversionException
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
|
|
||||||
@ -34,8 +32,6 @@ class TestPetscii {
|
|||||||
assertThat("expect lowercase error fallback", Petscii.encodePetscii("♥", true), equalTo(Ok(listOf<Short>(0xd3))))
|
assertThat("expect lowercase error fallback", Petscii.encodePetscii("♥", true), equalTo(Ok(listOf<Short>(0xd3))))
|
||||||
|
|
||||||
assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A"))
|
assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1), true) }
|
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(256), true) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -48,8 +44,6 @@ class TestPetscii {
|
|||||||
assertThat("expecting fallback", Petscii.encodePetscii("✓"), equalTo(Ok(listOf<Short>(250))))
|
assertThat("expecting fallback", Petscii.encodePetscii("✓"), equalTo(Ok(listOf<Short>(250))))
|
||||||
|
|
||||||
assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π"))
|
assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(-1)) }
|
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodePetscii(listOf(256)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -62,8 +56,6 @@ class TestPetscii {
|
|||||||
assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(Ok(listOf<Short>(94))))
|
assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(Ok(listOf<Short>(94))))
|
||||||
|
|
||||||
assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓"))
|
assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1), true) }
|
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(256), true) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -77,7 +69,29 @@ class TestPetscii {
|
|||||||
assertThat("expecting fallback", Petscii.encodeScreencode("✓"), equalTo(Ok(listOf<Short>(122))))
|
assertThat("expecting fallback", Petscii.encodeScreencode("✓"), equalTo(Ok(listOf<Short>(122))))
|
||||||
|
|
||||||
assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π"))
|
assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π"))
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(-1)) }
|
}
|
||||||
assertFailsWith<ArrayIndexOutOfBoundsException> { Petscii.decodeScreencode(listOf(256)) }
|
|
||||||
|
@Test
|
||||||
|
fun testErrorCases() {
|
||||||
|
Petscii.encodePetscii("~", true).expectError { "shouldn't be able to encode tilde" }
|
||||||
|
Petscii.encodePetscii("~", false).expectError { "shouldn't be able to encode tilde" }
|
||||||
|
Petscii.encodeScreencode("~", true).expectError { "shouldn't be able to encode tilde" }
|
||||||
|
Petscii.encodeScreencode("~", false).expectError { "shouldn't be able to encode tilde" }
|
||||||
|
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodePetscii(listOf<Short>(-1), true) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodePetscii(listOf<Short>(256), true) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodePetscii(listOf<Short>(-1), false) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodePetscii(listOf<Short>(256), false) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodeScreencode(listOf<Short>(-1), true) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodeScreencode(listOf<Short>(256), true) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodeScreencode(listOf<Short>(-1), false) }
|
||||||
|
assertFailsWith<CharConversionException> { Petscii.decodeScreencode(listOf<Short>(256), false) }
|
||||||
|
|
||||||
|
Petscii.scr2petscii(-1).expectError { "-1 should error" }
|
||||||
|
Petscii.scr2petscii(256).expectError { "256 should error" }
|
||||||
|
Petscii.petscii2scr(-1, true).expectError { "-1 should error" }
|
||||||
|
Petscii.petscii2scr(256, true).expectError { "256 should error" }
|
||||||
|
Petscii.petscii2scr(-1, false).expectError { "-1 should error" }
|
||||||
|
Petscii.petscii2scr(256, false).expectError { "256 should error" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,7 +513,7 @@ class CharLiteral(val value: Char,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun referencesIdentifier(vararg scopedName: String) = false
|
override fun referencesIdentifier(vararg scopedName: String) = false
|
||||||
override fun constValue(program: Program): NumericLiteralValue? = null // TODO: CharLiteral.constValue can't be NumericLiteralValue...
|
override fun constValue(program: Program): NumericLiteralValue? = null // TODO: CharLiteral.constValue can't be NumericLiteralValue... unless we re-add string encoder to program?
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user