diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 0eb770d7d..d1cab9029 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -39,7 +39,7 @@ private fun compileMain(args: Array): Boolean { val watchMode by cli.option(ArgType.Boolean, fullName = "watch", description = "continuous compilation mode (watches for file changes), greatly increases compilation speed") val slowCodegenWarnings by cli.option(ArgType.Boolean, fullName = "slowwarn", description="show debug warnings about slow/problematic assembly code generation") val compilationTarget by cli.option(ArgType.String, fullName = "target", description = "target output of the compiler, currently '${C64Target.name}' and '${Cx16Target.name}' available").default(C64Target.name) - val libDirs by cli.option(ArgType.String, fullName="libdirs", description = "list of extra paths to search in for imported modules").multiple().delimiter(File.pathSeparator) + val sourceDirs by cli.option(ArgType.String, fullName="srcdirs", description = "list of extra paths to search in for imported modules").multiple().delimiter(File.pathSeparator) val moduleFiles by cli.argument(ArgType.String, fullName = "modules", description = "main module file(s) to compile").multiple(999) try { @@ -61,9 +61,9 @@ private fun compileMain(args: Array): Boolean { return false } - val libdirs = libDirs.toMutableList() - if(libdirs.firstOrNull()!=".") - libdirs.add(0, ".") + val srcdirs = sourceDirs.toMutableList() + if(srcdirs.firstOrNull()!=".") + srcdirs.add(0, ".") if(watchMode==true) { val watchservice = FileSystems.getDefault().newWatchService() @@ -74,7 +74,7 @@ private fun compileMain(args: Array): Boolean { val results = mutableListOf() for(filepathRaw in moduleFiles) { val filepath = pathFrom(filepathRaw).normalize() - val compilationResult = compileProgram(filepath, dontOptimize!=true, dontWriteAssembly!=true, slowCodegenWarnings==true, compilationTarget, libdirs, outputPath) + val compilationResult = compileProgram(filepath, dontOptimize!=true, dontWriteAssembly!=true, slowCodegenWarnings==true, compilationTarget, srcdirs, outputPath) results.add(compilationResult) } @@ -85,7 +85,7 @@ private fun compileMain(args: Array): Boolean { for (importedFile in allImportedFiles) { print(" ") println(importedFile) - val watchDir = importedFile.parent ?: Path.of(".") + val watchDir = importedFile.parent ?: Path.of("") watchDir.register(watchservice, StandardWatchEventKinds.ENTRY_MODIFY) } println("[${LocalDateTime.now().withNano(0)}] Waiting for file changes.") @@ -111,7 +111,7 @@ private fun compileMain(args: Array): Boolean { val filepath = pathFrom(filepathRaw).normalize() val compilationResult: CompilationResult try { - compilationResult = compileProgram(filepath, dontOptimize!=true, dontWriteAssembly!=true, slowCodegenWarnings==true, compilationTarget, libdirs, outputPath) + compilationResult = compileProgram(filepath, dontOptimize!=true, dontWriteAssembly!=true, slowCodegenWarnings==true, compilationTarget, srcdirs, outputPath) if(!compilationResult.success) return false } catch (x: ParsingFailedError) { diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 126ae7048..4436e78e9 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -341,7 +341,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I val modifications = mutableListOf() val statement = expr.containingStatement val dt = expr.indexer.indexExpr.inferType(program) - val register = if(dt.istype(DataType.UBYTE) || dt.istype(DataType.BYTE)) "r9L" else "r9" + val register = if(dt istype DataType.UBYTE || dt istype DataType.BYTE ) "r9L" else "r9" // replace the indexer with just the variable (simply use a cx16 virtual register r9, that we HOPE is not used for other things in the expression...) // assign the indexing expression to the helper variable, but only if that hasn't been done already val target = AssignTarget(IdentifierReference(listOf("cx16", register), expr.indexer.position), null, null, expr.indexer.position) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 6f67e2e87..363b776c7 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -17,7 +17,9 @@ import prog8.compiler.target.Cx16Target import prog8.compiler.target.ICompilationTarget import prog8.compiler.target.asmGeneratorFor import prog8.optimizer.* +import prog8.parser.ParseError import prog8.parser.ParsingFailedError +import prog8.parser.SourceCode import prog8.parser.SourceCode.Companion.libraryFilePrefix import java.io.File import java.nio.file.Path @@ -70,7 +72,7 @@ fun compileProgram(filepath: Path, writeAssembly: Boolean, slowCodegenWarnings: Boolean, compilationTarget: String, - libdirs: List, + sourceDirs: List, outputDir: Path): CompilationResult { var programName = "" lateinit var programAst: Program @@ -87,21 +89,27 @@ fun compileProgram(filepath: Path, try { val totalTime = measureTimeMillis { // import main module and everything it needs - val (ast, compilationOptions, imported) = parseImports(filepath, errors, compTarget, libdirs) + val (ast, compilationOptions, imported) = parseImports(filepath, errors, compTarget, sourceDirs) compilationOptions.slowCodegenWarnings = slowCodegenWarnings compilationOptions.optimize = optimize programAst = ast importedFiles = imported processAst(programAst, errors, compilationOptions) if (compilationOptions.optimize) - optimizeAst(programAst, errors, BuiltinFunctionsFacade(BuiltinFunctions), compTarget, compilationOptions) + optimizeAst( + programAst, + errors, + BuiltinFunctionsFacade(BuiltinFunctions), + compTarget, + compilationOptions + ) postprocessAst(programAst, errors, compilationOptions) // printAst(programAst) - if(writeAssembly) { + if (writeAssembly) { val result = writeAssembly(programAst, errors, outputDir, compilationOptions) - when(result) { + when (result) { is WriteAssemblyResult.Ok -> programName = result.filename is WriteAssemblyResult.Fail -> { System.err.println(result.error) @@ -114,10 +122,13 @@ fun compileProgram(filepath: Path, System.err.flush() println("\nTotal compilation+assemble time: ${totalTime / 1000.0} sec.") return CompilationResult(true, programAst, programName, compTarget, importedFiles) - - } catch (px: ParsingFailedError) { + } catch (px: ParseError) { System.err.print("\u001b[91m") // bright red - System.err.println(px.message) + System.err.println("${px.position.toClickableStr()} parse error: ${px.message}".trim()) + System.err.print("\u001b[0m") // reset + } catch (pfx: ParsingFailedError) { + System.err.print("\u001b[91m") // bright red + System.err.println(pfx.message) System.err.print("\u001b[0m") // reset } catch (ax: AstException) { System.err.print("\u001b[91m") // bright red @@ -172,23 +183,22 @@ private class BuiltinFunctionsFacade(functions: Map): IBuilt } fun parseImports(filepath: Path, - errors: IErrorReporter, - compTarget: ICompilationTarget, - libdirs: List): Triple> { + errors: IErrorReporter, + compTarget: ICompilationTarget, + sourceDirs: List): Triple> { println("Compiler target: ${compTarget.name}. Parsing...") val bf = BuiltinFunctionsFacade(BuiltinFunctions) val programAst = Program(filepath.nameWithoutExtension, bf, compTarget) bf.program = programAst - val importer = ModuleImporter(programAst, compTarget.name, errors, libdirs) + val importer = ModuleImporter(programAst, compTarget.name, errors, sourceDirs) val importedModuleResult = importer.importModule(filepath) importedModuleResult.onFailure { throw it } errors.report() - val importedFiles = programAst.modules - .mapNotNull { it.source } - .filter { !it.isFromResources } // TODO: parseImports/importedFiles - maybe rather `source.isFromFilesystem`? - .map { Path(it.pathString()) } + val importedFiles = programAst.modules.map { it.source } + .filter { it.isFromFilesystem } + .map { Path(it.origin) } val compilerOptions = determineCompilationOptions(programAst, compTarget) if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG) throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.") @@ -365,7 +375,7 @@ fun printAst(programAst: Program) { println() } -internal fun loadAsmIncludeFile(filename: String, sourcePath: Path): Result { +internal fun loadAsmIncludeFile(filename: String, source: SourceCode): Result { return if (filename.startsWith(libraryFilePrefix)) { return runCatching { val stream = object {}.javaClass.getResourceAsStream("/prog8lib/${filename.substring(libraryFilePrefix.length)}") // TODO handle via SourceCode @@ -373,7 +383,7 @@ internal fun loadAsmIncludeFile(filename: String, sourcePath: Path): Result) { + sourceDirs: List) { - private val libpaths: List = libdirs.map { Path(it) } + private val sourcePaths: List = sourceDirs.map { Path(it) } fun importModule(filePath: Path): Result { val currentDir = Path("").absolute() - val searchIn = listOf(currentDir) + libpaths + val searchIn = listOf(currentDir) + sourcePaths val candidates = searchIn .map { it.absolute().div(filePath).normalize().absolute() } .filter { it.exists() } @@ -42,7 +41,7 @@ class ModuleImporter(private val program: Program, val logMsg = "importing '${filePath.nameWithoutExtension}' (from file $srcPath)" println(logMsg) - return Ok(importModule(SourceCode.fromPath(srcPath))) + return Ok(importModule(SourceCode.File(srcPath))) } fun importLibraryModule(name: String): Module? { @@ -69,30 +68,41 @@ class ModuleImporter(private val program: Program, } private fun executeImportDirective(import: Directive, importingModule: Module?): Module? { - if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null) + if(import.directive!="%import" || import.args.size!=1) throw SyntaxError("invalid import directive", import.position) + if(!import.args[0].str.isNullOrEmpty() || import.args[0].name==null) + throw SyntaxError("%import requires unquoted module name", import.position) val moduleName = import.args[0].name!! if("$moduleName.p8" == import.position.file) throw SyntaxError("cannot import self", import.position) val existing = program.modules.singleOrNull { it.name == moduleName } if (existing!=null) - return null // TODO: why return null instead of Module instance? + return existing - var srcCode = tryGetModuleFromResource("$moduleName.p8", compilationTargetName) + // try internal library first + val moduleResourceSrc = getModuleFromResource("$moduleName.p8", compilationTargetName) val importedModule = - if (srcCode != null) { - println("importing '$moduleName' (from internal ${srcCode.origin})") - importModule(srcCode) - } else { - srcCode = tryGetModuleFromFile(moduleName, importingModule) - if (srcCode == null) { - errors.err("imported file not found: $moduleName.p8", import.position) - return null - //throw NoSuchFileException(File("$moduleName.p8")) + moduleResourceSrc.fold( + success = { + println("importing '$moduleName' (from internal ${it.origin})") + importModule(it) + }, + failure = { + // try filesystem next + val moduleSrc = getModuleFromFile(moduleName, importingModule) + moduleSrc.fold( + success = { + println("importing '$moduleName' (from file ${it.origin})") + importModule(it) + }, + failure = { + errors.err("no module found with name $moduleName", import.position) + return null + } + ) } - importModule(srcCode) - } + ) removeDirectivesFromImportedModule(importedModule) return importedModule @@ -100,33 +110,29 @@ class ModuleImporter(private val program: Program, private fun removeDirectivesFromImportedModule(importedModule: Module) { // Most global directives don't apply for imported modules, so remove them - val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%target") + val moduleLevelDirectives = listOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address") var directives = importedModule.statements.filterIsInstance() importedModule.statements.removeAll(directives) directives = directives.filter{ it.directive !in moduleLevelDirectives } importedModule.statements.addAll(0, directives) } - private fun tryGetModuleFromResource(name: String, compilationTargetName: String): SourceCode? { - // try target speficic first - try { - return SourceCode.fromResources("/prog8lib/$compilationTargetName/$name") - } catch (e: FileSystemException) { - } - try { - return SourceCode.fromResources("/prog8lib/$name") - } catch (e: FileSystemException) { - } - return null + private fun getModuleFromResource(name: String, compilationTargetName: String): Result { + val result = + runCatching { SourceCode.Resource("/prog8lib/$compilationTargetName/$name") } + .orElse { runCatching { SourceCode.Resource("/prog8lib/$name") } } + + return result.mapError { NoSuchFileException(File(name)) } } - private fun tryGetModuleFromFile(name: String, importingModule: Module?): SourceCode? { + private fun getModuleFromFile(name: String, importingModule: Module?): Result { val fileName = "$name.p8" val locations = if (importingModule == null) { // <=> imported from library module - libpaths + sourcePaths } else { - libpaths.drop(1) + // TODO: why drop the first? + val dropCurDir = if(sourcePaths.isNotEmpty() && sourcePaths[0].name == ".") 1 else 0 + sourcePaths.drop(dropCurDir) + // FIXME: won't work until Prog8Parser is fixed s.t. it fully initialzes the modules it returns listOf(Path(importingModule.position.file).parent ?: Path("")) + listOf(Path(".", "prog8lib")) @@ -134,12 +140,11 @@ class ModuleImporter(private val program: Program, locations.forEach { try { - return SourceCode.fromPath(it.resolve(fileName)) + return Ok(SourceCode.File(it.resolve(fileName))) } catch (e: NoSuchFileException) { } } - //throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: embedded libs and $locations)") - return null + return Err(NoSuchFileException(File("name"))) } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index cafce0d3c..001138b22 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -13,6 +13,7 @@ import prog8.compiler.ZeropageType import prog8.compiler.functions.BuiltinFunctions import prog8.compiler.functions.builtinFunctionReturnType import prog8.compiler.target.ICompilationTarget +import prog8.parser.SourceCode import java.io.CharConversionException import java.io.File import java.util.* @@ -44,7 +45,7 @@ internal class AstChecker(private val program: Program, } if(compilerOptions.floats) { - if (compilerOptions.zeropage !in setOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) + if (compilerOptions.zeropage !in arrayOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) errors.err("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'", program.mainModule.position) } @@ -152,11 +153,11 @@ internal class AstChecker(private val program: Program, val to = range.to as? NumericLiteralValue if(from != null) checkValueTypeAndRange(loopvar.datatype, from) - else if(!range.from.inferType(program).istype(loopvar.datatype)) + else if(range.from.inferType(program) isnot loopvar.datatype) errors.err("range start value is incompatible with loop variable type", range.position) if(to != null) checkValueTypeAndRange(loopvar.datatype, to) - else if(!range.to.inferType(program).istype(loopvar.datatype)) + else if(range.to.inferType(program) isnot loopvar.datatype) errors.err("range end value is incompatible with loop variable type", range.position) } } @@ -283,11 +284,11 @@ internal class AstChecker(private val program: Program, if(subroutine.asmReturnvaluesRegisters.size != subroutine.returntypes.size) err("number of return registers is not the isSameAs as number of return values") for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) { - if(param.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { + if(param.second.registerOrPair in arrayOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { if (param.first.type != DataType.UBYTE && param.first.type != DataType.BYTE) err("parameter '${param.first.name}' should be (u)byte") } - else if(param.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { + else if(param.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { if (param.first.type != DataType.UWORD && param.first.type != DataType.WORD && param.first.type != DataType.STR && param.first.type !in ArrayDatatypes && param.first.type != DataType.FLOAT) err("parameter '${param.first.name}' should be (u)word/address") @@ -298,11 +299,11 @@ internal class AstChecker(private val program: Program, } } subroutine.returntypes.zip(subroutine.asmReturnvaluesRegisters).forEachIndexed { index, pair -> - if(pair.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { + if(pair.second.registerOrPair in arrayOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { if (pair.first != DataType.UBYTE && pair.first != DataType.BYTE) err("return value #${index + 1} should be (u)byte") } - else if(pair.second.registerOrPair in setOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { + else if(pair.second.registerOrPair in arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)) { if (pair.first != DataType.UWORD && pair.first != DataType.WORD && pair.first != DataType.STR && pair.first !in ArrayDatatypes && pair.first != DataType.FLOAT) err("return value #${index + 1} should be (u)word/address") @@ -428,12 +429,12 @@ internal class AstChecker(private val program: Program, if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) { if(targetDt.isIterable) errors.err("cannot assign value to string or array", assignment.value.position) - else if(!(valueDt.istype(DataType.STR) && targetDt.istype(DataType.UWORD))) + else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) errors.err("type of value doesn't match target", assignment.value.position) } if(assignment.value is TypecastExpression) { - if(assignment.isAugmentable && targetDt.istype(DataType.FLOAT)) + if(assignment.isAugmentable && targetDt istype DataType.FLOAT) errors.err("typecasting a float value in-place makes no sense", assignment.value.position) } @@ -518,7 +519,7 @@ internal class AstChecker(private val program: Program, } // FLOATS enabled? - if(!compilerOptions.floats && decl.datatype in setOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY) + if(!compilerOptions.floats && decl.datatype.oneOf(DataType.FLOAT, DataType.ARRAY_F) && decl.type!= VarDeclType.MEMORY) err("floating point used, but that is not enabled via options") if(decl.datatype == DataType.FLOAT && (decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE || decl.zeropage==ZeropageWish.PREFER_ZEROPAGE)) @@ -596,7 +597,7 @@ internal class AstChecker(private val program: Program, val declValue = decl.value if(declValue!=null && decl.type==VarDeclType.VAR) { - if (!declValue.inferType(program).istype(decl.datatype)) { + if (declValue.inferType(program) isnot decl.datatype) { err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position) } } @@ -714,7 +715,7 @@ internal class AstChecker(private val program: Program, err("this directive may only occur in a block or at module level") if(directive.args.isEmpty()) err("missing option directive argument(s)") - else if(directive.args.map{it.name in setOf("enable_floats", "force_output", "no_sysinit", "align_word", "align_page")}.any { !it }) + else if(directive.args.map{it.name in arrayOf("enable_floats", "force_output", "no_sysinit", "align_word", "align_page")}.any { !it }) err("invalid option directive argument(s)") } else -> throw SyntaxError("invalid directive ${directive.directive}", directive.position) @@ -726,25 +727,21 @@ internal class AstChecker(private val program: Program, if (File(filename).isFile) return - var definingModule = directive.parent // TODO: why not just use directive.definingModule() here? - while (definingModule !is Module) - definingModule = definingModule.parent - if (definingModule.isLibrary) + val definingModule = directive.definingModule + if (definingModule.isLibrary || !definingModule.source.isFromFilesystem) return - val s = definingModule.source?.pathString() - if (s != null) { - val sourceFileCandidate = Path(s).resolveSibling(filename).toFile() - if (sourceFileCandidate.isFile) - return - } - - errors.err("included file not found: $filename", directive.position) + val s = definingModule.source.origin + val sourceFileCandidate = Path(s).resolveSibling(filename).toFile() + if (sourceFileCandidate.isFile) + return + else + errors.err("included file not found: $filename", directive.position) } override fun visit(array: ArrayLiteralValue) { if(array.type.isKnown) { - if (!compilerOptions.floats && array.type.getOr(DataType.UNDEFINED) in setOf(DataType.FLOAT, DataType.ARRAY_F)) { + if (!compilerOptions.floats && array.type.oneOf(DataType.FLOAT, DataType.ARRAY_F)) { errors.err("floating point used, but that is not enabled via options", array.position) } val arrayspec = ArrayIndex.forArray(array) @@ -919,7 +916,7 @@ internal class AstChecker(private val program: Program, // warn about sgn(unsigned) this is likely a mistake if(functionCall.target.nameInSource.last()=="sgn") { val sgnArgType = functionCall.args.first().inferType(program) - if(sgnArgType.istype(DataType.UBYTE) || sgnArgType.istype(DataType.UWORD)) + if(sgnArgType istype DataType.UBYTE || sgnArgType istype DataType.UWORD) errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCall.args.first().position) } @@ -988,12 +985,12 @@ internal class AstChecker(private val program: Program, if(functionCallStatement.target.nameInSource.last() == "sort") { // sort is not supported on float arrays val idref = functionCallStatement.args.singleOrNull() as? IdentifierReference - if(idref!=null && idref.inferType(program).istype(DataType.ARRAY_F)) { + if(idref!=null && idref.inferType(program) istype DataType.ARRAY_F) { errors.err("sorting a floating point array is not supported", functionCallStatement.args.first().position) } } - if(functionCallStatement.target.nameInSource.last() in setOf("rol", "ror", "rol2", "ror2", "swap", "sort", "reverse")) { + if(functionCallStatement.target.nameInSource.last() in arrayOf("rol", "ror", "rol2", "ror2", "swap", "sort", "reverse")) { // in-place modification, can't be done on literals if(functionCallStatement.args.any { it !is IdentifierReference && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) { errors.err("invalid argument to a in-place modifying function", functionCallStatement.args.first().position) @@ -1122,7 +1119,7 @@ internal class AstChecker(private val program: Program, // check index value 0..255 val dtxNum = arrayIndexedExpression.indexer.indexExpr.inferType(program) - if(!dtxNum.istype(DataType.UBYTE) && !dtxNum.istype(DataType.BYTE)) + if(dtxNum isnot DataType.UBYTE && dtxNum isnot DataType.BYTE) errors.err("array indexing is limited to byte size 0..255", arrayIndexedExpression.position) super.visit(arrayIndexedExpression) @@ -1160,7 +1157,7 @@ internal class AstChecker(private val program: Program, when { constvalue == null -> errors.err("choice value must be a constant", whenChoice.position) constvalue.type !in IntegerDatatypes -> errors.err("choice value must be a byte or word", whenChoice.position) - constvalue.type != conditionType.getOr(DataType.UNDEFINED) -> errors.err("choice value datatype differs from condition value", whenChoice.position) + conditionType isnot constvalue.type -> errors.err("choice value datatype differs from condition value", whenChoice.position) } } } else { @@ -1204,7 +1201,7 @@ internal class AstChecker(private val program: Program, DataType.STR -> return err("string value expected") DataType.ARRAY_UB, DataType.ARRAY_B -> { // value may be either a single byte, or a byte arraysize (of all constant values), or a range - if(value.type.istype(targetDt)) { + if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.constIndex() @@ -1223,7 +1220,7 @@ internal class AstChecker(private val program: Program, } DataType.ARRAY_UW, DataType.ARRAY_W -> { // value may be either a single word, or a word arraysize, or a range - if(value.type.istype(targetDt)) { + if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.constIndex() @@ -1242,7 +1239,7 @@ internal class AstChecker(private val program: Program, } DataType.ARRAY_F -> { // value may be either a single float, or a float arraysize - if(value.type.istype(targetDt)) { + if(value.type istype targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySize = value.value.size diff --git a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt index 4e47645f2..c77a577ec 100644 --- a/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt +++ b/compiler/src/prog8/compiler/astprocessing/LiteralsToAutoVars.kt @@ -29,7 +29,7 @@ internal class LiteralsToAutoVars(private val program: Program) : AstWalker() { if(vardecl!=null) { // adjust the datatype of the array (to an educated guess) val arrayDt = array.type - if(!arrayDt.istype(vardecl.datatype)) { + if(arrayDt isnot vardecl.datatype) { val cast = array.cast(vardecl.datatype) if (cast != null && cast !== array) return listOf(IAstModification.ReplaceNode(vardecl.value!!, cast, vardecl)) diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index bd12a7dc5..bd875846f 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -111,7 +111,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport } } is VarDecl -> { - if(!leftDt.istype(parent.datatype)) { + if(leftDt isnot parent.datatype) { val cast = TypecastExpression(expr.left, parent.datatype, true, parent.position) return listOf(IAstModification.ReplaceNode(expr.left, cast, expr)) } diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index 7620919e9..f45f7dec7 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -22,7 +22,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk val declValue = decl.value if(decl.type==VarDeclType.VAR && declValue!=null) { val valueDt = declValue.inferType(program) - if(!valueDt.istype(decl.datatype)) { + if(valueDt isnot decl.datatype) { // don't add a typecast on an array initializer value if(valueDt.isInteger && decl.datatype in ArrayDatatypes) @@ -182,7 +182,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk override fun after(typecast: TypecastExpression, parent: Node): Iterable { // warn about any implicit type casts to Float, because that may not be intended - if(typecast.implicit && typecast.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) { + if(typecast.implicit && typecast.type.oneOf(DataType.FLOAT, DataType.ARRAY_F)) { errors.warn("integer implicitly converted to float. Suggestion: use float literals, add an explicit cast, or revert to integer arithmetic", typecast.position) } return noModifications @@ -217,7 +217,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk val subroutine = returnStmt.definingSubroutine!! if(subroutine.returntypes.size==1) { val subReturnType = subroutine.returntypes.first() - if (returnValue.inferType(program).istype(subReturnType)) + if (returnValue.inferType(program) istype subReturnType) return noModifications if (returnValue is NumericLiteralValue) { val cast = returnValue.cast(subroutine.returntypes.single()) diff --git a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt index 039815bcd..688e29021 100644 --- a/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt +++ b/compiler/src/prog8/compiler/astprocessing/VariousCleanups.kt @@ -71,7 +71,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter) } val sourceDt = typecast.expression.inferType(program) - if(sourceDt.istype(typecast.type)) + if(sourceDt istype typecast.type) return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) return noModifications diff --git a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt index 5affb0745..3e0b28444 100644 --- a/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/functions/BuiltinFunctions.kt @@ -9,7 +9,7 @@ import prog8.compiler.CompilerException import kotlin.math.* -class FParam(val name: String, val possibleDatatypes: Set) +class FParam(val name: String, val possibleDatatypes: Array) typealias ConstExpressionCaller = (args: List, position: Position, program: Program, memsizer: IMemSizer) -> NumericLiteralValue @@ -90,10 +90,10 @@ class FSignature(val name: String, @Suppress("UNUSED_ANONYMOUS_PARAMETER") private val functionSignatures: List = listOf( // this set of function have no return value and operate in-place: - FSignature("rol" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - FSignature("ror" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - FSignature("rol2" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), - FSignature("ror2" , false, listOf(FParam("item", setOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("rol" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("ror" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("rol2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), + FSignature("ror2" , false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null), FSignature("sort" , false, listOf(FParam("array", ArrayDatatypes)), null), FSignature("reverse" , false, listOf(FParam("array", ArrayDatatypes)), null), FSignature("cmp" , false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null), @@ -103,46 +103,46 @@ private val functionSignatures: List = listOf( FSignature("sum" , true, listOf(FParam("values", ArrayDatatypes)), null) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinSum) }, // type depends on args FSignature("abs" , true, listOf(FParam("value", NumericDatatypes)), null, ::builtinAbs), // type depends on argument FSignature("len" , true, listOf(FParam("values", IterableDatatypes)), null, ::builtinLen), // type is UBYTE or UWORD depending on actual length - FSignature("sizeof" , true, listOf(FParam("object", DataType.values().toSet())), DataType.UBYTE, ::builtinSizeof), + FSignature("sizeof" , true, listOf(FParam("object", DataType.values())), DataType.UBYTE, ::builtinSizeof), // normal functions follow: FSignature("sgn" , true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE, ::builtinSgn ), - FSignature("sin" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sin) }, - FSignature("sin8" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ), - FSignature("sin8u" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ), - FSignature("sin16" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ), - FSignature("sin16u" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ), - FSignature("cos" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::cos) }, - FSignature("cos8" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ), - FSignature("cos8u" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ), - FSignature("cos16" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ), - FSignature("cos16u" , true, listOf(FParam("angle8", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ), - FSignature("tan" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::tan) }, - FSignature("atan" , true, listOf(FParam("rads", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::atan) }, - FSignature("ln" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::log) }, - FSignature("log2" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, ::log2) }, - FSignature("sqrt16" , true, listOf(FParam("value", setOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()).toInt() } }, - FSignature("sqrt" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sqrt) }, - FSignature("rad" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::toRadians) }, - FSignature("deg" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::toDegrees) }, - FSignature("round" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::round) }, - FSignature("floor" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::floor) }, - FSignature("ceil" , true, listOf(FParam("value", setOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) }, + FSignature("sin" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sin) }, + FSignature("sin8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinSin8 ), + FSignature("sin8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinSin8u ), + FSignature("sin16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinSin16 ), + FSignature("sin16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinSin16u ), + FSignature("cos" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::cos) }, + FSignature("cos8" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.BYTE, ::builtinCos8 ), + FSignature("cos8u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UBYTE, ::builtinCos8u ), + FSignature("cos16" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.WORD, ::builtinCos16 ), + FSignature("cos16u" , true, listOf(FParam("angle8", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinCos16u ), + FSignature("tan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::tan) }, + FSignature("atan" , true, listOf(FParam("rads", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::atan) }, + FSignature("ln" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::log) }, + FSignature("log2" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, ::log2) }, + FSignature("sqrt16" , true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { sqrt(it.toDouble()).toInt() } }, + FSignature("sqrt" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::sqrt) }, + FSignature("rad" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::toRadians) }, + FSignature("deg" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArg(a, p, prg, Math::toDegrees) }, + FSignature("round" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::round) }, + FSignature("floor" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::floor) }, + FSignature("ceil" , true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT) { a, p, prg, ct -> oneDoubleArgOutputWord(a, p, prg, Math::ceil) }, FSignature("any" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinAny) }, FSignature("all" , true, listOf(FParam("values", ArrayDatatypes)), DataType.UBYTE) { a, p, prg, ct -> collectionArg(a, p, prg, ::builtinAll) }, - FSignature("lsb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 } }, - FSignature("msb" , true, listOf(FParam("value", setOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { x: Int -> x ushr 8 and 255} }, - FSignature("mkword" , true, listOf(FParam("msb", setOf(DataType.UBYTE)), FParam("lsb", setOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword), - FSignature("peek" , true, listOf(FParam("address", setOf(DataType.UWORD))), DataType.UBYTE), - FSignature("peekw" , true, listOf(FParam("address", setOf(DataType.UWORD))), DataType.UWORD), - FSignature("poke" , false, listOf(FParam("address", setOf(DataType.UWORD)), FParam("value", setOf(DataType.UBYTE))), null), - FSignature("pokew" , false, listOf(FParam("address", setOf(DataType.UWORD)), FParam("value", setOf(DataType.UWORD))), null), + FSignature("lsb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { x: Int -> x and 255 } }, + FSignature("msb" , true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE) { a, p, prg, ct -> oneIntArgOutputInt(a, p, prg) { x: Int -> x ushr 8 and 255} }, + FSignature("mkword" , true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD, ::builtinMkword), + FSignature("peek" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE), + FSignature("peekw" , true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD), + FSignature("poke" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null), + FSignature("pokew" , false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null), FSignature("rnd" , false, emptyList(), DataType.UBYTE), FSignature("rndw" , false, emptyList(), DataType.UWORD), FSignature("rndf" , false, emptyList(), DataType.FLOAT), - FSignature("memory" , true, listOf(FParam("name", setOf(DataType.STR)), FParam("size", setOf(DataType.UWORD))), DataType.UWORD), + FSignature("memory" , true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD))), DataType.UWORD), FSignature("swap" , false, listOf(FParam("first", NumericDatatypes), FParam("second", NumericDatatypes)), null), - FSignature("callfar" , false, listOf(FParam("bank", setOf(DataType.UBYTE)), FParam("address", setOf(DataType.UWORD)), FParam("arg", setOf(DataType.UWORD))), null), - FSignature("callrom" , false, listOf(FParam("bank", setOf(DataType.UBYTE)), FParam("address", setOf(DataType.UWORD)), FParam("arg", setOf(DataType.UWORD))), null), + FSignature("callfar" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null), + FSignature("callrom" , false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), null), ) @@ -305,7 +305,7 @@ private fun builtinSizeof(args: List, position: Position, program: P val elementDt = ArrayToElementTypes.getValue(dt.getOr(DataType.UNDEFINED)) numericLiteral(memsizer.memorySize(elementDt) * length, position) } - dt.istype(DataType.STR) -> throw SyntaxError("sizeof str is undefined, did you mean len?", position) + dt istype DataType.STR -> throw SyntaxError("sizeof str is undefined, did you mean len?", position) else -> NumericLiteralValue(DataType.UBYTE, memsizer.memorySize(dt.getOr(DataType.UNDEFINED)), position) } } else { diff --git a/compiler/src/prog8/compiler/target/ICompilationTarget.kt b/compiler/src/prog8/compiler/target/ICompilationTarget.kt index ef12c9ac0..eb06b9a0f 100644 --- a/compiler/src/prog8/compiler/target/ICompilationTarget.kt +++ b/compiler/src/prog8/compiler/target/ICompilationTarget.kt @@ -1,5 +1,6 @@ package prog8.compiler.target +import com.github.michaelbull.result.fold import prog8.ast.IMemSizer import prog8.ast.Program import prog8.ast.base.* @@ -75,8 +76,8 @@ internal object C64Target: ICompilationTarget { override fun encodeString(str: String, altEncoding: Boolean): List { val coded = if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true) return coded.fold( - { throw it }, - { it } + failure = { throw it }, + success = { it } ) } override fun decodeString(bytes: List, altEncoding: Boolean) = @@ -103,8 +104,8 @@ internal object Cx16Target: ICompilationTarget { override fun encodeString(str: String, altEncoding: Boolean): List { val coded= if (altEncoding) Petscii.encodeScreencode(str, true) else Petscii.encodePetscii(str, true) return coded.fold( - { throw it }, - { it} + failure = { throw it }, + success = { it } ) } override fun decodeString(bytes: List, altEncoding: Boolean) = diff --git a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt index c2126bfb4..2588e0b22 100644 --- a/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/c64/C64MachineDefinition.kt @@ -86,7 +86,7 @@ internal object C64MachineDefinition: IMachineDefinition { init { - if (options.floats && options.zeropage !in setOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) + if (options.floats && options.zeropage !in arrayOf(ZeropageType.FLOATSAFE, ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) throw CompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'") if (options.zeropage == ZeropageType.FULL) { diff --git a/compiler/src/prog8/compiler/target/cbm/Petscii.kt b/compiler/src/prog8/compiler/target/cbm/Petscii.kt index 083ee99d4..dde6660ca 100644 --- a/compiler/src/prog8/compiler/target/cbm/Petscii.kt +++ b/compiler/src/prog8/compiler/target/cbm/Petscii.kt @@ -1,9 +1,9 @@ package prog8.compiler.target.cbm -import prog8.Either +import com.github.michaelbull.result.Err +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result import prog8.ast.antlr.escape -import prog8.left -import prog8.right import java.io.CharConversionException object Petscii { @@ -12,1039 +12,1039 @@ object Petscii { // character tables used from https://github.com/dj51d/cbmcodecs private val decodingPetsciiLowercase = arrayOf( - '\u0000', // 0x00 -> \u0000 - '\ufffe', // 0x01 -> UNDEFINED - '\ufffe', // 0x02 -> UNDEFINED - '\ufffe', // 0x03 -> UNDEFINED - '\ufffe', // 0x04 -> UNDEFINED - '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) - '\ufffe', // 0x06 -> UNDEFINED - '\ufffe', // 0x07 -> UNDEFINED - '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) - '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) - '\ufffe', // 0x0A -> UNDEFINED - '\ufffe', // 0x0B -> UNDEFINED - '\ufffe', // 0x0C -> UNDEFINED - '\r' , // 0x0D -> CARRIAGE RETURN - '\u000e', // 0x0E -> SHIFT OUT - '\ufffe', // 0x0F -> UNDEFINED - '\ufffe', // 0x10 -> UNDEFINED - '\uf11c', // 0x11 -> CURSOR DOWN (CUS) - '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) - '\uf120', // 0x13 -> HOME (CUS) - '\u007f', // 0x14 -> DELETE - '\ufffe', // 0x15 -> UNDEFINED - '\ufffe', // 0x16 -> UNDEFINED - '\ufffe', // 0x17 -> UNDEFINED - '\ufffe', // 0x18 -> UNDEFINED - '\ufffe', // 0x19 -> UNDEFINED - '\ufffe', // 0x1A -> UNDEFINED - '\ufffe', // 0x1B -> UNDEFINED - '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) - '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) - '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) - '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) - ' ' , // 0x20 -> SPACE - '!' , // ! 0x21 -> EXCLAMATION MARK - '"' , // " 0x22 -> QUOTATION MARK - '#' , // # 0x23 -> NUMBER SIGN - '$' , // $ 0x24 -> DOLLAR SIGN - '%' , // % 0x25 -> PERCENT SIGN - '&' , // & 0x26 -> AMPERSAND - '\'' , // ' 0x27 -> APOSTROPHE - '(' , // ( 0x28 -> LEFT PARENTHESIS - ')' , // ) 0x29 -> RIGHT PARENTHESIS - '*' , // * 0x2A -> ASTERISK - '+' , // + 0x2B -> PLUS SIGN - ',' , // , 0x2C -> COMMA - '-' , // - 0x2D -> HYPHEN-MINUS - '.' , // . 0x2E -> FULL STOP - '/' , // / 0x2F -> SOLIDUS - '0' , // 0 0x30 -> DIGIT ZERO - '1' , // 1 0x31 -> DIGIT ONE - '2' , // 2 0x32 -> DIGIT TWO - '3' , // 3 0x33 -> DIGIT THREE - '4' , // 4 0x34 -> DIGIT FOUR - '5' , // 5 0x35 -> DIGIT FIVE - '6' , // 6 0x36 -> DIGIT SIX - '7' , // 7 0x37 -> DIGIT SEVEN - '8' , // 8 0x38 -> DIGIT EIGHT - '9' , // 9 0x39 -> DIGIT NINE - ':' , // : 0x3A -> COLON - ';' , // ; 0x3B -> SEMICOLON - '<' , // < 0x3C -> LESS-THAN SIGN - '=' , // = 0x3D -> EQUALS SIGN - '>' , // > 0x3E -> GREATER-THAN SIGN - '?' , // ? 0x3F -> QUESTION MARK - '@' , // @ 0x40 -> COMMERCIAL AT - 'a' , // a 0x41 -> LATIN SMALL LETTER A - 'b' , // b 0x42 -> LATIN SMALL LETTER B - 'c' , // c 0x43 -> LATIN SMALL LETTER C - 'd' , // d 0x44 -> LATIN SMALL LETTER D - 'e' , // e 0x45 -> LATIN SMALL LETTER E - 'f' , // f 0x46 -> LATIN SMALL LETTER F - 'g' , // g 0x47 -> LATIN SMALL LETTER G - 'h' , // h 0x48 -> LATIN SMALL LETTER H - 'i' , // i 0x49 -> LATIN SMALL LETTER I - 'j' , // j 0x4A -> LATIN SMALL LETTER J - 'k' , // k 0x4B -> LATIN SMALL LETTER K - 'l' , // l 0x4C -> LATIN SMALL LETTER L - 'm' , // m 0x4D -> LATIN SMALL LETTER M - 'n' , // n 0x4E -> LATIN SMALL LETTER N - 'o' , // o 0x4F -> LATIN SMALL LETTER O - 'p' , // p 0x50 -> LATIN SMALL LETTER P - 'q' , // q 0x51 -> LATIN SMALL LETTER Q - 'r' , // r 0x52 -> LATIN SMALL LETTER R - 's' , // s 0x53 -> LATIN SMALL LETTER S - 't' , // t 0x54 -> LATIN SMALL LETTER T - 'u' , // u 0x55 -> LATIN SMALL LETTER U - 'v' , // v 0x56 -> LATIN SMALL LETTER V - 'w' , // w 0x57 -> LATIN SMALL LETTER W - 'x' , // x 0x58 -> LATIN SMALL LETTER X - 'y' , // y 0x59 -> LATIN SMALL LETTER Y - 'z' , // z 0x5A -> LATIN SMALL LETTER Z - '[' , // [ 0x5B -> LEFT SQUARE BRACKET - '\u00a3', // £ 0x5C -> POUND SIGN - ']' , // ] 0x5D -> RIGHT SQUARE BRACKET - '\u2191', // ↑ 0x5E -> UPWARDS ARROW - '\u2190', // ← 0x5F -> LEFTWARDS ARROW - '\u2500', // ─ 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL - 'A' , // A 0x61 -> LATIN CAPITAL LETTER A - 'B' , // B 0x62 -> LATIN CAPITAL LETTER B - 'C' , // C 0x63 -> LATIN CAPITAL LETTER C - 'D' , // D 0x64 -> LATIN CAPITAL LETTER D - 'E' , // E 0x65 -> LATIN CAPITAL LETTER E - 'F' , // F 0x66 -> LATIN CAPITAL LETTER F - 'G' , // G 0x67 -> LATIN CAPITAL LETTER G - 'H' , // H 0x68 -> LATIN CAPITAL LETTER H - 'I' , // I 0x69 -> LATIN CAPITAL LETTER I - 'J' , // J 0x6A -> LATIN CAPITAL LETTER J - 'K' , // K 0x6B -> LATIN CAPITAL LETTER K - 'L' , // L 0x6C -> LATIN CAPITAL LETTER L - 'M' , // M 0x6D -> LATIN CAPITAL LETTER M - 'N' , // N 0x6E -> LATIN CAPITAL LETTER N - 'O' , // O 0x6F -> LATIN CAPITAL LETTER O - 'P' , // P 0x70 -> LATIN CAPITAL LETTER P - 'Q' , // Q 0x71 -> LATIN CAPITAL LETTER Q - 'R' , // R 0x72 -> LATIN CAPITAL LETTER R - 'S' , // S 0x73 -> LATIN CAPITAL LETTER S - 'T' , // T 0x74 -> LATIN CAPITAL LETTER T - 'U' , // U 0x75 -> LATIN CAPITAL LETTER U - 'V' , // V 0x76 -> LATIN CAPITAL LETTER V - 'W' , // W 0x77 -> LATIN CAPITAL LETTER W - 'X' , // X 0x78 -> LATIN CAPITAL LETTER X - 'Y' , // Y 0x79 -> LATIN CAPITAL LETTER Y - 'Z' , // Z 0x7A -> LATIN CAPITAL LETTER Z - '\u253c', // ┼ 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0x7D -> BOX DRAWINGS LIGHT VERTICAL - '\u2592', // ▒ 0x7E -> MEDIUM SHADE - '\uf139', //  0x7F -> MEDIUM SHADE SLASHED LEFT (CUS) - '\ufffe', // 0x80 -> UNDEFINED - '\uf104', // 0x81 -> ORANGE COLOR SWITCH (CUS) - '\ufffe', // 0x82 -> UNDEFINED - '\ufffe', // 0x83 -> UNDEFINED - '\ufffe', // 0x84 -> UNDEFINED - '\uf110', //  0x85 -> FUNCTION KEY 1 (CUS) - '\uf112', //  0x86 -> FUNCTION KEY 3 (CUS) - '\uf114', //  0x87 -> FUNCTION KEY 5 (CUS) - '\uf116', //  0x88 -> FUNCTION KEY 7 (CUS) - '\uf111', //  0x89 -> FUNCTION KEY 2 (CUS) - '\uf113', //  0x8A -> FUNCTION KEY 4 (CUS) - '\uf115', //  0x8B -> FUNCTION KEY 6 (CUS) - '\uf117', //  0x8C -> FUNCTION KEY 8 (CUS) - '\n' , // 0x8D -> LINE FEED - '\u000f', //  0x8E -> SHIFT IN - '\ufffe', // 0x8F -> UNDEFINED - '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) - '\uf11e', //  0x91 -> CURSOR UP (CUS) - '\uf11b', //  0x92 -> REVERSE VIDEO OFF (CUS) - '\u000c', // 0x93 -> FORM FEED - '\uf121', //  0x94 -> INSERT (CUS) - '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) - '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) - '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) - '\uf109', //  0x98 -> GRAY 2 COLOR SWITCH (CUS) - '\uf10a', //  0x99 -> LIGHT GREEN COLOR SWITCH (CUS) - '\uf10b', //  0x9A -> LIGHT BLUE COLOR SWITCH (CUS) - '\uf10c', //  0x9B -> GRAY 3 COLOR SWITCH (CUS) - '\uf10d', //  0x9C -> PURPLE COLOR SWITCH (CUS) - '\uf11d', //  0x9D -> CURSOR LEFT (CUS) - '\uf10e', //  0x9E -> YELLOW COLOR SWITCH (CUS) - '\uf10f', //  0x9F -> CYAN COLOR SWITCH (CUS) - '\u00a0', // 0xA0 -> NO-BREAK SPACE - '\u258c', // ▌ 0xA1 -> LEFT HALF BLOCK - '\u2584', // ▄ 0xA2 -> LOWER HALF BLOCK - '\u2594', // ▔ 0xA3 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0xA4 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0xA5 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0xA6 -> MEDIUM SHADE - '\u2595', // ▕ 0xA7 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\uf13a', //  0xA9 -> MEDIUM SHADE SLASHED RIGHT (CUS) - '\uf130', //  0xAA -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0xAC -> QUADRANT LOWER RIGHT - '\u2514', // └ 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0xAF -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0xB4 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0xB5 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0xB7 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0xB9 -> LOWER THREE EIGHTHS BLOCK - '\u2713', // ✓ 0xBA -> CHECK MARK - '\u2596', // ▖ 0xBB -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0xBC -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0xBE -> QUADRANT UPPER LEFT - '\u259a', // ▚ 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT - '\u2500', // ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL - 'A' , // A 0xC1 -> LATIN CAPITAL LETTER A - 'B' , // B 0xC2 -> LATIN CAPITAL LETTER B - 'C' , // C 0xC3 -> LATIN CAPITAL LETTER C - 'D' , // D 0xC4 -> LATIN CAPITAL LETTER D - 'E' , // E 0xC5 -> LATIN CAPITAL LETTER E - 'F' , // F 0xC6 -> LATIN CAPITAL LETTER F - 'G' , // G 0xC7 -> LATIN CAPITAL LETTER G - 'H' , // H 0xC8 -> LATIN CAPITAL LETTER H - 'I' , // I 0xC9 -> LATIN CAPITAL LETTER I - 'J' , // J 0xCA -> LATIN CAPITAL LETTER J - 'K' , // K 0xCB -> LATIN CAPITAL LETTER K - 'L' , // L 0xCC -> LATIN CAPITAL LETTER L - 'M' , // M 0xCD -> LATIN CAPITAL LETTER M - 'N' , // N 0xCE -> LATIN CAPITAL LETTER N - 'O' , // O 0xCF -> LATIN CAPITAL LETTER O - 'P' , // P 0xD0 -> LATIN CAPITAL LETTER P - 'Q' , // Q 0xD1 -> LATIN CAPITAL LETTER Q - 'R' , // R 0xD2 -> LATIN CAPITAL LETTER R - 'S' , // S 0xD3 -> LATIN CAPITAL LETTER S - 'T' , // T 0xD4 -> LATIN CAPITAL LETTER T - 'U' , // U 0xD5 -> LATIN CAPITAL LETTER U - 'V' , // V 0xD6 -> LATIN CAPITAL LETTER V - 'W' , // W 0xD7 -> LATIN CAPITAL LETTER W - 'X' , // X 0xD8 -> LATIN CAPITAL LETTER X - 'Y' , // Y 0xD9 -> LATIN CAPITAL LETTER Y - 'Z' , // Z 0xDA -> LATIN CAPITAL LETTER Z - '\u253c', // ┼ 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0xDD -> BOX DRAWINGS LIGHT VERTICAL - '\u2592', // ▒ 0xDE -> MEDIUM SHADE - '\uf139', //  0xDF -> MEDIUM SHADE SLASHED LEFT (CUS) - '\u00a0', // 0xE0 -> NO-BREAK SPACE - '\u258c', // ▌ 0xE1 -> LEFT HALF BLOCK - '\u2584', // ▄ 0xE2 -> LOWER HALF BLOCK - '\u2594', // ▔ 0xE3 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0xE4 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0xE5 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0xE6 -> MEDIUM SHADE - '\u2595', // ▕ 0xE7 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\uf13a', //  0xE9 -> MEDIUM SHADE SLASHED RIGHT (CUS) - '\uf130', //  0xEA -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0xEC -> QUADRANT LOWER RIGHT - '\u2514', // └ 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0xEF -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0xF4 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0xF5 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0xF7 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0xF9 -> LOWER THREE EIGHTHS BLOCK - '\u2713', // ✓ 0xFA -> CHECK MARK - '\u2596', // ▖ 0xFB -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0xFC -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0xFE -> QUADRANT UPPER LEFT - '\u2592' // ▒ 0xFF -> MEDIUM SHADE + '\u0000', // 0x00 -> \u0000 + '\ufffe', // 0x01 -> UNDEFINED + '\ufffe', // 0x02 -> UNDEFINED + '\ufffe', // 0x03 -> UNDEFINED + '\ufffe', // 0x04 -> UNDEFINED + '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) + '\ufffe', // 0x06 -> UNDEFINED + '\ufffe', // 0x07 -> UNDEFINED + '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) + '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) + '\ufffe', // 0x0A -> UNDEFINED + '\ufffe', // 0x0B -> UNDEFINED + '\ufffe', // 0x0C -> UNDEFINED + '\r' , // 0x0D -> CARRIAGE RETURN + '\u000e', // 0x0E -> SHIFT OUT + '\ufffe', // 0x0F -> UNDEFINED + '\ufffe', // 0x10 -> UNDEFINED + '\uf11c', // 0x11 -> CURSOR DOWN (CUS) + '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) + '\uf120', // 0x13 -> HOME (CUS) + '\u007f', // 0x14 -> DELETE + '\ufffe', // 0x15 -> UNDEFINED + '\ufffe', // 0x16 -> UNDEFINED + '\ufffe', // 0x17 -> UNDEFINED + '\ufffe', // 0x18 -> UNDEFINED + '\ufffe', // 0x19 -> UNDEFINED + '\ufffe', // 0x1A -> UNDEFINED + '\ufffe', // 0x1B -> UNDEFINED + '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) + '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) + '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) + '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) + ' ' , // 0x20 -> SPACE + '!' , // ! 0x21 -> EXCLAMATION MARK + '"' , // " 0x22 -> QUOTATION MARK + '#' , // # 0x23 -> NUMBER SIGN + '$' , // $ 0x24 -> DOLLAR SIGN + '%' , // % 0x25 -> PERCENT SIGN + '&' , // & 0x26 -> AMPERSAND + '\'' , // ' 0x27 -> APOSTROPHE + '(' , // ( 0x28 -> LEFT PARENTHESIS + ')' , // ) 0x29 -> RIGHT PARENTHESIS + '*' , // * 0x2A -> ASTERISK + '+' , // + 0x2B -> PLUS SIGN + ',' , // , 0x2C -> COMMA + '-' , // - 0x2D -> HYPHEN-MINUS + '.' , // . 0x2E -> FULL STOP + '/' , // / 0x2F -> SOLIDUS + '0' , // 0 0x30 -> DIGIT ZERO + '1' , // 1 0x31 -> DIGIT ONE + '2' , // 2 0x32 -> DIGIT TWO + '3' , // 3 0x33 -> DIGIT THREE + '4' , // 4 0x34 -> DIGIT FOUR + '5' , // 5 0x35 -> DIGIT FIVE + '6' , // 6 0x36 -> DIGIT SIX + '7' , // 7 0x37 -> DIGIT SEVEN + '8' , // 8 0x38 -> DIGIT EIGHT + '9' , // 9 0x39 -> DIGIT NINE + ':' , // : 0x3A -> COLON + ';' , // ; 0x3B -> SEMICOLON + '<' , // < 0x3C -> LESS-THAN SIGN + '=' , // = 0x3D -> EQUALS SIGN + '>' , // > 0x3E -> GREATER-THAN SIGN + '?' , // ? 0x3F -> QUESTION MARK + '@' , // @ 0x40 -> COMMERCIAL AT + 'a' , // a 0x41 -> LATIN SMALL LETTER A + 'b' , // b 0x42 -> LATIN SMALL LETTER B + 'c' , // c 0x43 -> LATIN SMALL LETTER C + 'd' , // d 0x44 -> LATIN SMALL LETTER D + 'e' , // e 0x45 -> LATIN SMALL LETTER E + 'f' , // f 0x46 -> LATIN SMALL LETTER F + 'g' , // g 0x47 -> LATIN SMALL LETTER G + 'h' , // h 0x48 -> LATIN SMALL LETTER H + 'i' , // i 0x49 -> LATIN SMALL LETTER I + 'j' , // j 0x4A -> LATIN SMALL LETTER J + 'k' , // k 0x4B -> LATIN SMALL LETTER K + 'l' , // l 0x4C -> LATIN SMALL LETTER L + 'm' , // m 0x4D -> LATIN SMALL LETTER M + 'n' , // n 0x4E -> LATIN SMALL LETTER N + 'o' , // o 0x4F -> LATIN SMALL LETTER O + 'p' , // p 0x50 -> LATIN SMALL LETTER P + 'q' , // q 0x51 -> LATIN SMALL LETTER Q + 'r' , // r 0x52 -> LATIN SMALL LETTER R + 's' , // s 0x53 -> LATIN SMALL LETTER S + 't' , // t 0x54 -> LATIN SMALL LETTER T + 'u' , // u 0x55 -> LATIN SMALL LETTER U + 'v' , // v 0x56 -> LATIN SMALL LETTER V + 'w' , // w 0x57 -> LATIN SMALL LETTER W + 'x' , // x 0x58 -> LATIN SMALL LETTER X + 'y' , // y 0x59 -> LATIN SMALL LETTER Y + 'z' , // z 0x5A -> LATIN SMALL LETTER Z + '[' , // [ 0x5B -> LEFT SQUARE BRACKET + '\u00a3', // £ 0x5C -> POUND SIGN + ']' , // ] 0x5D -> RIGHT SQUARE BRACKET + '\u2191', // ↑ 0x5E -> UPWARDS ARROW + '\u2190', // ← 0x5F -> LEFTWARDS ARROW + '\u2500', // ─ 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // A 0x61 -> LATIN CAPITAL LETTER A + 'B' , // B 0x62 -> LATIN CAPITAL LETTER B + 'C' , // C 0x63 -> LATIN CAPITAL LETTER C + 'D' , // D 0x64 -> LATIN CAPITAL LETTER D + 'E' , // E 0x65 -> LATIN CAPITAL LETTER E + 'F' , // F 0x66 -> LATIN CAPITAL LETTER F + 'G' , // G 0x67 -> LATIN CAPITAL LETTER G + 'H' , // H 0x68 -> LATIN CAPITAL LETTER H + 'I' , // I 0x69 -> LATIN CAPITAL LETTER I + 'J' , // J 0x6A -> LATIN CAPITAL LETTER J + 'K' , // K 0x6B -> LATIN CAPITAL LETTER K + 'L' , // L 0x6C -> LATIN CAPITAL LETTER L + 'M' , // M 0x6D -> LATIN CAPITAL LETTER M + 'N' , // N 0x6E -> LATIN CAPITAL LETTER N + 'O' , // O 0x6F -> LATIN CAPITAL LETTER O + 'P' , // P 0x70 -> LATIN CAPITAL LETTER P + 'Q' , // Q 0x71 -> LATIN CAPITAL LETTER Q + 'R' , // R 0x72 -> LATIN CAPITAL LETTER R + 'S' , // S 0x73 -> LATIN CAPITAL LETTER S + 'T' , // T 0x74 -> LATIN CAPITAL LETTER T + 'U' , // U 0x75 -> LATIN CAPITAL LETTER U + 'V' , // V 0x76 -> LATIN CAPITAL LETTER V + 'W' , // W 0x77 -> LATIN CAPITAL LETTER W + 'X' , // X 0x78 -> LATIN CAPITAL LETTER X + 'Y' , // Y 0x79 -> LATIN CAPITAL LETTER Y + 'Z' , // Z 0x7A -> LATIN CAPITAL LETTER Z + '\u253c', // ┼ 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0x7D -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // ▒ 0x7E -> MEDIUM SHADE + '\uf139', //  0x7F -> MEDIUM SHADE SLASHED LEFT (CUS) + '\ufffe', // 0x80 -> UNDEFINED + '\uf104', // 0x81 -> ORANGE COLOR SWITCH (CUS) + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\uf110', //  0x85 -> FUNCTION KEY 1 (CUS) + '\uf112', //  0x86 -> FUNCTION KEY 3 (CUS) + '\uf114', //  0x87 -> FUNCTION KEY 5 (CUS) + '\uf116', //  0x88 -> FUNCTION KEY 7 (CUS) + '\uf111', //  0x89 -> FUNCTION KEY 2 (CUS) + '\uf113', //  0x8A -> FUNCTION KEY 4 (CUS) + '\uf115', //  0x8B -> FUNCTION KEY 6 (CUS) + '\uf117', //  0x8C -> FUNCTION KEY 8 (CUS) + '\n' , // 0x8D -> LINE FEED + '\u000f', //  0x8E -> SHIFT IN + '\ufffe', // 0x8F -> UNDEFINED + '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) + '\uf11e', //  0x91 -> CURSOR UP (CUS) + '\uf11b', //  0x92 -> REVERSE VIDEO OFF (CUS) + '\u000c', // 0x93 -> FORM FEED + '\uf121', //  0x94 -> INSERT (CUS) + '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) + '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) + '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) + '\uf109', //  0x98 -> GRAY 2 COLOR SWITCH (CUS) + '\uf10a', //  0x99 -> LIGHT GREEN COLOR SWITCH (CUS) + '\uf10b', //  0x9A -> LIGHT BLUE COLOR SWITCH (CUS) + '\uf10c', //  0x9B -> GRAY 3 COLOR SWITCH (CUS) + '\uf10d', //  0x9C -> PURPLE COLOR SWITCH (CUS) + '\uf11d', //  0x9D -> CURSOR LEFT (CUS) + '\uf10e', //  0x9E -> YELLOW COLOR SWITCH (CUS) + '\uf10f', //  0x9F -> CYAN COLOR SWITCH (CUS) + '\u00a0', // 0xA0 -> NO-BREAK SPACE + '\u258c', // ▌ 0xA1 -> LEFT HALF BLOCK + '\u2584', // ▄ 0xA2 -> LOWER HALF BLOCK + '\u2594', // ▔ 0xA3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0xA4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0xA5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0xA6 -> MEDIUM SHADE + '\u2595', // ▕ 0xA7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', //  0xA9 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', //  0xAA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0xAC -> QUADRANT LOWER RIGHT + '\u2514', // └ 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0xAF -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0xB4 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0xB5 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0xB7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0xB9 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // ✓ 0xBA -> CHECK MARK + '\u2596', // ▖ 0xBB -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0xBC -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0xBE -> QUADRANT UPPER LEFT + '\u259a', // ▚ 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\u2500', // ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // A 0xC1 -> LATIN CAPITAL LETTER A + 'B' , // B 0xC2 -> LATIN CAPITAL LETTER B + 'C' , // C 0xC3 -> LATIN CAPITAL LETTER C + 'D' , // D 0xC4 -> LATIN CAPITAL LETTER D + 'E' , // E 0xC5 -> LATIN CAPITAL LETTER E + 'F' , // F 0xC6 -> LATIN CAPITAL LETTER F + 'G' , // G 0xC7 -> LATIN CAPITAL LETTER G + 'H' , // H 0xC8 -> LATIN CAPITAL LETTER H + 'I' , // I 0xC9 -> LATIN CAPITAL LETTER I + 'J' , // J 0xCA -> LATIN CAPITAL LETTER J + 'K' , // K 0xCB -> LATIN CAPITAL LETTER K + 'L' , // L 0xCC -> LATIN CAPITAL LETTER L + 'M' , // M 0xCD -> LATIN CAPITAL LETTER M + 'N' , // N 0xCE -> LATIN CAPITAL LETTER N + 'O' , // O 0xCF -> LATIN CAPITAL LETTER O + 'P' , // P 0xD0 -> LATIN CAPITAL LETTER P + 'Q' , // Q 0xD1 -> LATIN CAPITAL LETTER Q + 'R' , // R 0xD2 -> LATIN CAPITAL LETTER R + 'S' , // S 0xD3 -> LATIN CAPITAL LETTER S + 'T' , // T 0xD4 -> LATIN CAPITAL LETTER T + 'U' , // U 0xD5 -> LATIN CAPITAL LETTER U + 'V' , // V 0xD6 -> LATIN CAPITAL LETTER V + 'W' , // W 0xD7 -> LATIN CAPITAL LETTER W + 'X' , // X 0xD8 -> LATIN CAPITAL LETTER X + 'Y' , // Y 0xD9 -> LATIN CAPITAL LETTER Y + 'Z' , // Z 0xDA -> LATIN CAPITAL LETTER Z + '\u253c', // ┼ 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0xDD -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // ▒ 0xDE -> MEDIUM SHADE + '\uf139', //  0xDF -> MEDIUM SHADE SLASHED LEFT (CUS) + '\u00a0', // 0xE0 -> NO-BREAK SPACE + '\u258c', // ▌ 0xE1 -> LEFT HALF BLOCK + '\u2584', // ▄ 0xE2 -> LOWER HALF BLOCK + '\u2594', // ▔ 0xE3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0xE4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0xE5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0xE6 -> MEDIUM SHADE + '\u2595', // ▕ 0xE7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', //  0xE9 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', //  0xEA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0xEC -> QUADRANT LOWER RIGHT + '\u2514', // └ 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0xEF -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0xF4 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0xF5 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0xF7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0xF9 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // ✓ 0xFA -> CHECK MARK + '\u2596', // ▖ 0xFB -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0xFC -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0xFE -> QUADRANT UPPER LEFT + '\u2592' // ▒ 0xFF -> MEDIUM SHADE ) private val decodingPetsciiUppercase = arrayOf( - '\u0000', // 0x00 -> \u0000 - '\ufffe', // 0x01 -> UNDEFINED - '\ufffe', // 0x02 -> UNDEFINED - '\ufffe', // 0x03 -> UNDEFINED - '\ufffe', // 0x04 -> UNDEFINED - '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) - '\ufffe', // 0x06 -> UNDEFINED - '\ufffe', // 0x07 -> UNDEFINED - '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) - '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) - '\ufffe', // 0x0A -> UNDEFINED - '\ufffe', // 0x0B -> UNDEFINED - '\ufffe', // 0x0C -> UNDEFINED - '\r' , // 0x0D -> CARRIAGE RETURN - '\u000e', // 0x0E -> SHIFT OUT - '\ufffe', // 0x0F -> UNDEFINED - '\ufffe', // 0x10 -> UNDEFINED - '\uf11c', // 0x11 -> CURSOR DOWN (CUS) - '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) - '\uf120', // 0x13 -> HOME (CUS) - '\u007f', // 0x14 -> DELETE - '\ufffe', // 0x15 -> UNDEFINED - '\ufffe', // 0x16 -> UNDEFINED - '\ufffe', // 0x17 -> UNDEFINED - '\ufffe', // 0x18 -> UNDEFINED - '\ufffe', // 0x19 -> UNDEFINED - '\ufffe', // 0x1A -> UNDEFINED - '\ufffe', // 0x1B -> UNDEFINED - '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) - '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) - '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) - '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) - ' ' , // 0x20 -> SPACE - '!' , // ! 0x21 -> EXCLAMATION MARK - '"' , // " 0x22 -> QUOTATION MARK - '#' , // # 0x23 -> NUMBER SIGN - '$' , // $ 0x24 -> DOLLAR SIGN - '%' , // % 0x25 -> PERCENT SIGN - '&' , // & 0x26 -> AMPERSAND - '\'' , // ' 0x27 -> APOSTROPHE - '(' , // ( 0x28 -> LEFT PARENTHESIS - ')' , // ) 0x29 -> RIGHT PARENTHESIS - '*' , // * 0x2A -> ASTERISK - '+' , // + 0x2B -> PLUS SIGN - ',' , // , 0x2C -> COMMA - '-' , // - 0x2D -> HYPHEN-MINUS - '.' , // . 0x2E -> FULL STOP - '/' , // / 0x2F -> SOLIDUS - '0' , // 0 0x30 -> DIGIT ZERO - '1' , // 1 0x31 -> DIGIT ONE - '2' , // 2 0x32 -> DIGIT TWO - '3' , // 3 0x33 -> DIGIT THREE - '4' , // 4 0x34 -> DIGIT FOUR - '5' , // 5 0x35 -> DIGIT FIVE - '6' , // 6 0x36 -> DIGIT SIX - '7' , // 7 0x37 -> DIGIT SEVEN - '8' , // 8 0x38 -> DIGIT EIGHT - '9' , // 9 0x39 -> DIGIT NINE - ':' , // : 0x3A -> COLON - ';' , // ; 0x3B -> SEMICOLON - '<' , // < 0x3C -> LESS-THAN SIGN - '=' , // = 0x3D -> EQUALS SIGN - '>' , // > 0x3E -> GREATER-THAN SIGN - '?' , // ? 0x3F -> QUESTION MARK - '@' , // @ 0x40 -> COMMERCIAL AT - 'A' , // A 0x41 -> LATIN CAPITAL LETTER A - 'B' , // B 0x42 -> LATIN CAPITAL LETTER B - 'C' , // C 0x43 -> LATIN CAPITAL LETTER C - 'D' , // D 0x44 -> LATIN CAPITAL LETTER D - 'E' , // E 0x45 -> LATIN CAPITAL LETTER E - 'F' , // F 0x46 -> LATIN CAPITAL LETTER F - 'G' , // G 0x47 -> LATIN CAPITAL LETTER G - 'H' , // H 0x48 -> LATIN CAPITAL LETTER H - 'I' , // I 0x49 -> LATIN CAPITAL LETTER I - 'J' , // J 0x4A -> LATIN CAPITAL LETTER J - 'K' , // K 0x4B -> LATIN CAPITAL LETTER K - 'L' , // L 0x4C -> LATIN CAPITAL LETTER L - 'M' , // M 0x4D -> LATIN CAPITAL LETTER M - 'N' , // N 0x4E -> LATIN CAPITAL LETTER N - 'O' , // O 0x4F -> LATIN CAPITAL LETTER O - 'P' , // P 0x50 -> LATIN CAPITAL LETTER P - 'Q' , // Q 0x51 -> LATIN CAPITAL LETTER Q - 'R' , // R 0x52 -> LATIN CAPITAL LETTER R - 'S' , // S 0x53 -> LATIN CAPITAL LETTER S - 'T' , // T 0x54 -> LATIN CAPITAL LETTER T - 'U' , // U 0x55 -> LATIN CAPITAL LETTER U - 'V' , // V 0x56 -> LATIN CAPITAL LETTER V - 'W' , // W 0x57 -> LATIN CAPITAL LETTER W - 'X' , // X 0x58 -> LATIN CAPITAL LETTER X - 'Y' , // Y 0x59 -> LATIN CAPITAL LETTER Y - 'Z' , // Z 0x5A -> LATIN CAPITAL LETTER Z - '[' , // [ 0x5B -> LEFT SQUARE BRACKET - '\u00a3', // £ 0x5C -> POUND SIGN - ']' , // ] 0x5D -> RIGHT SQUARE BRACKET - '\u2191', // ↑ 0x5E -> UPWARDS ARROW - '\u2190', // ← 0x5F -> LEFTWARDS ARROW - '\u2500', // ─ 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL - '\u2660', // ♠ 0x61 -> BLACK SPADE SUIT - '\u2502', // │ 0x62 -> BOX DRAWINGS LIGHT VERTICAL - '\u2500', // ─ 0x63 -> BOX DRAWINGS LIGHT HORIZONTAL - '\uf122', //  0x64 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) - '\uf123', //  0x65 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) - '\uf124', //  0x66 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) - '\uf126', //  0x67 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) - '\uf128', //  0x68 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) - '\u256e', // ╮ 0x69 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT - '\u2570', // ╰ 0x6A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT - '\u256f', // ╯ 0x6B -> BOX DRAWINGS LIGHT ARC UP AND LEFT - '\uf12a', //  0x6C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) - '\u2572', // ╲ 0x6D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - '\u2571', // ╱ 0x6E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - '\uf12b', //  0x6F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) - '\uf12c', //  0x70 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) - '\u25cf', // ● 0x71 -> BLACK CIRCLE - '\uf125', //  0x72 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) - '\u2665', // ♥ 0x73 -> BLACK HEART SUIT - '\uf127', //  0x74 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) - '\u256d', // ╭ 0x75 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT - '\u2573', // ╳ 0x76 -> BOX DRAWINGS LIGHT DIAGONAL CROSS - '\u25cb', // ○ 0x77 -> WHITE CIRCLE - '\u2663', // ♣ 0x78 -> BLACK CLUB SUIT - '\uf129', //  0x79 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) - '\u2666', // ♦ 0x7A -> BLACK DIAMOND SUIT - '\u253c', // ┼ 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0x7D -> BOX DRAWINGS LIGHT VERTICAL - '\u03c0', // π 0x7E -> GREEK SMALL LETTER PI - '\u25e5', // ◥ 0x7F -> BLACK UPPER RIGHT TRIANGLE - '\ufffe', // 0x80 -> UNDEFINED - '\uf104', //  0x81 -> ORANGE COLOR SWITCH (CUS) - '\ufffe', // 0x82 -> UNDEFINED - '\ufffe', // 0x83 -> UNDEFINED - '\ufffe', // 0x84 -> UNDEFINED - '\uf110', // 0x85 -> FUNCTION KEY 1 (CUS) - '\uf112', // 0x86 -> FUNCTION KEY 3 (CUS) - '\uf114', // 0x87 -> FUNCTION KEY 5 (CUS) - '\uf116', // 0x88 -> FUNCTION KEY 7 (CUS) - '\uf111', // 0x89 -> FUNCTION KEY 2 (CUS) - '\uf113', // 0x8A -> FUNCTION KEY 4 (CUS) - '\uf115', // 0x8B -> FUNCTION KEY 6 (CUS) - '\uf117', // 0x8C -> FUNCTION KEY 8 (CUS) - '\n' , // 0x8D -> LINE FEED - '\u000f', // 0x8E -> SHIFT IN - '\ufffe', // 0x8F -> UNDEFINED - '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) - '\uf11e', // 0x91 -> CURSOR UP (CUS) - '\uf11b', // 0x92 -> REVERSE VIDEO OFF (CUS) - '\u000c', // 0x93 -> FORM FEED - '\uf121', // 0x94 -> INSERT (CUS) - '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) - '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) - '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) - '\uf109', // 0x98 -> GRAY 2 COLOR SWITCH (CUS) - '\uf10a', // 0x99 -> LIGHT GREEN COLOR SWITCH (CUS) - '\uf10b', // 0x9A -> LIGHT BLUE COLOR SWITCH (CUS) - '\uf10c', // 0x9B -> GRAY 3 COLOR SWITCH (CUS) - '\uf10d', // 0x9C -> PURPLE COLOR SWITCH (CUS) - '\uf11d', // 0x9D -> CURSOR LEFT (CUS) - '\uf10e', // 0x9E -> YELLOW COLOR SWITCH (CUS) - '\uf10f', // 0x9F -> CYAN COLOR SWITCH (CUS) - '\u00a0', // 0xA0 -> NO-BREAK SPACE - '\u258c', // ▌ 0xA1 -> LEFT HALF BLOCK - '\u2584', // ▄ 0xA2 -> LOWER HALF BLOCK - '\u2594', // ▔ 0xA3 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0xA4 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0xA5 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0xA6 -> MEDIUM SHADE - '\u2595', // ▕ 0xA7 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\u25e4', // ◤ 0xA9 -> BLACK UPPER LEFT TRIANGLE - '\uf130', //  0xAA -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0xAC -> QUADRANT LOWER RIGHT - '\u2514', // └ 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0xAF -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0xB4 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0xB5 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0xB7 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0xB9 -> LOWER THREE EIGHTHS BLOCK - '\uf12d', //  0xBA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) - '\u2596', // ▖ 0xBB -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0xBC -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0xBE -> QUADRANT UPPER LEFT - '\u259a', // ▚ 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT - '\u2500', // ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL - '\u2660', // ♠ 0xC1 -> BLACK SPADE SUIT - '\u2502', // │ 0xC2 -> BOX DRAWINGS LIGHT VERTICAL - '\u2500', // ─ 0xC3 -> BOX DRAWINGS LIGHT HORIZONTAL - '\uf122', //  0xC4 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) - '\uf123', //  0xC5 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) - '\uf124', //  0xC6 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) - '\uf126', //  0xC7 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) - '\uf128', //  0xC8 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) - '\u256e', // ╮ 0xC9 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT - '\u2570', // ╰ 0xCA -> BOX DRAWINGS LIGHT ARC UP AND RIGHT - '\u256f', // ╯ 0xCB -> BOX DRAWINGS LIGHT ARC UP AND LEFT - '\uf12a', //  0xCC -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) - '\u2572', // ╲ 0xCD -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - '\u2571', // ╱ 0xCE -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - '\uf12b', //  0xCF -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) - '\uf12c', //  0xD0 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) - '\u25cf', // ● 0xD1 -> BLACK CIRCLE - '\uf125', //  0xD2 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) - '\u2665', // ♥ 0xD3 -> BLACK HEART SUIT - '\uf127', //  0xD4 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) - '\u256d', // ╭ 0xD5 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT - '\u2573', // ╳ 0xD6 -> BOX DRAWINGS LIGHT DIAGONAL CROSS - '\u25cb', // ○ 0xD7 -> WHITE CIRCLE - '\u2663', // ♣ 0xD8 -> BLACK CLUB SUIT - '\uf129', //  0xD9 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) - '\u2666', // ♦ 0xDA -> BLACK DIAMOND SUIT - '\u253c', // ┼ 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0xDD -> BOX DRAWINGS LIGHT VERTICAL - '\u03c0', // π 0xDE -> GREEK SMALL LETTER PI - '\u25e5', // ◥ 0xDF -> BLACK UPPER RIGHT TRIANGLE - '\u00a0', // 0xE0 -> NO-BREAK SPACE - '\u258c', // ▌ 0xE1 -> LEFT HALF BLOCK - '\u2584', // ▄ 0xE2 -> LOWER HALF BLOCK - '\u2594', // ▔ 0xE3 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0xE4 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0xE5 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0xE6 -> MEDIUM SHADE - '\u2595', // ▕ 0xE7 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\u25e4', // ◤ 0xE9 -> BLACK UPPER LEFT TRIANGLE - '\uf130', //  0xEA -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0xEC -> QUADRANT LOWER RIGHT - '\u2514', // └ 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0xEF -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0xF4 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0xF5 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0xF7 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0xF9 -> LOWER THREE EIGHTHS BLOCK - '\uf12d', //  0xFA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) - '\u2596', // ▖ 0xFB -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0xFC -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0xFE -> QUADRANT UPPER LEFT - '\u03c0' // π 0xFF -> GREEK SMALL LETTER PI + '\u0000', // 0x00 -> \u0000 + '\ufffe', // 0x01 -> UNDEFINED + '\ufffe', // 0x02 -> UNDEFINED + '\ufffe', // 0x03 -> UNDEFINED + '\ufffe', // 0x04 -> UNDEFINED + '\uf100', // 0x05 -> WHITE COLOR SWITCH (CUS) + '\ufffe', // 0x06 -> UNDEFINED + '\ufffe', // 0x07 -> UNDEFINED + '\uf118', // 0x08 -> DISABLE CHARACTER SET SWITCHING (CUS) + '\uf119', // 0x09 -> ENABLE CHARACTER SET SWITCHING (CUS) + '\ufffe', // 0x0A -> UNDEFINED + '\ufffe', // 0x0B -> UNDEFINED + '\ufffe', // 0x0C -> UNDEFINED + '\r' , // 0x0D -> CARRIAGE RETURN + '\u000e', // 0x0E -> SHIFT OUT + '\ufffe', // 0x0F -> UNDEFINED + '\ufffe', // 0x10 -> UNDEFINED + '\uf11c', // 0x11 -> CURSOR DOWN (CUS) + '\uf11a', // 0x12 -> REVERSE VIDEO ON (CUS) + '\uf120', // 0x13 -> HOME (CUS) + '\u007f', // 0x14 -> DELETE + '\ufffe', // 0x15 -> UNDEFINED + '\ufffe', // 0x16 -> UNDEFINED + '\ufffe', // 0x17 -> UNDEFINED + '\ufffe', // 0x18 -> UNDEFINED + '\ufffe', // 0x19 -> UNDEFINED + '\ufffe', // 0x1A -> UNDEFINED + '\ufffe', // 0x1B -> UNDEFINED + '\uf101', // 0x1C -> RED COLOR SWITCH (CUS) + '\uf11d', // 0x1D -> CURSOR RIGHT (CUS) + '\uf102', // 0x1E -> GREEN COLOR SWITCH (CUS) + '\uf103', // 0x1F -> BLUE COLOR SWITCH (CUS) + ' ' , // 0x20 -> SPACE + '!' , // ! 0x21 -> EXCLAMATION MARK + '"' , // " 0x22 -> QUOTATION MARK + '#' , // # 0x23 -> NUMBER SIGN + '$' , // $ 0x24 -> DOLLAR SIGN + '%' , // % 0x25 -> PERCENT SIGN + '&' , // & 0x26 -> AMPERSAND + '\'' , // ' 0x27 -> APOSTROPHE + '(' , // ( 0x28 -> LEFT PARENTHESIS + ')' , // ) 0x29 -> RIGHT PARENTHESIS + '*' , // * 0x2A -> ASTERISK + '+' , // + 0x2B -> PLUS SIGN + ',' , // , 0x2C -> COMMA + '-' , // - 0x2D -> HYPHEN-MINUS + '.' , // . 0x2E -> FULL STOP + '/' , // / 0x2F -> SOLIDUS + '0' , // 0 0x30 -> DIGIT ZERO + '1' , // 1 0x31 -> DIGIT ONE + '2' , // 2 0x32 -> DIGIT TWO + '3' , // 3 0x33 -> DIGIT THREE + '4' , // 4 0x34 -> DIGIT FOUR + '5' , // 5 0x35 -> DIGIT FIVE + '6' , // 6 0x36 -> DIGIT SIX + '7' , // 7 0x37 -> DIGIT SEVEN + '8' , // 8 0x38 -> DIGIT EIGHT + '9' , // 9 0x39 -> DIGIT NINE + ':' , // : 0x3A -> COLON + ';' , // ; 0x3B -> SEMICOLON + '<' , // < 0x3C -> LESS-THAN SIGN + '=' , // = 0x3D -> EQUALS SIGN + '>' , // > 0x3E -> GREATER-THAN SIGN + '?' , // ? 0x3F -> QUESTION MARK + '@' , // @ 0x40 -> COMMERCIAL AT + 'A' , // A 0x41 -> LATIN CAPITAL LETTER A + 'B' , // B 0x42 -> LATIN CAPITAL LETTER B + 'C' , // C 0x43 -> LATIN CAPITAL LETTER C + 'D' , // D 0x44 -> LATIN CAPITAL LETTER D + 'E' , // E 0x45 -> LATIN CAPITAL LETTER E + 'F' , // F 0x46 -> LATIN CAPITAL LETTER F + 'G' , // G 0x47 -> LATIN CAPITAL LETTER G + 'H' , // H 0x48 -> LATIN CAPITAL LETTER H + 'I' , // I 0x49 -> LATIN CAPITAL LETTER I + 'J' , // J 0x4A -> LATIN CAPITAL LETTER J + 'K' , // K 0x4B -> LATIN CAPITAL LETTER K + 'L' , // L 0x4C -> LATIN CAPITAL LETTER L + 'M' , // M 0x4D -> LATIN CAPITAL LETTER M + 'N' , // N 0x4E -> LATIN CAPITAL LETTER N + 'O' , // O 0x4F -> LATIN CAPITAL LETTER O + 'P' , // P 0x50 -> LATIN CAPITAL LETTER P + 'Q' , // Q 0x51 -> LATIN CAPITAL LETTER Q + 'R' , // R 0x52 -> LATIN CAPITAL LETTER R + 'S' , // S 0x53 -> LATIN CAPITAL LETTER S + 'T' , // T 0x54 -> LATIN CAPITAL LETTER T + 'U' , // U 0x55 -> LATIN CAPITAL LETTER U + 'V' , // V 0x56 -> LATIN CAPITAL LETTER V + 'W' , // W 0x57 -> LATIN CAPITAL LETTER W + 'X' , // X 0x58 -> LATIN CAPITAL LETTER X + 'Y' , // Y 0x59 -> LATIN CAPITAL LETTER Y + 'Z' , // Z 0x5A -> LATIN CAPITAL LETTER Z + '[' , // [ 0x5B -> LEFT SQUARE BRACKET + '\u00a3', // £ 0x5C -> POUND SIGN + ']' , // ] 0x5D -> RIGHT SQUARE BRACKET + '\u2191', // ↑ 0x5E -> UPWARDS ARROW + '\u2190', // ← 0x5F -> LEFTWARDS ARROW + '\u2500', // ─ 0x60 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // ♠ 0x61 -> BLACK SPADE SUIT + '\u2502', // │ 0x62 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // ─ 0x63 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', //  0x64 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', //  0x65 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', //  0x66 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', //  0x67 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', //  0x68 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // ╮ 0x69 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // ╰ 0x6A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // ╯ 0x6B -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', //  0x6C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // ╲ 0x6D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // ╱ 0x6E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', //  0x6F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', //  0x70 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // ● 0x71 -> BLACK CIRCLE + '\uf125', //  0x72 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // ♥ 0x73 -> BLACK HEART SUIT + '\uf127', //  0x74 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // ╭ 0x75 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + '\u2573', // ╳ 0x76 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // ○ 0x77 -> WHITE CIRCLE + '\u2663', // ♣ 0x78 -> BLACK CLUB SUIT + '\uf129', //  0x79 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // ♦ 0x7A -> BLACK DIAMOND SUIT + '\u253c', // ┼ 0x7B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0x7C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0x7D -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // π 0x7E -> GREEK SMALL LETTER PI + '\u25e5', // ◥ 0x7F -> BLACK UPPER RIGHT TRIANGLE + '\ufffe', // 0x80 -> UNDEFINED + '\uf104', //  0x81 -> ORANGE COLOR SWITCH (CUS) + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\uf110', // 0x85 -> FUNCTION KEY 1 (CUS) + '\uf112', // 0x86 -> FUNCTION KEY 3 (CUS) + '\uf114', // 0x87 -> FUNCTION KEY 5 (CUS) + '\uf116', // 0x88 -> FUNCTION KEY 7 (CUS) + '\uf111', // 0x89 -> FUNCTION KEY 2 (CUS) + '\uf113', // 0x8A -> FUNCTION KEY 4 (CUS) + '\uf115', // 0x8B -> FUNCTION KEY 6 (CUS) + '\uf117', // 0x8C -> FUNCTION KEY 8 (CUS) + '\n' , // 0x8D -> LINE FEED + '\u000f', // 0x8E -> SHIFT IN + '\ufffe', // 0x8F -> UNDEFINED + '\uf105', // 0x90 -> BLACK COLOR SWITCH (CUS) + '\uf11e', // 0x91 -> CURSOR UP (CUS) + '\uf11b', // 0x92 -> REVERSE VIDEO OFF (CUS) + '\u000c', // 0x93 -> FORM FEED + '\uf121', // 0x94 -> INSERT (CUS) + '\uf106', // 0x95 -> BROWN COLOR SWITCH (CUS) + '\uf107', // 0x96 -> LIGHT RED COLOR SWITCH (CUS) + '\uf108', // 0x97 -> GRAY 1 COLOR SWITCH (CUS) + '\uf109', // 0x98 -> GRAY 2 COLOR SWITCH (CUS) + '\uf10a', // 0x99 -> LIGHT GREEN COLOR SWITCH (CUS) + '\uf10b', // 0x9A -> LIGHT BLUE COLOR SWITCH (CUS) + '\uf10c', // 0x9B -> GRAY 3 COLOR SWITCH (CUS) + '\uf10d', // 0x9C -> PURPLE COLOR SWITCH (CUS) + '\uf11d', // 0x9D -> CURSOR LEFT (CUS) + '\uf10e', // 0x9E -> YELLOW COLOR SWITCH (CUS) + '\uf10f', // 0x9F -> CYAN COLOR SWITCH (CUS) + '\u00a0', // 0xA0 -> NO-BREAK SPACE + '\u258c', // ▌ 0xA1 -> LEFT HALF BLOCK + '\u2584', // ▄ 0xA2 -> LOWER HALF BLOCK + '\u2594', // ▔ 0xA3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0xA4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0xA5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0xA6 -> MEDIUM SHADE + '\u2595', // ▕ 0xA7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0xA8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // ◤ 0xA9 -> BLACK UPPER LEFT TRIANGLE + '\uf130', //  0xAA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0xAB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0xAC -> QUADRANT LOWER RIGHT + '\u2514', // └ 0xAD -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0xAE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0xAF -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0xB0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0xB1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0xB2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0xB3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0xB4 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0xB5 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0xB6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0xB7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0xB8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0xB9 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', //  0xBA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // ▖ 0xBB -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0xBC -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0xBD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0xBE -> QUADRANT UPPER LEFT + '\u259a', // ▚ 0xBF -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\u2500', // ─ 0xC0 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // ♠ 0xC1 -> BLACK SPADE SUIT + '\u2502', // │ 0xC2 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // ─ 0xC3 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', //  0xC4 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', //  0xC5 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', //  0xC6 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', //  0xC7 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', //  0xC8 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // ╮ 0xC9 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // ╰ 0xCA -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // ╯ 0xCB -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', //  0xCC -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // ╲ 0xCD -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // ╱ 0xCE -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', //  0xCF -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', //  0xD0 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // ● 0xD1 -> BLACK CIRCLE + '\uf125', //  0xD2 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // ♥ 0xD3 -> BLACK HEART SUIT + '\uf127', //  0xD4 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // ╭ 0xD5 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2573', // ╳ 0xD6 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // ○ 0xD7 -> WHITE CIRCLE + '\u2663', // ♣ 0xD8 -> BLACK CLUB SUIT + '\uf129', //  0xD9 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // ♦ 0xDA -> BLACK DIAMOND SUIT + '\u253c', // ┼ 0xDB -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0xDC -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0xDD -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // π 0xDE -> GREEK SMALL LETTER PI + '\u25e5', // ◥ 0xDF -> BLACK UPPER RIGHT TRIANGLE + '\u00a0', // 0xE0 -> NO-BREAK SPACE + '\u258c', // ▌ 0xE1 -> LEFT HALF BLOCK + '\u2584', // ▄ 0xE2 -> LOWER HALF BLOCK + '\u2594', // ▔ 0xE3 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0xE4 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0xE5 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0xE6 -> MEDIUM SHADE + '\u2595', // ▕ 0xE7 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0xE8 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // ◤ 0xE9 -> BLACK UPPER LEFT TRIANGLE + '\uf130', //  0xEA -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0xEB -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0xEC -> QUADRANT LOWER RIGHT + '\u2514', // └ 0xED -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0xEE -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0xEF -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0xF0 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0xF1 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0xF2 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0xF3 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0xF4 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0xF5 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0xF6 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0xF7 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0xF8 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0xF9 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', //  0xFA -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // ▖ 0xFB -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0xFC -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0xFD -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0xFE -> QUADRANT UPPER LEFT + '\u03c0' // π 0xFF -> GREEK SMALL LETTER PI ) private val decodingScreencodeLowercase = arrayOf( - '@' , // @ 0x00 -> COMMERCIAL AT - 'a' , // a 0x01 -> LATIN SMALL LETTER A - 'b' , // b 0x02 -> LATIN SMALL LETTER B - 'c' , // c 0x03 -> LATIN SMALL LETTER C - 'd' , // d 0x04 -> LATIN SMALL LETTER D - 'e' , // e 0x05 -> LATIN SMALL LETTER E - 'f' , // f 0x06 -> LATIN SMALL LETTER F - 'g' , // g 0x07 -> LATIN SMALL LETTER G - 'h' , // h 0x08 -> LATIN SMALL LETTER H - 'i' , // i 0x09 -> LATIN SMALL LETTER I - 'j' , // j 0x0A -> LATIN SMALL LETTER J - 'k' , // k 0x0B -> LATIN SMALL LETTER K - 'l' , // l 0x0C -> LATIN SMALL LETTER L - 'm' , // m 0x0D -> LATIN SMALL LETTER M - 'n' , // n 0x0E -> LATIN SMALL LETTER N - 'o' , // o 0x0F -> LATIN SMALL LETTER O - 'p' , // p 0x10 -> LATIN SMALL LETTER P - 'q' , // q 0x11 -> LATIN SMALL LETTER Q - 'r' , // r 0x12 -> LATIN SMALL LETTER R - 's' , // s 0x13 -> LATIN SMALL LETTER S - 't' , // t 0x14 -> LATIN SMALL LETTER T - 'u' , // u 0x15 -> LATIN SMALL LETTER U - 'v' , // v 0x16 -> LATIN SMALL LETTER V - 'w' , // w 0x17 -> LATIN SMALL LETTER W - 'x' , // x 0x18 -> LATIN SMALL LETTER X - 'y' , // y 0x19 -> LATIN SMALL LETTER Y - 'z' , // z 0x1A -> LATIN SMALL LETTER Z - '[' , // [ 0x1B -> LEFT SQUARE BRACKET - '\u00a3', // £ 0x1C -> POUND SIGN - ']' , // ] 0x1D -> RIGHT SQUARE BRACKET - '\u2191', // ↑ 0x1E -> UPWARDS ARROW - '\u2190', // ← 0x1F -> LEFTWARDS ARROW - ' ' , // 0x20 -> SPACE - '!' , // ! 0x21 -> EXCLAMATION MARK - '"' , // " 0x22 -> QUOTATION MARK - '#' , // # 0x23 -> NUMBER SIGN - '$' , // $ 0x24 -> DOLLAR SIGN - '%' , // % 0x25 -> PERCENT SIGN - '&' , // & 0x26 -> AMPERSAND - '\'' , // ' 0x27 -> APOSTROPHE - '(' , // ( 0x28 -> LEFT PARENTHESIS - ')' , // ) 0x29 -> RIGHT PARENTHESIS - '*' , // * 0x2A -> ASTERISK - '+' , // + 0x2B -> PLUS SIGN - ',' , // , 0x2C -> COMMA - '-' , // - 0x2D -> HYPHEN-MINUS - '.' , // . 0x2E -> FULL STOP - '/' , // / 0x2F -> SOLIDUS - '0' , // 0 0x30 -> DIGIT ZERO - '1' , // 1 0x31 -> DIGIT ONE - '2' , // 2 0x32 -> DIGIT TWO - '3' , // 3 0x33 -> DIGIT THREE - '4' , // 4 0x34 -> DIGIT FOUR - '5' , // 5 0x35 -> DIGIT FIVE - '6' , // 6 0x36 -> DIGIT SIX - '7' , // 7 0x37 -> DIGIT SEVEN - '8' , // 8 0x38 -> DIGIT EIGHT - '9' , // 9 0x39 -> DIGIT NINE - ':' , // : 0x3A -> COLON - ';' , // ; 0x3B -> SEMICOLON - '<' , // < 0x3C -> LESS-THAN SIGN - '=' , // = 0x3D -> EQUALS SIGN - '>' , // > 0x3E -> GREATER-THAN SIGN - '?' , // ? 0x3F -> QUESTION MARK - '\u2500', // ─ 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL - 'A' , // A 0x41 -> LATIN CAPITAL LETTER A - 'B' , // B 0x42 -> LATIN CAPITAL LETTER B - 'C' , // C 0x43 -> LATIN CAPITAL LETTER C - 'D' , // D 0x44 -> LATIN CAPITAL LETTER D - 'E' , // E 0x45 -> LATIN CAPITAL LETTER E - 'F' , // F 0x46 -> LATIN CAPITAL LETTER F - 'G' , // G 0x47 -> LATIN CAPITAL LETTER G - 'H' , // H 0x48 -> LATIN CAPITAL LETTER H - 'I' , // I 0x49 -> LATIN CAPITAL LETTER I - 'J' , // J 0x4A -> LATIN CAPITAL LETTER J - 'K' , // K 0x4B -> LATIN CAPITAL LETTER K - 'L' , // L 0x4C -> LATIN CAPITAL LETTER L - 'M' , // M 0x4D -> LATIN CAPITAL LETTER M - 'N' , // N 0x4E -> LATIN CAPITAL LETTER N - 'O' , // O 0x4F -> LATIN CAPITAL LETTER O - 'P' , // P 0x50 -> LATIN CAPITAL LETTER P - 'Q' , // Q 0x51 -> LATIN CAPITAL LETTER Q - 'R' , // R 0x52 -> LATIN CAPITAL LETTER R - 'S' , // S 0x53 -> LATIN CAPITAL LETTER S - 'T' , // T 0x54 -> LATIN CAPITAL LETTER T - 'U' , // U 0x55 -> LATIN CAPITAL LETTER U - 'V' , // V 0x56 -> LATIN CAPITAL LETTER V - 'W' , // W 0x57 -> LATIN CAPITAL LETTER W - 'X' , // X 0x58 -> LATIN CAPITAL LETTER X - 'Y' , // Y 0x59 -> LATIN CAPITAL LETTER Y - 'Z' , // Z 0x5A -> LATIN CAPITAL LETTER Z - '\u253c', // ┼ 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0x5D -> BOX DRAWINGS LIGHT VERTICAL - '\u2592', // ▒ 0x5E -> MEDIUM SHADE - '\uf139', //  0x5F -> MEDIUM SHADE SLASHED LEFT (CUS) - '\u00a0', // 0x60 -> NO-BREAK SPACE - '\u258c', // ▌ 0x61 -> LEFT HALF BLOCK - '\u2584', // ▄ 0x62 -> LOWER HALF BLOCK - '\u2594', // ▔ 0x63 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0x64 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0x65 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0x66 -> MEDIUM SHADE - '\u2595', // ▕ 0x67 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\uf13a', //  0x69 -> MEDIUM SHADE SLASHED RIGHT (CUS) - '\uf130', //  0x6A -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0x6C -> QUADRANT LOWER RIGHT - '\u2514', // └ 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0x6F -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0x74 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0x75 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0x77 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0x78 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0x79 -> LOWER THREE EIGHTHS BLOCK - '\u2713', // ✓ 0x7A -> CHECK MARK - '\u2596', // ▖ 0x7B -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0x7C -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0x7E -> QUADRANT UPPER LEFT - '\u259a', // ▚ 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT - '\ufffe', // 0x80 -> UNDEFINED - '\ufffe', // 0x81 -> UNDEFINED - '\ufffe', // 0x82 -> UNDEFINED - '\ufffe', // 0x83 -> UNDEFINED - '\ufffe', // 0x84 -> UNDEFINED - '\ufffe', // 0x85 -> UNDEFINED - '\ufffe', // 0x86 -> UNDEFINED - '\ufffe', // 0x87 -> UNDEFINED - '\ufffe', // 0x88 -> UNDEFINED - '\ufffe', // 0x89 -> UNDEFINED - '\ufffe', // 0x8A -> UNDEFINED - '\ufffe', // 0x8B -> UNDEFINED - '\ufffe', // 0x8C -> UNDEFINED - '\ufffe', // 0x8D -> UNDEFINED - '\ufffe', // 0x8E -> UNDEFINED - '\ufffe', // 0x8F -> UNDEFINED - '\ufffe', // 0x90 -> UNDEFINED - '\ufffe', // 0x91 -> UNDEFINED - '\ufffe', // 0x92 -> UNDEFINED - '\ufffe', // 0x93 -> UNDEFINED - '\ufffe', // 0x94 -> UNDEFINED - '\ufffe', // 0x95 -> UNDEFINED - '\ufffe', // 0x96 -> UNDEFINED - '\ufffe', // 0x97 -> UNDEFINED - '\ufffe', // 0x98 -> UNDEFINED - '\ufffe', // 0x99 -> UNDEFINED - '\ufffe', // 0x9A -> UNDEFINED - '\ufffe', // 0x9B -> UNDEFINED - '\ufffe', // 0x9C -> UNDEFINED - '\ufffe', // 0x9D -> UNDEFINED - '\ufffe', // 0x9E -> UNDEFINED - '\ufffe', // 0x9F -> UNDEFINED - '\ufffe', // 0xA0 -> UNDEFINED - '\ufffe', // 0xA1 -> UNDEFINED - '\ufffe', // 0xA2 -> UNDEFINED - '\ufffe', // 0xA3 -> UNDEFINED - '\ufffe', // 0xA4 -> UNDEFINED - '\ufffe', // 0xA5 -> UNDEFINED - '\ufffe', // 0xA6 -> UNDEFINED - '\ufffe', // 0xA7 -> UNDEFINED - '\ufffe', // 0xA8 -> UNDEFINED - '\ufffe', // 0xA9 -> UNDEFINED - '\ufffe', // 0xAA -> UNDEFINED - '\ufffe', // 0xAB -> UNDEFINED - '\ufffe', // 0xAC -> UNDEFINED - '\ufffe', // 0xAD -> UNDEFINED - '\ufffe', // 0xAE -> UNDEFINED - '\ufffe', // 0xAF -> UNDEFINED - '\ufffe', // 0xB0 -> UNDEFINED - '\ufffe', // 0xB1 -> UNDEFINED - '\ufffe', // 0xB2 -> UNDEFINED - '\ufffe', // 0xB3 -> UNDEFINED - '\ufffe', // 0xB4 -> UNDEFINED - '\ufffe', // 0xB5 -> UNDEFINED - '\ufffe', // 0xB6 -> UNDEFINED - '\ufffe', // 0xB7 -> UNDEFINED - '\ufffe', // 0xB8 -> UNDEFINED - '\ufffe', // 0xB9 -> UNDEFINED - '\ufffe', // 0xBA -> UNDEFINED - '\ufffe', // 0xBB -> UNDEFINED - '\ufffe', // 0xBC -> UNDEFINED - '\ufffe', // 0xBD -> UNDEFINED - '\ufffe', // 0xBE -> UNDEFINED - '\ufffe', // 0xBF -> UNDEFINED - '\ufffe', // 0xC0 -> UNDEFINED - '\ufffe', // 0xC1 -> UNDEFINED - '\ufffe', // 0xC2 -> UNDEFINED - '\ufffe', // 0xC3 -> UNDEFINED - '\ufffe', // 0xC4 -> UNDEFINED - '\ufffe', // 0xC5 -> UNDEFINED - '\ufffe', // 0xC6 -> UNDEFINED - '\ufffe', // 0xC7 -> UNDEFINED - '\ufffe', // 0xC8 -> UNDEFINED - '\ufffe', // 0xC9 -> UNDEFINED - '\ufffe', // 0xCA -> UNDEFINED - '\ufffe', // 0xCB -> UNDEFINED - '\ufffe', // 0xCC -> UNDEFINED - '\ufffe', // 0xCD -> UNDEFINED - '\ufffe', // 0xCE -> UNDEFINED - '\ufffe', // 0xCF -> UNDEFINED - '\ufffe', // 0xD0 -> UNDEFINED - '\ufffe', // 0xD1 -> UNDEFINED - '\ufffe', // 0xD2 -> UNDEFINED - '\ufffe', // 0xD3 -> UNDEFINED - '\ufffe', // 0xD4 -> UNDEFINED - '\ufffe', // 0xD5 -> UNDEFINED - '\ufffe', // 0xD6 -> UNDEFINED - '\ufffe', // 0xD7 -> UNDEFINED - '\ufffe', // 0xD8 -> UNDEFINED - '\ufffe', // 0xD9 -> UNDEFINED - '\ufffe', // 0xDA -> UNDEFINED - '\ufffe', // 0xDB -> UNDEFINED - '\ufffe', // 0xDC -> UNDEFINED - '\ufffe', // 0xDD -> UNDEFINED - '\ufffe', // 0xDE -> UNDEFINED - '\ufffe', // 0xDF -> UNDEFINED - '\ufffe', // 0xE0 -> UNDEFINED - '\ufffe', // 0xE1 -> UNDEFINED - '\ufffe', // 0xE2 -> UNDEFINED - '\ufffe', // 0xE3 -> UNDEFINED - '\ufffe', // 0xE4 -> UNDEFINED - '\ufffe', // 0xE5 -> UNDEFINED - '\ufffe', // 0xE6 -> UNDEFINED - '\ufffe', // 0xE7 -> UNDEFINED - '\ufffe', // 0xE8 -> UNDEFINED - '\ufffe', // 0xE9 -> UNDEFINED - '\ufffe', // 0xEA -> UNDEFINED - '\ufffe', // 0xEB -> UNDEFINED - '\ufffe', // 0xEC -> UNDEFINED - '\ufffe', // 0xED -> UNDEFINED - '\ufffe', // 0xEE -> UNDEFINED - '\ufffe', // 0xEF -> UNDEFINED - '\ufffe', // 0xF0 -> UNDEFINED - '\ufffe', // 0xF1 -> UNDEFINED - '\ufffe', // 0xF2 -> UNDEFINED - '\ufffe', // 0xF3 -> UNDEFINED - '\ufffe', // 0xF4 -> UNDEFINED - '\ufffe', // 0xF5 -> UNDEFINED - '\ufffe', // 0xF6 -> UNDEFINED - '\ufffe', // 0xF7 -> UNDEFINED - '\ufffe', // 0xF8 -> UNDEFINED - '\ufffe', // 0xF9 -> UNDEFINED - '\ufffe', // 0xFA -> UNDEFINED - '\ufffe', // 0xFB -> UNDEFINED - '\ufffe', // 0xFC -> UNDEFINED - '\ufffe', // 0xFD -> UNDEFINED - '\ufffe', // 0xFE -> UNDEFINED - '\ufffe' // 0xFF -> UNDEFINED + '@' , // @ 0x00 -> COMMERCIAL AT + 'a' , // a 0x01 -> LATIN SMALL LETTER A + 'b' , // b 0x02 -> LATIN SMALL LETTER B + 'c' , // c 0x03 -> LATIN SMALL LETTER C + 'd' , // d 0x04 -> LATIN SMALL LETTER D + 'e' , // e 0x05 -> LATIN SMALL LETTER E + 'f' , // f 0x06 -> LATIN SMALL LETTER F + 'g' , // g 0x07 -> LATIN SMALL LETTER G + 'h' , // h 0x08 -> LATIN SMALL LETTER H + 'i' , // i 0x09 -> LATIN SMALL LETTER I + 'j' , // j 0x0A -> LATIN SMALL LETTER J + 'k' , // k 0x0B -> LATIN SMALL LETTER K + 'l' , // l 0x0C -> LATIN SMALL LETTER L + 'm' , // m 0x0D -> LATIN SMALL LETTER M + 'n' , // n 0x0E -> LATIN SMALL LETTER N + 'o' , // o 0x0F -> LATIN SMALL LETTER O + 'p' , // p 0x10 -> LATIN SMALL LETTER P + 'q' , // q 0x11 -> LATIN SMALL LETTER Q + 'r' , // r 0x12 -> LATIN SMALL LETTER R + 's' , // s 0x13 -> LATIN SMALL LETTER S + 't' , // t 0x14 -> LATIN SMALL LETTER T + 'u' , // u 0x15 -> LATIN SMALL LETTER U + 'v' , // v 0x16 -> LATIN SMALL LETTER V + 'w' , // w 0x17 -> LATIN SMALL LETTER W + 'x' , // x 0x18 -> LATIN SMALL LETTER X + 'y' , // y 0x19 -> LATIN SMALL LETTER Y + 'z' , // z 0x1A -> LATIN SMALL LETTER Z + '[' , // [ 0x1B -> LEFT SQUARE BRACKET + '\u00a3', // £ 0x1C -> POUND SIGN + ']' , // ] 0x1D -> RIGHT SQUARE BRACKET + '\u2191', // ↑ 0x1E -> UPWARDS ARROW + '\u2190', // ← 0x1F -> LEFTWARDS ARROW + ' ' , // 0x20 -> SPACE + '!' , // ! 0x21 -> EXCLAMATION MARK + '"' , // " 0x22 -> QUOTATION MARK + '#' , // # 0x23 -> NUMBER SIGN + '$' , // $ 0x24 -> DOLLAR SIGN + '%' , // % 0x25 -> PERCENT SIGN + '&' , // & 0x26 -> AMPERSAND + '\'' , // ' 0x27 -> APOSTROPHE + '(' , // ( 0x28 -> LEFT PARENTHESIS + ')' , // ) 0x29 -> RIGHT PARENTHESIS + '*' , // * 0x2A -> ASTERISK + '+' , // + 0x2B -> PLUS SIGN + ',' , // , 0x2C -> COMMA + '-' , // - 0x2D -> HYPHEN-MINUS + '.' , // . 0x2E -> FULL STOP + '/' , // / 0x2F -> SOLIDUS + '0' , // 0 0x30 -> DIGIT ZERO + '1' , // 1 0x31 -> DIGIT ONE + '2' , // 2 0x32 -> DIGIT TWO + '3' , // 3 0x33 -> DIGIT THREE + '4' , // 4 0x34 -> DIGIT FOUR + '5' , // 5 0x35 -> DIGIT FIVE + '6' , // 6 0x36 -> DIGIT SIX + '7' , // 7 0x37 -> DIGIT SEVEN + '8' , // 8 0x38 -> DIGIT EIGHT + '9' , // 9 0x39 -> DIGIT NINE + ':' , // : 0x3A -> COLON + ';' , // ; 0x3B -> SEMICOLON + '<' , // < 0x3C -> LESS-THAN SIGN + '=' , // = 0x3D -> EQUALS SIGN + '>' , // > 0x3E -> GREATER-THAN SIGN + '?' , // ? 0x3F -> QUESTION MARK + '\u2500', // ─ 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL + 'A' , // A 0x41 -> LATIN CAPITAL LETTER A + 'B' , // B 0x42 -> LATIN CAPITAL LETTER B + 'C' , // C 0x43 -> LATIN CAPITAL LETTER C + 'D' , // D 0x44 -> LATIN CAPITAL LETTER D + 'E' , // E 0x45 -> LATIN CAPITAL LETTER E + 'F' , // F 0x46 -> LATIN CAPITAL LETTER F + 'G' , // G 0x47 -> LATIN CAPITAL LETTER G + 'H' , // H 0x48 -> LATIN CAPITAL LETTER H + 'I' , // I 0x49 -> LATIN CAPITAL LETTER I + 'J' , // J 0x4A -> LATIN CAPITAL LETTER J + 'K' , // K 0x4B -> LATIN CAPITAL LETTER K + 'L' , // L 0x4C -> LATIN CAPITAL LETTER L + 'M' , // M 0x4D -> LATIN CAPITAL LETTER M + 'N' , // N 0x4E -> LATIN CAPITAL LETTER N + 'O' , // O 0x4F -> LATIN CAPITAL LETTER O + 'P' , // P 0x50 -> LATIN CAPITAL LETTER P + 'Q' , // Q 0x51 -> LATIN CAPITAL LETTER Q + 'R' , // R 0x52 -> LATIN CAPITAL LETTER R + 'S' , // S 0x53 -> LATIN CAPITAL LETTER S + 'T' , // T 0x54 -> LATIN CAPITAL LETTER T + 'U' , // U 0x55 -> LATIN CAPITAL LETTER U + 'V' , // V 0x56 -> LATIN CAPITAL LETTER V + 'W' , // W 0x57 -> LATIN CAPITAL LETTER W + 'X' , // X 0x58 -> LATIN CAPITAL LETTER X + 'Y' , // Y 0x59 -> LATIN CAPITAL LETTER Y + 'Z' , // Z 0x5A -> LATIN CAPITAL LETTER Z + '\u253c', // ┼ 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0x5D -> BOX DRAWINGS LIGHT VERTICAL + '\u2592', // ▒ 0x5E -> MEDIUM SHADE + '\uf139', //  0x5F -> MEDIUM SHADE SLASHED LEFT (CUS) + '\u00a0', // 0x60 -> NO-BREAK SPACE + '\u258c', // ▌ 0x61 -> LEFT HALF BLOCK + '\u2584', // ▄ 0x62 -> LOWER HALF BLOCK + '\u2594', // ▔ 0x63 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0x64 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0x65 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0x66 -> MEDIUM SHADE + '\u2595', // ▕ 0x67 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\uf13a', //  0x69 -> MEDIUM SHADE SLASHED RIGHT (CUS) + '\uf130', //  0x6A -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0x6C -> QUADRANT LOWER RIGHT + '\u2514', // └ 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0x6F -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0x74 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0x75 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0x77 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0x78 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0x79 -> LOWER THREE EIGHTHS BLOCK + '\u2713', // ✓ 0x7A -> CHECK MARK + '\u2596', // ▖ 0x7B -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0x7C -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0x7E -> QUADRANT UPPER LEFT + '\u259a', // ▚ 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\ufffe', // 0x80 -> UNDEFINED + '\ufffe', // 0x81 -> UNDEFINED + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\ufffe', // 0x85 -> UNDEFINED + '\ufffe', // 0x86 -> UNDEFINED + '\ufffe', // 0x87 -> UNDEFINED + '\ufffe', // 0x88 -> UNDEFINED + '\ufffe', // 0x89 -> UNDEFINED + '\ufffe', // 0x8A -> UNDEFINED + '\ufffe', // 0x8B -> UNDEFINED + '\ufffe', // 0x8C -> UNDEFINED + '\ufffe', // 0x8D -> UNDEFINED + '\ufffe', // 0x8E -> UNDEFINED + '\ufffe', // 0x8F -> UNDEFINED + '\ufffe', // 0x90 -> UNDEFINED + '\ufffe', // 0x91 -> UNDEFINED + '\ufffe', // 0x92 -> UNDEFINED + '\ufffe', // 0x93 -> UNDEFINED + '\ufffe', // 0x94 -> UNDEFINED + '\ufffe', // 0x95 -> UNDEFINED + '\ufffe', // 0x96 -> UNDEFINED + '\ufffe', // 0x97 -> UNDEFINED + '\ufffe', // 0x98 -> UNDEFINED + '\ufffe', // 0x99 -> UNDEFINED + '\ufffe', // 0x9A -> UNDEFINED + '\ufffe', // 0x9B -> UNDEFINED + '\ufffe', // 0x9C -> UNDEFINED + '\ufffe', // 0x9D -> UNDEFINED + '\ufffe', // 0x9E -> UNDEFINED + '\ufffe', // 0x9F -> UNDEFINED + '\ufffe', // 0xA0 -> UNDEFINED + '\ufffe', // 0xA1 -> UNDEFINED + '\ufffe', // 0xA2 -> UNDEFINED + '\ufffe', // 0xA3 -> UNDEFINED + '\ufffe', // 0xA4 -> UNDEFINED + '\ufffe', // 0xA5 -> UNDEFINED + '\ufffe', // 0xA6 -> UNDEFINED + '\ufffe', // 0xA7 -> UNDEFINED + '\ufffe', // 0xA8 -> UNDEFINED + '\ufffe', // 0xA9 -> UNDEFINED + '\ufffe', // 0xAA -> UNDEFINED + '\ufffe', // 0xAB -> UNDEFINED + '\ufffe', // 0xAC -> UNDEFINED + '\ufffe', // 0xAD -> UNDEFINED + '\ufffe', // 0xAE -> UNDEFINED + '\ufffe', // 0xAF -> UNDEFINED + '\ufffe', // 0xB0 -> UNDEFINED + '\ufffe', // 0xB1 -> UNDEFINED + '\ufffe', // 0xB2 -> UNDEFINED + '\ufffe', // 0xB3 -> UNDEFINED + '\ufffe', // 0xB4 -> UNDEFINED + '\ufffe', // 0xB5 -> UNDEFINED + '\ufffe', // 0xB6 -> UNDEFINED + '\ufffe', // 0xB7 -> UNDEFINED + '\ufffe', // 0xB8 -> UNDEFINED + '\ufffe', // 0xB9 -> UNDEFINED + '\ufffe', // 0xBA -> UNDEFINED + '\ufffe', // 0xBB -> UNDEFINED + '\ufffe', // 0xBC -> UNDEFINED + '\ufffe', // 0xBD -> UNDEFINED + '\ufffe', // 0xBE -> UNDEFINED + '\ufffe', // 0xBF -> UNDEFINED + '\ufffe', // 0xC0 -> UNDEFINED + '\ufffe', // 0xC1 -> UNDEFINED + '\ufffe', // 0xC2 -> UNDEFINED + '\ufffe', // 0xC3 -> UNDEFINED + '\ufffe', // 0xC4 -> UNDEFINED + '\ufffe', // 0xC5 -> UNDEFINED + '\ufffe', // 0xC6 -> UNDEFINED + '\ufffe', // 0xC7 -> UNDEFINED + '\ufffe', // 0xC8 -> UNDEFINED + '\ufffe', // 0xC9 -> UNDEFINED + '\ufffe', // 0xCA -> UNDEFINED + '\ufffe', // 0xCB -> UNDEFINED + '\ufffe', // 0xCC -> UNDEFINED + '\ufffe', // 0xCD -> UNDEFINED + '\ufffe', // 0xCE -> UNDEFINED + '\ufffe', // 0xCF -> UNDEFINED + '\ufffe', // 0xD0 -> UNDEFINED + '\ufffe', // 0xD1 -> UNDEFINED + '\ufffe', // 0xD2 -> UNDEFINED + '\ufffe', // 0xD3 -> UNDEFINED + '\ufffe', // 0xD4 -> UNDEFINED + '\ufffe', // 0xD5 -> UNDEFINED + '\ufffe', // 0xD6 -> UNDEFINED + '\ufffe', // 0xD7 -> UNDEFINED + '\ufffe', // 0xD8 -> UNDEFINED + '\ufffe', // 0xD9 -> UNDEFINED + '\ufffe', // 0xDA -> UNDEFINED + '\ufffe', // 0xDB -> UNDEFINED + '\ufffe', // 0xDC -> UNDEFINED + '\ufffe', // 0xDD -> UNDEFINED + '\ufffe', // 0xDE -> UNDEFINED + '\ufffe', // 0xDF -> UNDEFINED + '\ufffe', // 0xE0 -> UNDEFINED + '\ufffe', // 0xE1 -> UNDEFINED + '\ufffe', // 0xE2 -> UNDEFINED + '\ufffe', // 0xE3 -> UNDEFINED + '\ufffe', // 0xE4 -> UNDEFINED + '\ufffe', // 0xE5 -> UNDEFINED + '\ufffe', // 0xE6 -> UNDEFINED + '\ufffe', // 0xE7 -> UNDEFINED + '\ufffe', // 0xE8 -> UNDEFINED + '\ufffe', // 0xE9 -> UNDEFINED + '\ufffe', // 0xEA -> UNDEFINED + '\ufffe', // 0xEB -> UNDEFINED + '\ufffe', // 0xEC -> UNDEFINED + '\ufffe', // 0xED -> UNDEFINED + '\ufffe', // 0xEE -> UNDEFINED + '\ufffe', // 0xEF -> UNDEFINED + '\ufffe', // 0xF0 -> UNDEFINED + '\ufffe', // 0xF1 -> UNDEFINED + '\ufffe', // 0xF2 -> UNDEFINED + '\ufffe', // 0xF3 -> UNDEFINED + '\ufffe', // 0xF4 -> UNDEFINED + '\ufffe', // 0xF5 -> UNDEFINED + '\ufffe', // 0xF6 -> UNDEFINED + '\ufffe', // 0xF7 -> UNDEFINED + '\ufffe', // 0xF8 -> UNDEFINED + '\ufffe', // 0xF9 -> UNDEFINED + '\ufffe', // 0xFA -> UNDEFINED + '\ufffe', // 0xFB -> UNDEFINED + '\ufffe', // 0xFC -> UNDEFINED + '\ufffe', // 0xFD -> UNDEFINED + '\ufffe', // 0xFE -> UNDEFINED + '\ufffe' // 0xFF -> UNDEFINED ) private val decodingScreencodeUppercase = arrayOf( - '@' , // @ 0x00 -> COMMERCIAL AT - 'A' , // A 0x01 -> LATIN CAPITAL LETTER A - 'B' , // B 0x02 -> LATIN CAPITAL LETTER B - 'C' , // C 0x03 -> LATIN CAPITAL LETTER C - 'D' , // D 0x04 -> LATIN CAPITAL LETTER D - 'E' , // E 0x05 -> LATIN CAPITAL LETTER E - 'F' , // F 0x06 -> LATIN CAPITAL LETTER F - 'G' , // G 0x07 -> LATIN CAPITAL LETTER G - 'H' , // H 0x08 -> LATIN CAPITAL LETTER H - 'I' , // I 0x09 -> LATIN CAPITAL LETTER I - 'J' , // J 0x0A -> LATIN CAPITAL LETTER J - 'K' , // K 0x0B -> LATIN CAPITAL LETTER K - 'L' , // L 0x0C -> LATIN CAPITAL LETTER L - 'M' , // M 0x0D -> LATIN CAPITAL LETTER M - 'N' , // N 0x0E -> LATIN CAPITAL LETTER N - 'O' , // O 0x0F -> LATIN CAPITAL LETTER O - 'P' , // P 0x10 -> LATIN CAPITAL LETTER P - 'Q' , // Q 0x11 -> LATIN CAPITAL LETTER Q - 'R' , // R 0x12 -> LATIN CAPITAL LETTER R - 'S' , // S 0x13 -> LATIN CAPITAL LETTER S - 'T' , // T 0x14 -> LATIN CAPITAL LETTER T - 'U' , // U 0x15 -> LATIN CAPITAL LETTER U - 'V' , // V 0x16 -> LATIN CAPITAL LETTER V - 'W' , // W 0x17 -> LATIN CAPITAL LETTER W - 'X' , // X 0x18 -> LATIN CAPITAL LETTER X - 'Y' , // Y 0x19 -> LATIN CAPITAL LETTER Y - 'Z' , // Z 0x1A -> LATIN CAPITAL LETTER Z - '[' , // [ 0x1B -> LEFT SQUARE BRACKET - '\u00a3', // £ 0x1C -> POUND SIGN - ']' , // ] 0x1D -> RIGHT SQUARE BRACKET - '\u2191', // ↑ 0x1E -> UPWARDS ARROW - '\u2190', // ← 0x1F -> LEFTWARDS ARROW - ' ' , // 0x20 -> SPACE - '!' , // ! 0x21 -> EXCLAMATION MARK - '"' , // " 0x22 -> QUOTATION MARK - '#' , // # 0x23 -> NUMBER SIGN - '$' , // $ 0x24 -> DOLLAR SIGN - '%' , // % 0x25 -> PERCENT SIGN - '&' , // & 0x26 -> AMPERSAND - '\'' , // ' 0x27 -> APOSTROPHE - '(' , // ( 0x28 -> LEFT PARENTHESIS - ')' , // ) 0x29 -> RIGHT PARENTHESIS - '*' , // * 0x2A -> ASTERISK - '+' , // + 0x2B -> PLUS SIGN - ',' , // , 0x2C -> COMMA - '-' , // - 0x2D -> HYPHEN-MINUS - '.' , // . 0x2E -> FULL STOP - '/' , // / 0x2F -> SOLIDUS - '0' , // 0 0x30 -> DIGIT ZERO - '1' , // 1 0x31 -> DIGIT ONE - '2' , // 2 0x32 -> DIGIT TWO - '3' , // 3 0x33 -> DIGIT THREE - '4' , // 4 0x34 -> DIGIT FOUR - '5' , // 5 0x35 -> DIGIT FIVE - '6' , // 6 0x36 -> DIGIT SIX - '7' , // 7 0x37 -> DIGIT SEVEN - '8' , // 8 0x38 -> DIGIT EIGHT - '9' , // 9 0x39 -> DIGIT NINE - ':' , // : 0x3A -> COLON - ';' , // ; 0x3B -> SEMICOLON - '<' , // < 0x3C -> LESS-THAN SIGN - '=' , // = 0x3D -> EQUALS SIGN - '>' , // > 0x3E -> GREATER-THAN SIGN - '?' , // ? 0x3F -> QUESTION MARK - '\u2500', // ─ 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL - '\u2660', // ♠ 0x41 -> BLACK SPADE SUIT - '\u2502', // │ 0x42 -> BOX DRAWINGS LIGHT VERTICAL - '\u2500', // ─ 0x43 -> BOX DRAWINGS LIGHT HORIZONTAL - '\uf122', //  0x44 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) - '\uf123', //  0x45 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) - '\uf124', //  0x46 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) - '\uf126', //  0x47 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) - '\uf128', //  0x48 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) - '\u256e', // ╮ 0x49 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT - '\u2570', // ╰ 0x4A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT - '\u256f', // ╯ 0x4B -> BOX DRAWINGS LIGHT ARC UP AND LEFT - '\uf12a', //  0x4C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) - '\u2572', // ╲ 0x4D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - '\u2571', // ╱ 0x4E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT - '\uf12b', //  0x4F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) - '\uf12c', //  0x50 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) - '\u25cf', // ● 0x51 -> BLACK CIRCLE - '\uf125', //  0x52 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) - '\u2665', // ♥ 0x53 -> BLACK HEART SUIT - '\uf127', //  0x54 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) - '\u256d', // ╭ 0x55 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT - '\u2573', // ╳ 0x56 -> BOX DRAWINGS LIGHT DIAGONAL CROSS - '\u25cb', // ○ 0x57 -> WHITE CIRCLE - '\u2663', // ♣ 0x58 -> BLACK CLUB SUIT - '\uf129', //  0x59 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) - '\u2666', // ♦ 0x5A -> BLACK DIAMOND SUIT - '\u253c', // ┼ 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - '\uf12e', //  0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) - '\u2502', // │ 0x5D -> BOX DRAWINGS LIGHT VERTICAL - '\u03c0', // π 0x5E -> GREEK SMALL LETTER PI - '\u25e5', // ◥ 0x5F -> BLACK UPPER RIGHT TRIANGLE - '\u00a0', // 0x60 -> NO-BREAK SPACE - '\u258c', // ▌ 0x61 -> LEFT HALF BLOCK - '\u2584', // ▄ 0x62 -> LOWER HALF BLOCK - '\u2594', // ▔ 0x63 -> UPPER ONE EIGHTH BLOCK - '\u2581', // ▁ 0x64 -> LOWER ONE EIGHTH BLOCK - '\u258f', // ▏ 0x65 -> LEFT ONE EIGHTH BLOCK - '\u2592', // ▒ 0x66 -> MEDIUM SHADE - '\u2595', // ▕ 0x67 -> RIGHT ONE EIGHTH BLOCK - '\uf12f', //  0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) - '\u25e4', // ◤ 0x69 -> BLACK UPPER LEFT TRIANGLE - '\uf130', //  0x6A -> RIGHT ONE QUARTER BLOCK (CUS) - '\u251c', // ├ 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT - '\u2597', // ▗ 0x6C -> QUADRANT LOWER RIGHT - '\u2514', // └ 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT - '\u2510', // ┐ 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT - '\u2582', // ▂ 0x6F -> LOWER ONE QUARTER BLOCK - '\u250c', // ┌ 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT - '\u2534', // ┴ 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL - '\u252c', // ┬ 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - '\u2524', // ┤ 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT - '\u258e', // ▎ 0x74 -> LEFT ONE QUARTER BLOCK - '\u258d', // ▍ 0x75 -> LEFT THREE EIGTHS BLOCK - '\uf131', //  0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) - '\uf132', //  0x77 -> UPPER ONE QUARTER BLOCK (CUS) - '\uf133', //  0x78 -> UPPER THREE EIGHTS BLOCK (CUS) - '\u2583', // ▃ 0x79 -> LOWER THREE EIGHTHS BLOCK - '\uf12d', //  0x7A -> ONE EIGHTH BLOCK UP AND LEFT (CUS) - '\u2596', // ▖ 0x7B -> QUADRANT LOWER LEFT - '\u259d', // ▝ 0x7C -> QUADRANT UPPER RIGHT - '\u2518', // ┘ 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT - '\u2598', // ▘ 0x7E -> QUADRANT UPPER LEFT - '\u259a', // ▚ 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT - '\ufffe', // 0x80 -> UNDEFINED - '\ufffe', // 0x81 -> UNDEFINED - '\ufffe', // 0x82 -> UNDEFINED - '\ufffe', // 0x83 -> UNDEFINED - '\ufffe', // 0x84 -> UNDEFINED - '\ufffe', // 0x85 -> UNDEFINED - '\ufffe', // 0x86 -> UNDEFINED - '\ufffe', // 0x87 -> UNDEFINED - '\ufffe', // 0x88 -> UNDEFINED - '\ufffe', // 0x89 -> UNDEFINED - '\ufffe', // 0x8A -> UNDEFINED - '\ufffe', // 0x8B -> UNDEFINED - '\ufffe', // 0x8C -> UNDEFINED - '\ufffe', // 0x8D -> UNDEFINED - '\ufffe', // 0x8E -> UNDEFINED - '\ufffe', // 0x8F -> UNDEFINED - '\ufffe', // 0x90 -> UNDEFINED - '\ufffe', // 0x91 -> UNDEFINED - '\ufffe', // 0x92 -> UNDEFINED - '\ufffe', // 0x93 -> UNDEFINED - '\ufffe', // 0x94 -> UNDEFINED - '\ufffe', // 0x95 -> UNDEFINED - '\ufffe', // 0x96 -> UNDEFINED - '\ufffe', // 0x97 -> UNDEFINED - '\ufffe', // 0x98 -> UNDEFINED - '\ufffe', // 0x99 -> UNDEFINED - '\ufffe', // 0x9A -> UNDEFINED - '\ufffe', // 0x9B -> UNDEFINED - '\ufffe', // 0x9C -> UNDEFINED - '\ufffe', // 0x9D -> UNDEFINED - '\ufffe', // 0x9E -> UNDEFINED - '\ufffe', // 0x9F -> UNDEFINED - '\ufffe', // 0xA0 -> UNDEFINED - '\ufffe', // 0xA1 -> UNDEFINED - '\ufffe', // 0xA2 -> UNDEFINED - '\ufffe', // 0xA3 -> UNDEFINED - '\ufffe', // 0xA4 -> UNDEFINED - '\ufffe', // 0xA5 -> UNDEFINED - '\ufffe', // 0xA6 -> UNDEFINED - '\ufffe', // 0xA7 -> UNDEFINED - '\ufffe', // 0xA8 -> UNDEFINED - '\ufffe', // 0xA9 -> UNDEFINED - '\ufffe', // 0xAA -> UNDEFINED - '\ufffe', // 0xAB -> UNDEFINED - '\ufffe', // 0xAC -> UNDEFINED - '\ufffe', // 0xAD -> UNDEFINED - '\ufffe', // 0xAE -> UNDEFINED - '\ufffe', // 0xAF -> UNDEFINED - '\ufffe', // 0xB0 -> UNDEFINED - '\ufffe', // 0xB1 -> UNDEFINED - '\ufffe', // 0xB2 -> UNDEFINED - '\ufffe', // 0xB3 -> UNDEFINED - '\ufffe', // 0xB4 -> UNDEFINED - '\ufffe', // 0xB5 -> UNDEFINED - '\ufffe', // 0xB6 -> UNDEFINED - '\ufffe', // 0xB7 -> UNDEFINED - '\ufffe', // 0xB8 -> UNDEFINED - '\ufffe', // 0xB9 -> UNDEFINED - '\ufffe', // 0xBA -> UNDEFINED - '\ufffe', // 0xBB -> UNDEFINED - '\ufffe', // 0xBC -> UNDEFINED - '\ufffe', // 0xBD -> UNDEFINED - '\ufffe', // 0xBE -> UNDEFINED - '\ufffe', // 0xBF -> UNDEFINED - '\ufffe', // 0xC0 -> UNDEFINED - '\ufffe', // 0xC1 -> UNDEFINED - '\ufffe', // 0xC2 -> UNDEFINED - '\ufffe', // 0xC3 -> UNDEFINED - '\ufffe', // 0xC4 -> UNDEFINED - '\ufffe', // 0xC5 -> UNDEFINED - '\ufffe', // 0xC6 -> UNDEFINED - '\ufffe', // 0xC7 -> UNDEFINED - '\ufffe', // 0xC8 -> UNDEFINED - '\ufffe', // 0xC9 -> UNDEFINED - '\ufffe', // 0xCA -> UNDEFINED - '\ufffe', // 0xCB -> UNDEFINED - '\ufffe', // 0xCC -> UNDEFINED - '\ufffe', // 0xCD -> UNDEFINED - '\ufffe', // 0xCE -> UNDEFINED - '\ufffe', // 0xCF -> UNDEFINED - '\ufffe', // 0xD0 -> UNDEFINED - '\ufffe', // 0xD1 -> UNDEFINED - '\ufffe', // 0xD2 -> UNDEFINED - '\ufffe', // 0xD3 -> UNDEFINED - '\ufffe', // 0xD4 -> UNDEFINED - '\ufffe', // 0xD5 -> UNDEFINED - '\ufffe', // 0xD6 -> UNDEFINED - '\ufffe', // 0xD7 -> UNDEFINED - '\ufffe', // 0xD8 -> UNDEFINED - '\ufffe', // 0xD9 -> UNDEFINED - '\ufffe', // 0xDA -> UNDEFINED - '\ufffe', // 0xDB -> UNDEFINED - '\ufffe', // 0xDC -> UNDEFINED - '\ufffe', // 0xDD -> UNDEFINED - '\ufffe', // 0xDE -> UNDEFINED - '\ufffe', // 0xDF -> UNDEFINED - '\ufffe', // 0xE0 -> UNDEFINED - '\ufffe', // 0xE1 -> UNDEFINED - '\ufffe', // 0xE2 -> UNDEFINED - '\ufffe', // 0xE3 -> UNDEFINED - '\ufffe', // 0xE4 -> UNDEFINED - '\ufffe', // 0xE5 -> UNDEFINED - '\ufffe', // 0xE6 -> UNDEFINED - '\ufffe', // 0xE7 -> UNDEFINED - '\ufffe', // 0xE8 -> UNDEFINED - '\ufffe', // 0xE9 -> UNDEFINED - '\ufffe', // 0xEA -> UNDEFINED - '\ufffe', // 0xEB -> UNDEFINED - '\ufffe', // 0xEC -> UNDEFINED - '\ufffe', // 0xED -> UNDEFINED - '\ufffe', // 0xEE -> UNDEFINED - '\ufffe', // 0xEF -> UNDEFINED - '\ufffe', // 0xF0 -> UNDEFINED - '\ufffe', // 0xF1 -> UNDEFINED - '\ufffe', // 0xF2 -> UNDEFINED - '\ufffe', // 0xF3 -> UNDEFINED - '\ufffe', // 0xF4 -> UNDEFINED - '\ufffe', // 0xF5 -> UNDEFINED - '\ufffe', // 0xF6 -> UNDEFINED - '\ufffe', // 0xF7 -> UNDEFINED - '\ufffe', // 0xF8 -> UNDEFINED - '\ufffe', // 0xF9 -> UNDEFINED - '\ufffe', // 0xFA -> UNDEFINED - '\ufffe', // 0xFB -> UNDEFINED - '\ufffe', // 0xFC -> UNDEFINED - '\ufffe', // 0xFD -> UNDEFINED - '\ufffe', // 0xFE -> UNDEFINED - '\ufffe' // 0xFF -> UNDEFINED + '@' , // @ 0x00 -> COMMERCIAL AT + 'A' , // A 0x01 -> LATIN CAPITAL LETTER A + 'B' , // B 0x02 -> LATIN CAPITAL LETTER B + 'C' , // C 0x03 -> LATIN CAPITAL LETTER C + 'D' , // D 0x04 -> LATIN CAPITAL LETTER D + 'E' , // E 0x05 -> LATIN CAPITAL LETTER E + 'F' , // F 0x06 -> LATIN CAPITAL LETTER F + 'G' , // G 0x07 -> LATIN CAPITAL LETTER G + 'H' , // H 0x08 -> LATIN CAPITAL LETTER H + 'I' , // I 0x09 -> LATIN CAPITAL LETTER I + 'J' , // J 0x0A -> LATIN CAPITAL LETTER J + 'K' , // K 0x0B -> LATIN CAPITAL LETTER K + 'L' , // L 0x0C -> LATIN CAPITAL LETTER L + 'M' , // M 0x0D -> LATIN CAPITAL LETTER M + 'N' , // N 0x0E -> LATIN CAPITAL LETTER N + 'O' , // O 0x0F -> LATIN CAPITAL LETTER O + 'P' , // P 0x10 -> LATIN CAPITAL LETTER P + 'Q' , // Q 0x11 -> LATIN CAPITAL LETTER Q + 'R' , // R 0x12 -> LATIN CAPITAL LETTER R + 'S' , // S 0x13 -> LATIN CAPITAL LETTER S + 'T' , // T 0x14 -> LATIN CAPITAL LETTER T + 'U' , // U 0x15 -> LATIN CAPITAL LETTER U + 'V' , // V 0x16 -> LATIN CAPITAL LETTER V + 'W' , // W 0x17 -> LATIN CAPITAL LETTER W + 'X' , // X 0x18 -> LATIN CAPITAL LETTER X + 'Y' , // Y 0x19 -> LATIN CAPITAL LETTER Y + 'Z' , // Z 0x1A -> LATIN CAPITAL LETTER Z + '[' , // [ 0x1B -> LEFT SQUARE BRACKET + '\u00a3', // £ 0x1C -> POUND SIGN + ']' , // ] 0x1D -> RIGHT SQUARE BRACKET + '\u2191', // ↑ 0x1E -> UPWARDS ARROW + '\u2190', // ← 0x1F -> LEFTWARDS ARROW + ' ' , // 0x20 -> SPACE + '!' , // ! 0x21 -> EXCLAMATION MARK + '"' , // " 0x22 -> QUOTATION MARK + '#' , // # 0x23 -> NUMBER SIGN + '$' , // $ 0x24 -> DOLLAR SIGN + '%' , // % 0x25 -> PERCENT SIGN + '&' , // & 0x26 -> AMPERSAND + '\'' , // ' 0x27 -> APOSTROPHE + '(' , // ( 0x28 -> LEFT PARENTHESIS + ')' , // ) 0x29 -> RIGHT PARENTHESIS + '*' , // * 0x2A -> ASTERISK + '+' , // + 0x2B -> PLUS SIGN + ',' , // , 0x2C -> COMMA + '-' , // - 0x2D -> HYPHEN-MINUS + '.' , // . 0x2E -> FULL STOP + '/' , // / 0x2F -> SOLIDUS + '0' , // 0 0x30 -> DIGIT ZERO + '1' , // 1 0x31 -> DIGIT ONE + '2' , // 2 0x32 -> DIGIT TWO + '3' , // 3 0x33 -> DIGIT THREE + '4' , // 4 0x34 -> DIGIT FOUR + '5' , // 5 0x35 -> DIGIT FIVE + '6' , // 6 0x36 -> DIGIT SIX + '7' , // 7 0x37 -> DIGIT SEVEN + '8' , // 8 0x38 -> DIGIT EIGHT + '9' , // 9 0x39 -> DIGIT NINE + ':' , // : 0x3A -> COLON + ';' , // ; 0x3B -> SEMICOLON + '<' , // < 0x3C -> LESS-THAN SIGN + '=' , // = 0x3D -> EQUALS SIGN + '>' , // > 0x3E -> GREATER-THAN SIGN + '?' , // ? 0x3F -> QUESTION MARK + '\u2500', // ─ 0x40 -> BOX DRAWINGS LIGHT HORIZONTAL + '\u2660', // ♠ 0x41 -> BLACK SPADE SUIT + '\u2502', // │ 0x42 -> BOX DRAWINGS LIGHT VERTICAL + '\u2500', // ─ 0x43 -> BOX DRAWINGS LIGHT HORIZONTAL + '\uf122', //  0x44 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER UP (CUS) + '\uf123', //  0x45 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS UP (CUS) + '\uf124', //  0x46 -> BOX DRAWINGS LIGHT HORIZONTAL ONE QUARTER DOWN (CUS) + '\uf126', //  0x47 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER LEFT (CUS) + '\uf128', //  0x48 -> BOX DRAWINGS LIGHT VERTICAL ONE QUARTER RIGHT (CUS) + '\u256e', // ╮ 0x49 -> BOX DRAWINGS LIGHT ARC DOWN AND LEFT + '\u2570', // ╰ 0x4A -> BOX DRAWINGS LIGHT ARC UP AND RIGHT + '\u256f', // ╯ 0x4B -> BOX DRAWINGS LIGHT ARC UP AND LEFT + '\uf12a', //  0x4C -> ONE EIGHTH BLOCK UP AND RIGHT (CUS) + '\u2572', // ╲ 0x4D -> BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + '\u2571', // ╱ 0x4E -> BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + '\uf12b', //  0x4F -> ONE EIGHTH BLOCK DOWN AND RIGHT (CUS) + '\uf12c', //  0x50 -> ONE EIGHTH BLOCK DOWN AND LEFT (CUS) + '\u25cf', // ● 0x51 -> BLACK CIRCLE + '\uf125', //  0x52 -> BOX DRAWINGS LIGHT HORIZONTAL TWO QUARTERS DOWN (CUS) + '\u2665', // ♥ 0x53 -> BLACK HEART SUIT + '\uf127', //  0x54 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS LEFT (CUS) + '\u256d', // ╭ 0x55 -> BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + '\u2573', // ╳ 0x56 -> BOX DRAWINGS LIGHT DIAGONAL CROSS + '\u25cb', // ○ 0x57 -> WHITE CIRCLE + '\u2663', // ♣ 0x58 -> BLACK CLUB SUIT + '\uf129', //  0x59 -> BOX DRAWINGS LIGHT VERTICAL TWO QUARTERS RIGHT (CUS) + '\u2666', // ♦ 0x5A -> BLACK DIAMOND SUIT + '\u253c', // ┼ 0x5B -> BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + '\uf12e', //  0x5C -> LEFT HALF BLOCK MEDIUM SHADE (CUS) + '\u2502', // │ 0x5D -> BOX DRAWINGS LIGHT VERTICAL + '\u03c0', // π 0x5E -> GREEK SMALL LETTER PI + '\u25e5', // ◥ 0x5F -> BLACK UPPER RIGHT TRIANGLE + '\u00a0', // 0x60 -> NO-BREAK SPACE + '\u258c', // ▌ 0x61 -> LEFT HALF BLOCK + '\u2584', // ▄ 0x62 -> LOWER HALF BLOCK + '\u2594', // ▔ 0x63 -> UPPER ONE EIGHTH BLOCK + '\u2581', // ▁ 0x64 -> LOWER ONE EIGHTH BLOCK + '\u258f', // ▏ 0x65 -> LEFT ONE EIGHTH BLOCK + '\u2592', // ▒ 0x66 -> MEDIUM SHADE + '\u2595', // ▕ 0x67 -> RIGHT ONE EIGHTH BLOCK + '\uf12f', //  0x68 -> LOWER HALF BLOCK MEDIUM SHADE (CUS) + '\u25e4', // ◤ 0x69 -> BLACK UPPER LEFT TRIANGLE + '\uf130', //  0x6A -> RIGHT ONE QUARTER BLOCK (CUS) + '\u251c', // ├ 0x6B -> BOX DRAWINGS LIGHT VERTICAL AND RIGHT + '\u2597', // ▗ 0x6C -> QUADRANT LOWER RIGHT + '\u2514', // └ 0x6D -> BOX DRAWINGS LIGHT UP AND RIGHT + '\u2510', // ┐ 0x6E -> BOX DRAWINGS LIGHT DOWN AND LEFT + '\u2582', // ▂ 0x6F -> LOWER ONE QUARTER BLOCK + '\u250c', // ┌ 0x70 -> BOX DRAWINGS LIGHT DOWN AND RIGHT + '\u2534', // ┴ 0x71 -> BOX DRAWINGS LIGHT UP AND HORIZONTAL + '\u252c', // ┬ 0x72 -> BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + '\u2524', // ┤ 0x73 -> BOX DRAWINGS LIGHT VERTICAL AND LEFT + '\u258e', // ▎ 0x74 -> LEFT ONE QUARTER BLOCK + '\u258d', // ▍ 0x75 -> LEFT THREE EIGTHS BLOCK + '\uf131', //  0x76 -> RIGHT THREE EIGHTHS BLOCK (CUS) + '\uf132', //  0x77 -> UPPER ONE QUARTER BLOCK (CUS) + '\uf133', //  0x78 -> UPPER THREE EIGHTS BLOCK (CUS) + '\u2583', // ▃ 0x79 -> LOWER THREE EIGHTHS BLOCK + '\uf12d', //  0x7A -> ONE EIGHTH BLOCK UP AND LEFT (CUS) + '\u2596', // ▖ 0x7B -> QUADRANT LOWER LEFT + '\u259d', // ▝ 0x7C -> QUADRANT UPPER RIGHT + '\u2518', // ┘ 0x7D -> BOX DRAWINGS LIGHT UP AND LEFT + '\u2598', // ▘ 0x7E -> QUADRANT UPPER LEFT + '\u259a', // ▚ 0x7F -> QUADRANT UPPER LEFT AND LOWER RIGHT + '\ufffe', // 0x80 -> UNDEFINED + '\ufffe', // 0x81 -> UNDEFINED + '\ufffe', // 0x82 -> UNDEFINED + '\ufffe', // 0x83 -> UNDEFINED + '\ufffe', // 0x84 -> UNDEFINED + '\ufffe', // 0x85 -> UNDEFINED + '\ufffe', // 0x86 -> UNDEFINED + '\ufffe', // 0x87 -> UNDEFINED + '\ufffe', // 0x88 -> UNDEFINED + '\ufffe', // 0x89 -> UNDEFINED + '\ufffe', // 0x8A -> UNDEFINED + '\ufffe', // 0x8B -> UNDEFINED + '\ufffe', // 0x8C -> UNDEFINED + '\ufffe', // 0x8D -> UNDEFINED + '\ufffe', // 0x8E -> UNDEFINED + '\ufffe', // 0x8F -> UNDEFINED + '\ufffe', // 0x90 -> UNDEFINED + '\ufffe', // 0x91 -> UNDEFINED + '\ufffe', // 0x92 -> UNDEFINED + '\ufffe', // 0x93 -> UNDEFINED + '\ufffe', // 0x94 -> UNDEFINED + '\ufffe', // 0x95 -> UNDEFINED + '\ufffe', // 0x96 -> UNDEFINED + '\ufffe', // 0x97 -> UNDEFINED + '\ufffe', // 0x98 -> UNDEFINED + '\ufffe', // 0x99 -> UNDEFINED + '\ufffe', // 0x9A -> UNDEFINED + '\ufffe', // 0x9B -> UNDEFINED + '\ufffe', // 0x9C -> UNDEFINED + '\ufffe', // 0x9D -> UNDEFINED + '\ufffe', // 0x9E -> UNDEFINED + '\ufffe', // 0x9F -> UNDEFINED + '\ufffe', // 0xA0 -> UNDEFINED + '\ufffe', // 0xA1 -> UNDEFINED + '\ufffe', // 0xA2 -> UNDEFINED + '\ufffe', // 0xA3 -> UNDEFINED + '\ufffe', // 0xA4 -> UNDEFINED + '\ufffe', // 0xA5 -> UNDEFINED + '\ufffe', // 0xA6 -> UNDEFINED + '\ufffe', // 0xA7 -> UNDEFINED + '\ufffe', // 0xA8 -> UNDEFINED + '\ufffe', // 0xA9 -> UNDEFINED + '\ufffe', // 0xAA -> UNDEFINED + '\ufffe', // 0xAB -> UNDEFINED + '\ufffe', // 0xAC -> UNDEFINED + '\ufffe', // 0xAD -> UNDEFINED + '\ufffe', // 0xAE -> UNDEFINED + '\ufffe', // 0xAF -> UNDEFINED + '\ufffe', // 0xB0 -> UNDEFINED + '\ufffe', // 0xB1 -> UNDEFINED + '\ufffe', // 0xB2 -> UNDEFINED + '\ufffe', // 0xB3 -> UNDEFINED + '\ufffe', // 0xB4 -> UNDEFINED + '\ufffe', // 0xB5 -> UNDEFINED + '\ufffe', // 0xB6 -> UNDEFINED + '\ufffe', // 0xB7 -> UNDEFINED + '\ufffe', // 0xB8 -> UNDEFINED + '\ufffe', // 0xB9 -> UNDEFINED + '\ufffe', // 0xBA -> UNDEFINED + '\ufffe', // 0xBB -> UNDEFINED + '\ufffe', // 0xBC -> UNDEFINED + '\ufffe', // 0xBD -> UNDEFINED + '\ufffe', // 0xBE -> UNDEFINED + '\ufffe', // 0xBF -> UNDEFINED + '\ufffe', // 0xC0 -> UNDEFINED + '\ufffe', // 0xC1 -> UNDEFINED + '\ufffe', // 0xC2 -> UNDEFINED + '\ufffe', // 0xC3 -> UNDEFINED + '\ufffe', // 0xC4 -> UNDEFINED + '\ufffe', // 0xC5 -> UNDEFINED + '\ufffe', // 0xC6 -> UNDEFINED + '\ufffe', // 0xC7 -> UNDEFINED + '\ufffe', // 0xC8 -> UNDEFINED + '\ufffe', // 0xC9 -> UNDEFINED + '\ufffe', // 0xCA -> UNDEFINED + '\ufffe', // 0xCB -> UNDEFINED + '\ufffe', // 0xCC -> UNDEFINED + '\ufffe', // 0xCD -> UNDEFINED + '\ufffe', // 0xCE -> UNDEFINED + '\ufffe', // 0xCF -> UNDEFINED + '\ufffe', // 0xD0 -> UNDEFINED + '\ufffe', // 0xD1 -> UNDEFINED + '\ufffe', // 0xD2 -> UNDEFINED + '\ufffe', // 0xD3 -> UNDEFINED + '\ufffe', // 0xD4 -> UNDEFINED + '\ufffe', // 0xD5 -> UNDEFINED + '\ufffe', // 0xD6 -> UNDEFINED + '\ufffe', // 0xD7 -> UNDEFINED + '\ufffe', // 0xD8 -> UNDEFINED + '\ufffe', // 0xD9 -> UNDEFINED + '\ufffe', // 0xDA -> UNDEFINED + '\ufffe', // 0xDB -> UNDEFINED + '\ufffe', // 0xDC -> UNDEFINED + '\ufffe', // 0xDD -> UNDEFINED + '\ufffe', // 0xDE -> UNDEFINED + '\ufffe', // 0xDF -> UNDEFINED + '\ufffe', // 0xE0 -> UNDEFINED + '\ufffe', // 0xE1 -> UNDEFINED + '\ufffe', // 0xE2 -> UNDEFINED + '\ufffe', // 0xE3 -> UNDEFINED + '\ufffe', // 0xE4 -> UNDEFINED + '\ufffe', // 0xE5 -> UNDEFINED + '\ufffe', // 0xE6 -> UNDEFINED + '\ufffe', // 0xE7 -> UNDEFINED + '\ufffe', // 0xE8 -> UNDEFINED + '\ufffe', // 0xE9 -> UNDEFINED + '\ufffe', // 0xEA -> UNDEFINED + '\ufffe', // 0xEB -> UNDEFINED + '\ufffe', // 0xEC -> UNDEFINED + '\ufffe', // 0xED -> UNDEFINED + '\ufffe', // 0xEE -> UNDEFINED + '\ufffe', // 0xEF -> UNDEFINED + '\ufffe', // 0xF0 -> UNDEFINED + '\ufffe', // 0xF1 -> UNDEFINED + '\ufffe', // 0xF2 -> UNDEFINED + '\ufffe', // 0xF3 -> UNDEFINED + '\ufffe', // 0xF4 -> UNDEFINED + '\ufffe', // 0xF5 -> UNDEFINED + '\ufffe', // 0xF6 -> UNDEFINED + '\ufffe', // 0xF7 -> UNDEFINED + '\ufffe', // 0xF8 -> UNDEFINED + '\ufffe', // 0xF9 -> UNDEFINED + '\ufffe', // 0xFA -> UNDEFINED + '\ufffe', // 0xFB -> UNDEFINED + '\ufffe', // 0xFC -> UNDEFINED + '\ufffe', // 0xFD -> UNDEFINED + '\ufffe', // 0xFE -> UNDEFINED + '\ufffe' // 0xFF -> UNDEFINED ) // encoding: from unicode to Petscii/Screencodes (0-255) @@ -1065,7 +1065,7 @@ object Petscii { else -> chr } - fun encodePetscii(text: String, lowercase: Boolean = false): Either> { + fun encodePetscii(text: String, lowercase: Boolean = false): Result, CharConversionException> { fun encodeChar(chr3: Char, lowercase: Boolean): Short { val chr = replaceSpecial(chr3) val screencode = if(lowercase) encodingPetsciiLowercase[chr] else encodingPetsciiUppercase[chr] @@ -1083,7 +1083,7 @@ object Petscii { } return try { - right(text.map { + Ok(text.map { try { encodeChar(it, lowercase) } catch (x: CharConversionException) { @@ -1091,7 +1091,7 @@ object Petscii { } }) } catch(cx: CharConversionException) { - left(cx) + Err(cx) } } @@ -1107,7 +1107,7 @@ object Petscii { }.joinToString("") } - fun encodeScreencode(text: String, lowercase: Boolean = false): Either> { + fun encodeScreencode(text: String, lowercase: Boolean = false): Result, CharConversionException> { fun encodeChar(chr3: Char, lowercase: Boolean): Short { val chr = replaceSpecial(chr3) val screencode = if(lowercase) encodingScreencodeLowercase[chr] else encodingScreencodeUppercase[chr] @@ -1125,7 +1125,7 @@ object Petscii { } return try { - right(text.map { + Ok(text.map { try { encodeChar(it, lowercase) } catch (x: CharConversionException) { @@ -1133,7 +1133,7 @@ object Petscii { } }) } catch(cx: CharConversionException) { - left(cx) + Err(cx) } } @@ -1149,7 +1149,7 @@ object Petscii { }.joinToString("") } - fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Either { + fun petscii2scr(petscii_code: Short, inverseVideo: Boolean): Result { val code = when { petscii_code <= 0x1f -> petscii_code + 128 petscii_code <= 0x3f -> petscii_code.toInt() @@ -1159,14 +1159,14 @@ object Petscii { petscii_code <= 0xbf -> petscii_code - 64 petscii_code <= 0xfe -> petscii_code - 128 petscii_code == 255.toShort() -> 95 - else -> return left(CharConversionException("petscii code out of range")) + else -> return Err(CharConversionException("petscii code out of range")) } if(inverseVideo) - return right((code or 0x80).toShort()) - return right(code.toShort()) + return Ok((code or 0x80).toShort()) + return Ok(code.toShort()) } - fun scr2petscii(screencode: Short): Either { + fun scr2petscii(screencode: Short): Result { val petscii = when { screencode <= 0x1f -> screencode + 64 screencode <= 0x3f -> screencode.toInt() @@ -1177,8 +1177,8 @@ object Petscii { screencode <= 0xbf -> screencode - 128 screencode <= 0xfe -> screencode - 64 screencode == 255.toShort() -> 191 - else -> return left(CharConversionException("screencode out of range")) + else -> return Err(CharConversionException("screencode out of range")) } - return right(petscii.toShort()) + return Ok(petscii.toShort()) } } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 3ff00f288..2697adc9e 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -14,6 +14,7 @@ import prog8.compiler.target.cbm.AssemblyProgram import prog8.compiler.target.cpu6502.codegen.assignment.AsmAssignment import prog8.compiler.target.cpu6502.codegen.assignment.AssignmentAsmGen import prog8.optimizer.CallGraph +import prog8.parser.SourceCode import java.nio.file.Path import java.time.LocalDate import java.time.LocalDateTime @@ -154,7 +155,7 @@ internal class AsmGen(private val program: Program, } } - if(options.zeropage !in setOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE)) { + if(options.zeropage !in arrayOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE)) { out(""" ; zeropage is clobbered so we need to reset the machine at exit lda #>sys.reset_system @@ -1325,8 +1326,9 @@ $repeatLabel lda $counterVar "%asminclude" -> { // TODO: handle %asminclude with SourceCode val includedName = stmt.args[0].str!! - val sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module - loadAsmIncludeFile(includedName, sourcePath).fold( + if(stmt.definingModule.source is SourceCode.Generated) + TODO("%asminclude inside non-library, non-filesystem module") + loadAsmIncludeFile(includedName, stmt.definingModule.source).fold( success = { assemblyLines.add(it.trimEnd().trimStart('\n')) }, failure = { errors.err(it.toString(), stmt.position) } ) @@ -1335,11 +1337,13 @@ $repeatLabel lda $counterVar val includedName = stmt.args[0].str!! val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else "" val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else "" - val sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module + if(stmt.definingModule.source is SourceCode.Generated) + TODO("%asmbinary inside non-library, non-filesystem module") + val sourcePath = Path(stmt.definingModule.source.origin) val includedPath = sourcePath.resolveSibling(includedName) val pathForAssembler = outputDir // #54: 64tass needs the path *relative to the .asm file* - .absolute() // avoid IllegalArgumentExc due to non-absolute path .relativize(absolute path) - .relativize(includedPath) + .toAbsolutePath() + .relativize(includedPath.toAbsolutePath()) .normalize() // avoid assembler warnings (-Wportable; only some, not all) .toString().replace('\\', '/') out(" .binary \"$pathForAssembler\" $offset $length") @@ -1459,11 +1463,11 @@ $label nop""") if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") { val leftDt = pointerOffsetExpr.left.inferType(program) val rightDt = pointerOffsetExpr.left.inferType(program) - if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UBYTE)) + if(leftDt istype DataType.UWORD && rightDt istype DataType.UBYTE) return Pair(pointerOffsetExpr.left, pointerOffsetExpr.right) - if(leftDt.istype(DataType.UBYTE) && rightDt.istype(DataType.UWORD)) + if(leftDt istype DataType.UBYTE && rightDt istype DataType.UWORD) return Pair(pointerOffsetExpr.right, pointerOffsetExpr.left) - if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UWORD)) { + if(leftDt istype DataType.UWORD && rightDt istype DataType.UWORD) { // could be that the index was a constant numeric byte but converted to word, check that val constIdx = pointerOffsetExpr.right.constValue(program) if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) { @@ -1471,10 +1475,10 @@ $label nop""") } // could be that the index was typecasted into uword, check that val rightTc = pointerOffsetExpr.right as? TypecastExpression - if(rightTc!=null && rightTc.expression.inferType(program).istype(DataType.UBYTE)) + if(rightTc!=null && rightTc.expression.inferType(program) istype DataType.UBYTE) return Pair(pointerOffsetExpr.left, rightTc.expression) val leftTc = pointerOffsetExpr.left as? TypecastExpression - if(leftTc!=null && leftTc.expression.inferType(program).istype(DataType.UBYTE)) + if(leftTc!=null && leftTc.expression.inferType(program) istype DataType.UBYTE) return Pair(pointerOffsetExpr.right, leftTc.expression) } @@ -1487,7 +1491,7 @@ $label nop""") fun evalBytevalueWillClobberA(expr: Expression): Boolean { val dt = expr.inferType(program) - if(!dt.istype(DataType.UBYTE) && !dt.istype(DataType.BYTE)) + if(dt isnot DataType.UBYTE && dt isnot DataType.BYTE) return true return when(expr) { is IdentifierReference -> false diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index 2f6587c60..8a4c2d210 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -715,11 +715,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val val firstName = asmgen.asmVariableName(first) val secondName = asmgen.asmVariableName(second) val dt = first.inferType(program) - if(dt.istype(DataType.BYTE) || dt.istype(DataType.UBYTE)) { + if(dt istype DataType.BYTE || dt istype DataType.UBYTE) { asmgen.out(" ldy $firstName | lda $secondName | sta $firstName | sty $secondName") return } - if(dt.istype(DataType.WORD) || dt.istype(DataType.UWORD)) { + if(dt istype DataType.WORD || dt istype DataType.UWORD) { asmgen.out(""" ldy $firstName lda $secondName @@ -732,7 +732,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val """) return } - if(dt.istype(DataType.FLOAT)) { + if(dt istype DataType.FLOAT) { asmgen.out(""" lda #<$firstName sta P8ZP_SCRATCH_W1 diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt index 62a7cd155..e5562d199 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt @@ -157,11 +157,11 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg argForCarry = argi } argi.value.second.statusflag != null -> throw AssemblyError("can only use Carry as status flag parameter") - argi.value.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) -> { + argi.value.second.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) -> { require(argForXregister==null) argForXregister = argi } - argi.value.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.AY) -> { + argi.value.second.registerOrPair in arrayOf(RegisterOrPair.A, RegisterOrPair.AY) -> { require(argForAregister == null) argForAregister = argi } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt index b9e490a50..45f06d49c 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/assignment/AsmAssignment.kt @@ -205,7 +205,7 @@ internal class AsmAssignment(val source: AsmAssignSource, val position: Position) { init { - if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY)) + if(target.register !in arrayOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY)) require(source.datatype != DataType.UNDEFINED) { "must not be placeholder/undefined datatype" } require(memsizer.memorySize(source.datatype) <= memsizer.memorySize(target.datatype)) { "source storage size must be less or equal to target datatype storage size" diff --git a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt index eac34edaf..d0e45eb62 100644 --- a/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt +++ b/compiler/src/prog8/compiler/target/cx16/CX16MachineDefinition.kt @@ -97,7 +97,7 @@ internal object CX16MachineDefinition: IMachineDefinition { init { - if (options.floats && options.zeropage !in setOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) + if (options.floats && options.zeropage !in arrayOf(ZeropageType.BASICSAFE, ZeropageType.DONTUSE )) throw CompilerException("when floats are enabled, zero page type should be 'basicsafe' or 'dontuse'") // the addresses 0x02 to 0x21 (inclusive) are taken for sixteen virtual 16-bit api registers. diff --git a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 0640ead82..605672bd0 100644 --- a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -137,7 +137,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke } } - if(expr.inferType(program).istype(DataType.FLOAT)) { + if(expr.inferType(program) istype DataType.FLOAT) { val subExpr: BinaryExpression? = when { leftconst != null -> expr.right as? BinaryExpression rightconst != null -> expr.left as? BinaryExpression @@ -277,7 +277,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke val numval = decl.value as? NumericLiteralValue if(decl.type== VarDeclType.CONST && numval!=null) { val valueDt = numval.inferType(program) - if(!valueDt.istype(decl.datatype)) { + if(valueDt isnot decl.datatype) { val cast = numval.cast(decl.datatype) if(cast.isValid) return listOf(IAstModification.ReplaceNode(numval, cast.valueOrZero(), decl)) diff --git a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt index 4429ffe66..fca8e6355 100644 --- a/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt +++ b/compiler/src/prog8/optimizer/ConstantIdentifierReplacer.kt @@ -21,7 +21,7 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat try { val declConstValue = decl.value?.constValue(program) if(declConstValue!=null && (decl.type==VarDeclType.VAR || decl.type==VarDeclType.CONST) - && !declConstValue.inferType(program).istype(decl.datatype)) { + && declConstValue.inferType(program) isnot decl.datatype) { // cast the numeric literal to the appropriate datatype of the variable val cast = declConstValue.cast(decl.datatype) if(cast.isValid) diff --git a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt index c33918774..58eba0492 100644 --- a/compiler/src/prog8/optimizer/ExpressionSimplifier.kt +++ b/compiler/src/prog8/optimizer/ExpressionSimplifier.kt @@ -45,7 +45,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() mods += IAstModification.ReplaceNode(typecast.expression, subTypecast.expression, typecast) } } else { - if (typecast.expression.inferType(program).istype(typecast.type)) { + if (typecast.expression.inferType(program) istype typecast.type) { // remove duplicate cast mods += IAstModification.ReplaceNode(typecast, typecast.expression, parent) } @@ -289,13 +289,13 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() val arg = functionCall.args[0] if(arg is TypecastExpression) { val valueDt = arg.expression.inferType(program) - if (valueDt.istype(DataType.BYTE) || valueDt.istype(DataType.UBYTE)) { + if (valueDt istype DataType.BYTE || valueDt istype DataType.UBYTE) { // useless lsb() of byte value that was typecasted to word return listOf(IAstModification.ReplaceNode(functionCall, arg.expression, parent)) } } else { val argDt = arg.inferType(program) - if (argDt.istype(DataType.BYTE) || argDt.istype(DataType.UBYTE)) { + if (argDt istype DataType.BYTE || argDt istype DataType.UBYTE) { // useless lsb() of byte value return listOf(IAstModification.ReplaceNode(functionCall, arg, parent)) } @@ -305,7 +305,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() val arg = functionCall.args[0] if(arg is TypecastExpression) { val valueDt = arg.expression.inferType(program) - if (valueDt.istype(DataType.BYTE) || valueDt.istype(DataType.UBYTE)) { + if (valueDt istype DataType.BYTE || valueDt istype DataType.UBYTE) { // useless msb() of byte value that was typecasted to word, replace with 0 return listOf(IAstModification.ReplaceNode( functionCall, @@ -314,7 +314,7 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker() } } else { val argDt = arg.inferType(program) - if (argDt.istype(DataType.BYTE) || argDt.istype(DataType.UBYTE)) { + if (argDt istype DataType.BYTE || argDt istype DataType.UBYTE) { // useless msb() of byte value, replace with 0 return listOf(IAstModification.ReplaceNode( functionCall, diff --git a/compiler/test/AsmgenTests.kt b/compiler/test/AsmgenTests.kt index f1f385f37..c66db1ce6 100644 --- a/compiler/test/AsmgenTests.kt +++ b/compiler/test/AsmgenTests.kt @@ -15,6 +15,7 @@ import prog8.compiler.* import prog8.compiler.target.C64Target import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.cpu6502.codegen.AsmGen +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import java.nio.file.Path @@ -67,7 +68,7 @@ locallabel: val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY) val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY) - val module = Module("test", mutableListOf(block), Position.DUMMY, null) + val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -78,7 +79,7 @@ locallabel: val errors = ErrorReporter() val options = CompilationOptions(OutputType.RAW, LauncherType.NONE, ZeropageType.FULL, emptyList(), false, true, C64Target) val zp = C64MachineDefinition.C64Zeropage(options) - val asmgen = AsmGen(program, errors, zp, options, C64Target, Path.of(".")) + val asmgen = AsmGen(program, errors, zp, options, C64Target, Path.of("")) return asmgen } diff --git a/compiler/test/ModuleImporterTests.kt b/compiler/test/ModuleImporterTests.kt index 49c23c0cd..74a2a1fe6 100644 --- a/compiler/test/ModuleImporterTests.kt +++ b/compiler/test/ModuleImporterTests.kt @@ -15,6 +15,7 @@ import prog8.ast.Program import prog8.compiler.IErrorReporter import prog8.compiler.ModuleImporter import prog8.parser.ParseError +import prog8.parser.SourceCode import prog8tests.helpers.* import kotlin.io.path.* @@ -191,7 +192,7 @@ class TestModuleImporter { repeat(2) { n -> assertFailsWith(count[n] + " call") { act() }.let { - assertThat(it.position.file, equalTo(srcPath.absolutePathString())) + assertThat(it.position.file, equalTo(SourceCode.relative(srcPath).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) @@ -221,7 +222,7 @@ class TestModuleImporter { repeat(repetitions) { n -> assertFailsWith(count[n] + " call") { act() }.let { - assertThat(it.position.file, equalTo(imported.absolutePathString())) + assertThat(it.position.file, equalTo(SourceCode.relative(imported).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) @@ -250,14 +251,14 @@ class TestModuleImporter { val result = importer.importLibraryModule(filenameNoExt) assertThat(count[n] + " call / NO .p8 extension", result, Is(nullValue())) assertFalse(errors.noErrors(), count[n] + " call / NO .p8 extension") - assertEquals(errors.errors.single(), "imported file not found: i_do_not_exist.p8") + assertEquals(errors.errors.single(), "no module found with name i_do_not_exist") errors.report() assertThat(program.modules.size, equalTo(1)) val result2 = importer.importLibraryModule(filenameWithExt) assertThat(count[n] + " call / with .p8 extension", result2, Is(nullValue())) assertFalse(importer.errors.noErrors(), count[n] + " call / with .p8 extension") - assertEquals(errors.errors.single(), "imported file not found: i_do_not_exist.p8.p8") // TODO don't duplicate the p8 extension in the import logic... + assertEquals(errors.errors.single(), "no module found with name i_do_not_exist.p8") // TODO don't add a p8 extension in the import logic... errors.report() assertThat(program.modules.size, equalTo(1)) } @@ -277,7 +278,7 @@ class TestModuleImporter { repeat(2) { n -> assertFailsWith(count[n] + " call") { importer.importLibraryModule(srcPath.nameWithoutExtension) }.let { - assertThat(it.position.file, equalTo(srcPath.absolutePathString())) + assertThat(it.position.file, equalTo(SourceCode.relative(srcPath).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) @@ -297,12 +298,13 @@ class TestModuleImporter { repeat(repetitions) { n -> assertFailsWith(count[n] + " call") { act() }.let { - assertThat(it.position.file, equalTo(imported.normalize().absolutePathString())) + assertThat(it.position.file, equalTo(SourceCode.relative(imported).toString())) assertThat("line; should be 1-based", it.position.line, equalTo(2)) assertThat("startCol; should be 0-based", it.position.startCol, equalTo(6)) assertThat("endCol; should be 0-based", it.position.endCol, equalTo(6)) } assertThat(program.modules.size, equalTo(2)) + importer.errors.report() } } diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index a5fa1854c..f9d02d005 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -1,5 +1,6 @@ package prog8tests +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.DynamicTest import org.junit.jupiter.api.DynamicTest.dynamicTest import org.junit.jupiter.api.TestFactory @@ -41,7 +42,7 @@ class TestCompilerOnExamples { writeAssembly = true, slowCodegenWarnings = false, compilationTarget = platform.name, - libdirs = listOf(), + sourceDirs = listOf(), outputDir ).assertSuccess("; $displayName") } diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt index 31015d253..dddd9df4b 100644 --- a/compiler/test/TestCompilerOnImportsAndIncludes.kt +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -46,29 +46,6 @@ class TestCompilerOnImportsAndIncludes { assertEquals("main", strLits[0].definingScope.name) assertEquals("foo", strLits[1].definingScope.name) } - - @Test - @Disabled("TODO: why would we not accept string literals as argument to %import?") - fun testImportFromSameFolder_strLit() { - val filepath = assumeReadableFile(fixturesDir,"importFromSameFolder_strLit.p8") - val imported = assumeReadableFile(fixturesDir, "foo_bar.p8") - - val platform = Cx16Target - val result = compileFile(platform, optimize = false, fixturesDir, filepath.name) - .assertSuccess() - - val program = result.programAst - val startSub = program.entrypoint - val strLits = startSub.statements - .filterIsInstance() - .map { it.args[0] as IdentifierReference } - .map { it.targetVarDecl(program)!!.value as StringLiteralValue } - - assertEquals("main.bar", strLits[0].value) - assertEquals("foo.bar", strLits[1].value) - assertEquals("main", strLits[0].definingScope.name) - assertEquals("foo", strLits[1].definingScope.name) - } } @Nested diff --git a/compiler/test/TestCompilerOptionLibdirs.kt b/compiler/test/TestCompilerOptionLibdirs.kt index aeff77691..e81108dbd 100644 --- a/compiler/test/TestCompilerOptionLibdirs.kt +++ b/compiler/test/TestCompilerOptionLibdirs.kt @@ -19,7 +19,7 @@ import kotlin.io.path.writeText * from source file loading all the way through to running 64tass. */ @TestInstance(TestInstance.Lifecycle.PER_CLASS) -class TestCompilerOptionLibdirs { +class TestCompilerOptionSourcedirs { private lateinit var tempFileInWorkingDir: Path @@ -39,14 +39,14 @@ class TestCompilerOptionLibdirs { tempFileInWorkingDir.deleteExisting() } - private fun compileFile(filePath: Path, libdirs: List) = + private fun compileFile(filePath: Path, sourceDirs: List) = compileProgram( filepath = filePath, optimize = false, writeAssembly = true, slowCodegenWarnings = false, compilationTarget = Cx16Target.name, - libdirs, + sourceDirs, outputDir ) @@ -65,7 +65,7 @@ class TestCompilerOptionLibdirs { } @Test - fun testFilePathInWorkingDirRelativeTo1stInLibdirs() { + fun testFilePathInWorkingDirRelativeTo1stInSourcedirs() { val filepath = assumeReadableFile(tempFileInWorkingDir) compileFile(filepath.fileName, listOf(workingDir.toString())) .assertSuccess() @@ -86,10 +86,10 @@ class TestCompilerOptionLibdirs { } @Test - fun testFilePathOutsideWorkingDirRelativeTo1stInLibdirs() { + fun testFilePathOutsideWorkingDirRelativeTo1stInSourcedirs() { val filepath = assumeReadableFile(fixturesDir, "simple_main.p8") - val libdirs = listOf("$fixturesDir") - compileFile(filepath.fileName, libdirs) + val sourcedirs = listOf("$fixturesDir") + compileFile(filepath.fileName, sourcedirs) .assertSuccess() } diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 6f6fef236..f5e2a5659 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -14,6 +14,7 @@ import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.PrefixExpression import prog8.ast.statements.* import prog8.compiler.target.C64Target +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import kotlin.test.assertFalse @@ -91,7 +92,7 @@ class TestMemory { val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) module.linkParents(program.namespace) return target } @@ -110,7 +111,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -124,7 +125,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -138,7 +139,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -152,7 +153,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -167,7 +168,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -182,7 +183,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) + val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) diff --git a/compiler/test/TestPetscii.kt b/compiler/test/TestPetscii.kt index be6d79c79..5315a97df 100644 --- a/compiler/test/TestPetscii.kt +++ b/compiler/test/TestPetscii.kt @@ -1,5 +1,6 @@ package prog8tests +import com.github.michaelbull.result.Ok import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test @@ -9,8 +10,6 @@ import prog8.ast.base.Position import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.StringLiteralValue import prog8.compiler.target.cbm.Petscii -import prog8.left -import prog8.right import kotlin.test.* @@ -19,8 +18,8 @@ class TestPetscii { @Test fun testZero() { - assertThat(Petscii.encodePetscii("\u0000", true), equalTo(right(listOf(0)))) - assertThat(Petscii.encodePetscii("\u0000", false), equalTo(right(listOf(0)))) + assertThat(Petscii.encodePetscii("\u0000", true), equalTo(Ok(listOf(0)))) + assertThat(Petscii.encodePetscii("\u0000", false), equalTo(Ok(listOf(0)))) assertThat(Petscii.decodePetscii(listOf(0), true), equalTo("\u0000")) assertThat(Petscii.decodePetscii(listOf(0), false), equalTo("\u0000")) } @@ -28,11 +27,11 @@ class TestPetscii { @Test fun testLowercase() { assertThat(Petscii.encodePetscii("hello WORLD 123 @!£", true), equalTo( - right(listOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) - assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(right(listOf(0x12)))) // reverse vid - assertThat(Petscii.encodePetscii("✓", true), equalTo(right(listOf(0xfa)))) - assertThat("expect lowercase error fallback", Petscii.encodePetscii("π", true), equalTo(right(listOf(255)))) - assertThat("expect lowercase error fallback", Petscii.encodePetscii("♥", true), equalTo(right(listOf(0xd3)))) + Ok(listOf(72, 69, 76, 76, 79, 32, 0xd7, 0xcf, 0xd2, 0xcc, 0xc4, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) + assertThat(Petscii.encodePetscii("\uf11a", true), equalTo(Ok(listOf(0x12)))) // reverse vid + assertThat(Petscii.encodePetscii("✓", true), equalTo(Ok(listOf(0xfa)))) + assertThat("expect lowercase error fallback", Petscii.encodePetscii("π", true), equalTo(Ok(listOf(255)))) + assertThat("expect lowercase error fallback", Petscii.encodePetscii("♥", true), equalTo(Ok(listOf(0xd3)))) assertThat(Petscii.decodePetscii(listOf(72, 0xd7, 0x5c, 0xfa, 0x12), true), equalTo("hW£✓\uF11A")) assertFailsWith { Petscii.decodePetscii(listOf(-1), true) } @@ -42,11 +41,11 @@ class TestPetscii { @Test fun testUppercase() { assertThat(Petscii.encodePetscii("HELLO 123 @!£"), equalTo( - right(listOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) - assertThat(Petscii.encodePetscii("\uf11a"), equalTo(right(listOf(0x12)))) // reverse vid - assertThat(Petscii.encodePetscii("♥"), equalTo(right(listOf(0xd3)))) - assertThat(Petscii.encodePetscii("π"), equalTo(right(listOf(0xff)))) - assertThat("expecting fallback", Petscii.encodePetscii("✓"), equalTo(right(listOf(250)))) + Ok(listOf(72, 69, 76, 76, 79, 32, 49, 50, 51, 32, 64, 33, 0x5c)))) + assertThat(Petscii.encodePetscii("\uf11a"), equalTo(Ok(listOf(0x12)))) // reverse vid + assertThat(Petscii.encodePetscii("♥"), equalTo(Ok(listOf(0xd3)))) + assertThat(Petscii.encodePetscii("π"), equalTo(Ok(listOf(0xff)))) + assertThat("expecting fallback", Petscii.encodePetscii("✓"), equalTo(Ok(listOf(250)))) assertThat(Petscii.decodePetscii(listOf(72, 0x5c, 0xd3, 0xff)), equalTo("H£♥π")) assertFailsWith { Petscii.decodePetscii(listOf(-1)) } @@ -56,11 +55,11 @@ class TestPetscii { @Test fun testScreencodeLowercase() { assertThat(Petscii.encodeScreencode("hello WORLD 123 @!£", true), equalTo( - right(listOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)) + Ok(listOf(0x08, 0x05, 0x0c, 0x0c, 0x0f, 0x20, 0x57, 0x4f, 0x52, 0x4c, 0x44, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)) )) - assertThat(Petscii.encodeScreencode("✓", true), equalTo(right(listOf(0x7a)))) - assertThat("expect fallback", Petscii.encodeScreencode("♥", true), equalTo(right(listOf(83)))) - assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(right(listOf(94)))) + assertThat(Petscii.encodeScreencode("✓", true), equalTo(Ok(listOf(0x7a)))) + assertThat("expect fallback", Petscii.encodeScreencode("♥", true), equalTo(Ok(listOf(83)))) + assertThat("expect fallback", Petscii.encodeScreencode("π", true), equalTo(Ok(listOf(94)))) assertThat(Petscii.decodeScreencode(listOf(0x08, 0x57, 0x1c, 0x7a), true), equalTo("hW£✓")) assertFailsWith { Petscii.decodeScreencode(listOf(-1), true) } @@ -70,12 +69,12 @@ class TestPetscii { @Test fun testScreencodeUppercase() { assertThat(Petscii.encodeScreencode("WORLD 123 @!£"), equalTo( - right(listOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))) - assertThat(Petscii.encodeScreencode("♥"), equalTo(right(listOf(0x53)))) - assertThat(Petscii.encodeScreencode("π"), equalTo(right(listOf(0x5e)))) - assertThat(Petscii.encodeScreencode("HELLO"), equalTo(right(listOf(8, 5, 12, 12, 15)))) - assertThat("expecting fallback", Petscii.encodeScreencode("hello"), equalTo(right(listOf(8, 5, 12, 12, 15)))) - assertThat("expecting fallback", Petscii.encodeScreencode("✓"), equalTo(right(listOf(122)))) + Ok(listOf(0x17, 0x0f, 0x12, 0x0c, 0x04, 0x20, 0x31, 0x32, 0x33, 0x20, 0x00, 0x21, 0x1c)))) + assertThat(Petscii.encodeScreencode("♥"), equalTo(Ok(listOf(0x53)))) + assertThat(Petscii.encodeScreencode("π"), equalTo(Ok(listOf(0x5e)))) + assertThat(Petscii.encodeScreencode("HELLO"), equalTo(Ok(listOf(8, 5, 12, 12, 15)))) + assertThat("expecting fallback", Petscii.encodeScreencode("hello"), equalTo(Ok(listOf(8, 5, 12, 12, 15)))) + assertThat("expecting fallback", Petscii.encodeScreencode("✓"), equalTo(Ok(listOf(122)))) assertThat(Petscii.decodeScreencode(listOf(0x17, 0x1c, 0x53, 0x5e)), equalTo("W£♥π")) assertFailsWith { Petscii.decodeScreencode(listOf(-1)) } diff --git a/compiler/test/fixtures/importFromSameFolder_strLit.p8 b/compiler/test/fixtures/importFromSameFolder_strLit.p8 deleted file mode 100644 index 0f75c437f..000000000 --- a/compiler/test/fixtures/importFromSameFolder_strLit.p8 +++ /dev/null @@ -1,9 +0,0 @@ -%import textio -%import "foo_bar.p8" -main { - str myBar = "main.bar" - sub start() { - txt.print(myBar) - txt.print(foo.bar) - } -} diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index 20fe00e94..4e59e499c 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -38,7 +38,7 @@ internal fun compileFile( writeAssembly = true, slowCodegenWarnings = false, platform.name, - libdirs = listOf(), + sourceDirs = listOf(), outputDir ) } diff --git a/compilerAst/src/prog8/ast/AstToSourceCode.kt b/compilerAst/src/prog8/ast/AstToSourceCode.kt index a1df487b1..ad02f3e39 100644 --- a/compilerAst/src/prog8/ast/AstToSourceCode.kt +++ b/compilerAst/src/prog8/ast/AstToSourceCode.kt @@ -304,7 +304,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): override fun visit(assignment: Assignment) { val binExpr = assignment.value as? BinaryExpression if(binExpr!=null && binExpr.left isSameAs assignment.target - && binExpr.operator !in setOf("and", "or", "xor") + && binExpr.operator !in arrayOf("and", "or", "xor") && binExpr.operator !in comparisonOperators) { // we only support the inplace assignments of the form A = A assignment.target.accept(this) diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index dd8dd937f..b3e665848 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -246,7 +246,7 @@ class Program(val name: String, init { // insert a container module for all interned strings later - val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, null) + val internedStringsModule = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated(internedStringsModuleName)) val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY) internedStringsModule.statements.add(block) @@ -347,14 +347,18 @@ class Program(val name: String, } -open class Module(override val name: String, - override var statements: MutableList, +open class Module(final override var statements: MutableList, final override val position: Position, - val source: SourceCode?) : Node, INameScope { + val source: SourceCode) : Node, INameScope { override lateinit var parent: Node lateinit var program: Program + override val name = source.origin + .substringBeforeLast(".") + .substringAfterLast("/") + .substringAfterLast("\\") + val loadAddress: Int by lazy { val address = (statements.singleOrNull { it is Directive && it.directive == "%address" } as? Directive)?.args?.single()?.int ?: 0 address @@ -380,7 +384,7 @@ open class Module(override val name: String, fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - val isLibrary get() = (source == null) || source.isFromResources + val isLibrary get() = source.isFromResources } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 110e56a0e..eadba560e 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -6,6 +6,9 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.parser.Prog8ANTLRParser +import prog8.parser.SourceCode +import java.nio.file.Path +import kotlin.io.path.isRegularFile /***************** Antlr Extension methods to create AST ****************/ @@ -14,17 +17,17 @@ private data class NumericLiteral(val number: Number, val datatype: DataType) private fun ParserRuleContext.toPosition() : Position { - /* - val customTokensource = this.start.tokenSource as? CustomLexer - val filename = - when { - customTokensource!=null -> customTokensource.modulePath.toString() - start.tokenSource.sourceName == IntStream.UNKNOWN_SOURCE_NAME -> "@internal@" - else -> File(start.inputStream.sourceName).name - } - */ - val filename = start.inputStream.sourceName - + val pathString = start.inputStream.sourceName + val filename = if(SourceCode.isRegularFilesystemPath(pathString)) { + val path = Path.of(pathString) + if(path.isRegularFile()) { + SourceCode.relative(path).toString() + } else { + path.toString() + } + } else { + pathString + } // note: beware of TAB characters in the source text, they count as 1 column... return Position(filename, start.line, start.charPositionInLine, stop.charPositionInLine + stop.text.length) } diff --git a/compilerAst/src/prog8/ast/base/Base.kt b/compilerAst/src/prog8/ast/base/Base.kt index a446fc264..c63e654b0 100644 --- a/compilerAst/src/prog8/ast/base/Base.kt +++ b/compilerAst/src/prog8/ast/base/Base.kt @@ -24,16 +24,17 @@ enum class DataType { */ infix fun isAssignableTo(targetType: DataType) = when(this) { - UBYTE -> targetType in setOf(UBYTE, WORD, UWORD, FLOAT) - BYTE -> targetType in setOf(BYTE, WORD, FLOAT) - UWORD -> targetType in setOf(UWORD, FLOAT) - WORD -> targetType in setOf(WORD, FLOAT) + UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, FLOAT) + BYTE -> targetType.oneOf(BYTE, WORD, FLOAT) + UWORD -> targetType.oneOf(UWORD, FLOAT) + WORD -> targetType.oneOf(WORD, FLOAT) FLOAT -> targetType == FLOAT STR -> targetType == STR in ArrayDatatypes -> targetType == this else -> false } + fun oneOf(vararg types: DataType) = this in types infix fun isAssignableTo(targetTypes: Set) = targetTypes.any { this isAssignableTo it } infix fun isNotAssignableTo(targetType: DataType) = !this.isAssignableTo(targetType) infix fun isNotAssignableTo(targetTypes: Set) = !this.isAssignableTo(targetTypes) @@ -127,13 +128,13 @@ enum class VarDeclType { MEMORY } -val ByteDatatypes = setOf(DataType.UBYTE, DataType.BYTE) -val WordDatatypes = setOf(DataType.UWORD, DataType.WORD) -val IntegerDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD) -val NumericDatatypes = setOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT) -val ArrayDatatypes = setOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F) -val StringlyDatatypes = setOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD) -val IterableDatatypes = setOf( +val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE) +val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD) +val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD) +val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.FLOAT) +val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, DataType.ARRAY_F) +val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD) +val IterableDatatypes = arrayOf( DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W, @@ -156,7 +157,7 @@ val ElementToArrayTypes = mapOf( DataType.UWORD to DataType.ARRAY_UW, DataType.FLOAT to DataType.ARRAY_F ) -val Cx16VirtualRegisters = listOf( +val Cx16VirtualRegisters = arrayOf( RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3, RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7, RegisterOrPair.R8, RegisterOrPair.R9, RegisterOrPair.R10, RegisterOrPair.R11, diff --git a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt index a6c2a876c..d30c9aed2 100644 --- a/compilerAst/src/prog8/ast/expressions/AstExpressions.kt +++ b/compilerAst/src/prog8/ast/expressions/AstExpressions.kt @@ -638,7 +638,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be } fun cast(targettype: DataType): ArrayLiteralValue? { - if(type.istype(targettype)) + if(type istype targettype) return this if(targettype in ArrayDatatypes) { val elementType = ArrayToElementTypes.getValue(targettype) @@ -797,7 +797,7 @@ class FunctionCall(override var target: IdentifierReference, args.forEach { it.linkParents(this) } } - override val isSimple = target.nameInSource.size==1 && (target.nameInSource[0] in setOf("msb", "lsb", "peek", "peekw")) + override val isSimple = target.nameInSource.size==1 && (target.nameInSource[0] in arrayOf("msb", "lsb", "peek", "peekw")) override fun replaceChildNode(node: Node, replacement: Node) { if(node===target) diff --git a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt index 857c273f6..55dd6eea6 100644 --- a/compilerAst/src/prog8/ast/expressions/InferredTypes.kt +++ b/compilerAst/src/prog8/ast/expressions/InferredTypes.kt @@ -15,6 +15,8 @@ object InferredTypes { fun getOrElse(transform: (InferredType) -> DataType): DataType = if(isUnknown || isVoid) transform(this) else datatype!! infix fun istype(type: DataType): Boolean = if(isUnknown || isVoid) false else this.datatype==type + infix fun isnot(type: DataType): Boolean = if(isUnknown || isVoid) true else this.datatype!=type + fun oneOf(vararg types: DataType) = if(isUnknown || isVoid) false else this.datatype in types companion object { fun unknown() = InferredType(isUnknown = true, isVoid = false, datatype = null) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 40d099cd1..9b41aebfc 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -648,8 +648,8 @@ class Subroutine(override val name: String, return "Subroutine(name=$name, parameters=$parameters, returntypes=$returntypes, ${statements.size} statements, address=$asmAddress)" } - fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } - fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } + fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) } fun shouldSaveX() = CpuRegister.X in asmClobbers || regXasResult() || regXasParam() class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean) diff --git a/compilerAst/src/prog8/parser/Prog8Parser.kt b/compilerAst/src/prog8/parser/Prog8Parser.kt index c1b7ff63c..546615afa 100644 --- a/compilerAst/src/prog8/parser/Prog8Parser.kt +++ b/compilerAst/src/prog8/parser/Prog8Parser.kt @@ -42,17 +42,9 @@ object Prog8Parser { return module } - private class ParsedModule(source: SourceCode) : Module( - // FIXME: hacking together a name for the module: - name = source.pathString() - .substringBeforeLast(".") // must also work with an origin = "" - .substringAfterLast("/") - .substringAfterLast("\\") - .replace("String@", "anonymous_"), - statements = mutableListOf(), - position = Position(source.origin, 1, 0, 0), - source - ) { + private class ParsedModule(source: SourceCode) : + Module(mutableListOf(), Position(source.origin, 1, 0, 0), source) + { /** * Adds a [Directive] to [statements] and @@ -62,7 +54,7 @@ object Prog8Parser { fun add(child: Directive) { child.linkParents(this) statements.add(child) - } + } /** * Adds a [Block] to [statements] and * sets this Module as its [parent]. @@ -71,7 +63,7 @@ object Prog8Parser { fun add(child: Block) { child.linkParents(this) statements.add(child) - } + } } private object Prog8ErrorStrategy: BailErrorStrategy() { diff --git a/compilerAst/src/prog8/parser/SourceCode.kt b/compilerAst/src/prog8/parser/SourceCode.kt index 44436b44a..c41c676f2 100644 --- a/compilerAst/src/prog8/parser/SourceCode.kt +++ b/compilerAst/src/prog8/parser/SourceCode.kt @@ -3,8 +3,11 @@ package prog8.parser import org.antlr.v4.runtime.CharStream import org.antlr.v4.runtime.CharStreams import java.io.File +import java.io.IOException +import java.nio.channels.Channels +import java.nio.charset.CodingErrorAction +import java.nio.charset.StandardCharsets import java.nio.file.Path -import kotlin.io.path.absolutePathString import kotlin.io.path.exists import kotlin.io.path.isDirectory import kotlin.io.path.isReadable @@ -13,7 +16,7 @@ import kotlin.io.path.isReadable * Encapsulates - and ties together - actual source code (=text) * and its [origin]. */ -abstract class SourceCode { +sealed class SourceCode { /** * To be used *only* by the parser (as input to a TokenStream). @@ -22,29 +25,23 @@ abstract class SourceCode { internal abstract fun getCharStream(): CharStream /** - * Whether this [SourceCode] instance was created by - * factory method [fromResources] + * Whether this [SourceCode] instance was created as a [Resource] */ abstract val isFromResources: Boolean /** - * Where this [SourceCode] instance came from. - * This can be one of the following: - * * a normal string representation of a [java.nio.file.Path], if it originates from a file (see [fromPath]) - * * `` if was created via [of] - * * `library:/x/y/z.ext` if it is a library file that was loaded from resources (see [fromResources]) + * Whether this [SourceCode] instance was created as a [File] */ - abstract val origin: String - + abstract val isFromFilesystem: Boolean /** - * FIXME: hacking together a [SourceCode]'s "path string" - * This is really just [origin] with any stuff removed that would render it an invalid path name. - * (Note: a *valid* path name does NOT mean that the denoted file or folder *exists*) + * Where this [SourceCode] instance came from. + * This can be one of the following: + * * a normal string representation of a [java.nio.file.Path], if it originates from a file (see [File]) + * * `$stringSourcePrefix44c56085>` if was created via [String] + * * `library:/x/y/z.ext` if it is a library file that was loaded from resources (see [Resource]) */ - fun pathString() = - origin - .substringAfter("<").substringBeforeLast(">") // or from plain string? + abstract val origin: String /** * The source code as plain string. @@ -58,42 +55,45 @@ abstract class SourceCode { */ final override fun toString() = "${this.javaClass.name}[${this.origin}]" - // "static" factory methods companion object { /** * filename prefix to designate library files that will be retreived from internal resources rather than disk */ const val libraryFilePrefix = "library:" + const val stringSourcePrefix = "`. - */ - fun of(text: String): SourceCode { - return object : SourceCode() { - override val isFromResources = false - override val origin = "" - override fun getCharStream(): CharStream { - return CharStreams.fromString(text) - } - } - } + /** + * Turn a plain String into a [SourceCode] object. + * [origin] will be something like `$stringSourcePrefix44c56085>`. + */ + class Text(val text: String): SourceCode() { + override val isFromResources = false + override val isFromFilesystem = false + override val origin = "$stringSourcePrefix${System.identityHashCode(text).toString(16)}>" + override fun getCharStream(): CharStream = CharStreams.fromString(text, origin) + } - /** - * Get [SourceCode] from the file represented by the specified Path. - * This does not actually *access* the file, but it does check - * whether it - * * exists - * * is a regular file (ie: not a directory) - * * and is actually readable - * - * [origin] will be the given path in absolute and normalized form. - * @throws NoSuchFileException if the file does not exist - * @throws AccessDeniedException if the given path points to a directory or the file is non-readable for some other reason - */ - fun fromPath(path: Path): SourceCode { - val normalized = path.normalize() + /** + * Get [SourceCode] from the file represented by the specified Path. + * This does not actually *access* the file, but it does check + * whether it + * * exists + * * is a regular file (ie: not a directory) + * * and is actually readable + * + * [origin] will be the given path in absolute and normalized form. + * @throws NoSuchFileException if the file does not exist + * @throws AccessDeniedException if the given path points to a directory or the file is non-readable for some other reason + */ + class File(path: Path): SourceCode() { + private val normalized = path.normalize() + init { val file = normalized.toFile() if (!path.exists()) throw NoSuchFileException(file) @@ -101,40 +101,53 @@ abstract class SourceCode { throw AccessDeniedException(file, reason = "Not a file but a directory") if (!path.isReadable()) throw AccessDeniedException(file, reason = "Is not readable") - return object : SourceCode() { - override val isFromResources = false - override val origin = normalized.absolutePathString() - override fun getCharStream(): CharStream { - return CharStreams.fromPath(normalized) - } - } } - /** - * [origin]: `` for a given `pathString` of "x/y/z.p8" - */ - fun fromResources(pathString: String): SourceCode { - val path = Path.of(pathString).normalize() - val sep = "/" - val normalized = sep + path.toMutableList().joinToString(sep) - val rscURL = object{}.javaClass.getResource(normalized) + override val isFromResources = false + override val isFromFilesystem = true + override val origin = relative(normalized).toString() + override fun getCharStream(): CharStream = CharStreams.fromPath(normalized) + } + + /** + * [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8" + */ + class Resource(pathString: String): SourceCode() { + private val normalized = "/" + Path.of(pathString).normalize().toMutableList().joinToString("/") + + init { + val rscURL = object {}.javaClass.getResource(normalized) if (rscURL == null) { - val rscRoot = object{}.javaClass.getResource("/") + val rscRoot = object {}.javaClass.getResource("/") throw NoSuchFileException( File(normalized), - reason = "looked in resources rooted at $rscRoot") - } - return object : SourceCode() { - override val isFromResources = true - override val origin = "$libraryFilePrefix$normalized" - override fun getCharStream(): CharStream { - val inpStr = object {}.javaClass.getResourceAsStream(normalized) - return CharStreams.fromStream(inpStr) - } + reason = "looked in resources rooted at $rscRoot" + ) } } - // TODO: possibly more, like fromURL(..) + override val isFromResources = true + override val isFromFilesystem = false + override val origin = "$libraryFilePrefix$normalized" + override fun getCharStream(): CharStream { + val inpStr = object {}.javaClass.getResourceAsStream(normalized)!! + // CharStreams.fromStream() doesn't allow us to set the stream name properly, so we use a lower level api + val channel = Channels.newChannel(inpStr) + return CharStreams.fromChannel(channel, StandardCharsets.UTF_8, 4096, CodingErrorAction.REPLACE, origin, -1); + } + } + + /** + * SourceCode for internally generated nodes (usually Modules) + */ + class Generated(name: String) : SourceCode() { + override fun getCharStream(): CharStream = throw IOException("generated code nodes doesn't have a stream to read") + override val isFromResources: Boolean = false + override val isFromFilesystem: Boolean = false + override val origin: String = name + } + + // TODO: possibly more, like fromURL(..) /* // For `jar:..` URLs // see https://stackoverflow.com/questions/22605666/java-access-files-in-jar-causes-java-nio-file-filesystemnotfoundexception var url = URL("jar:file:/E:/x16/prog8(meisl)/compiler/build/libs/prog8compiler-7.0-BETA3-all.jar!/prog8lib/c64/textio.p8") @@ -143,5 +156,4 @@ abstract class SourceCode { val fs = FileSystems.newFileSystem(URI.create(parts[0]), mutableMapOf(Pair("", "")) ) val path = fs.getPath(parts[1]) */ - } } diff --git a/compilerAst/test/TestAstToSourceCode.kt b/compilerAst/test/TestAstToSourceCode.kt index bf1918101..82fa0384b 100644 --- a/compilerAst/test/TestAstToSourceCode.kt +++ b/compilerAst/test/TestAstToSourceCode.kt @@ -31,7 +31,7 @@ class TestAstToSourceCode { private fun roundTrip(module: Module): Pair { val generatedText = generateP8(module) try { - val parsedAgain = parseModule(SourceCode.of(generatedText)) + val parsedAgain = parseModule(SourceCode.Text(generatedText)) return Pair(generatedText, parsedAgain) } catch (e: ParseError) { assert(false) { "should produce valid Prog8 but threw $e" } @@ -41,7 +41,7 @@ class TestAstToSourceCode { @Test fun testMentionsInternedStringsModule() { - val orig = SourceCode.of("\n") + val orig = SourceCode.Text("\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex(";.*$internedStringsModuleName")) @@ -49,7 +49,7 @@ class TestAstToSourceCode { @Test fun testImportDirectiveWithLib() { - val orig = SourceCode.of("%import textio\n") + val orig = SourceCode.Text("%import textio\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex("%import +textio")) @@ -57,7 +57,7 @@ class TestAstToSourceCode { @Test fun testImportDirectiveWithUserModule() { - val orig = SourceCode.of("%import my_own_stuff\n") + val orig = SourceCode.Text("%import my_own_stuff\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex("%import +my_own_stuff")) @@ -66,7 +66,7 @@ class TestAstToSourceCode { @Test fun testStringLiteral_noAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { str s = "fooBar\n" } @@ -78,7 +78,7 @@ class TestAstToSourceCode { @Test fun testStringLiteral_withAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { str sAlt = @"fooBar\n" } @@ -90,7 +90,7 @@ class TestAstToSourceCode { @Test fun testCharLiteral_noAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { ubyte c = 'x' } @@ -102,7 +102,7 @@ class TestAstToSourceCode { @Test fun testCharLiteral_withAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { ubyte cAlt = @'x' } diff --git a/compilerAst/test/TestProg8Parser.kt b/compilerAst/test/TestProg8Parser.kt index 7e3c6d3fe..4910fc7e6 100644 --- a/compilerAst/test/TestProg8Parser.kt +++ b/compilerAst/test/TestProg8Parser.kt @@ -1,6 +1,5 @@ package prog8tests -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance @@ -18,7 +17,6 @@ import prog8.parser.SourceCode import prog8tests.helpers.assumeNotExists import prog8tests.helpers.assumeReadableFile import prog8tests.helpers.fixturesDir -import kotlin.io.path.absolutePathString import kotlin.io.path.name import kotlin.io.path.nameWithoutExtension import kotlin.test.assertContains @@ -39,7 +37,7 @@ class TestProg8Parser { @Test fun `is not required - #40, fixed by #45`() { val nl = "\n" // say, Unix-style (different flavours tested elsewhere) - val src = SourceCode.of("foo {" + nl + "}") // source ends with '}' (= NO newline, issue #40) + val src = SourceCode.Text("foo {" + nl + "}") // source ends with '}' (= NO newline, issue #40) // #40: Prog8ANTLRParser would report (throw) "missing at ''" val module = parseModule(src) @@ -50,7 +48,7 @@ class TestProg8Parser { fun `is still accepted - #40, fixed by #45`() { val nl = "\n" // say, Unix-style (different flavours tested elsewhere) val srcText = "foo {" + nl + "}" + nl // source does end with a newline (issue #40) - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } } @@ -65,22 +63,22 @@ class TestProg8Parser { // GOOD: 2nd block `bar` does start on a new line; however, a nl at the very end ain't needed val srcGood = "foo {" + nl + "}" + nl + "bar {" + nl + "}" - assertFailsWith { parseModule(SourceCode.of(srcBad)) } - val module = parseModule(SourceCode.of(srcGood)) + assertFailsWith { parseModule(SourceCode.Text(srcBad)) } + val module = parseModule(SourceCode.Text(srcGood)) assertEquals(2, module.statements.size) } @Test fun `is required between two Blocks or Directives - #47`() { // block and block - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" blockA { } blockB { } """)) } // block and directive - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" blockB { } %import textio """)) } @@ -89,12 +87,12 @@ class TestProg8Parser { // Leaving them in anyways. // dir and block - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" %import textio blockB { } """)) } - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" %import textio %import syslib """)) } } @@ -123,7 +121,7 @@ class TestProg8Parser { "}" + nlUnix // end with newline (see testModuleSourceNeedNotEndWithNewline) - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(2, module.statements.size) } } @@ -142,7 +140,7 @@ class TestProg8Parser { blockA { } """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } @@ -159,7 +157,7 @@ class TestProg8Parser { blockB { } """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(2, module.statements.size) } @@ -174,7 +172,7 @@ class TestProg8Parser { ; comment """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } } @@ -187,7 +185,7 @@ class TestProg8Parser { val importedNoExt = assumeNotExists(fixturesDir, "i_do_not_exist") assumeNotExists(fixturesDir, "i_do_not_exist.p8") val text = "%import ${importedNoExt.name}" - val module = parseModule(SourceCode.of(text)) + val module = parseModule(SourceCode.Text(text)) assertEquals(1, module.statements.size) } @@ -198,14 +196,14 @@ class TestProg8Parser { inner class EmptySourcecode { @Test fun `from an empty string should result in empty Module`() { - val module = parseModule(SourceCode.of("")) + val module = parseModule(SourceCode.Text("")) assertEquals(0, module.statements.size) } @Test fun `from an empty file should result in empty Module`() { val path = assumeReadableFile(fixturesDir, "empty.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) assertEquals(0, module.statements.size) } } @@ -218,16 +216,16 @@ class TestProg8Parser { main { } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) // Note: assertContains has *actual* as first param - assertContains(module.name, Regex("^anonymous_[0-9a-f]+$")) + assertContains(module.name, Regex("^$")) } @Test fun `parsed from a file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) assertEquals(path.nameWithoutExtension, module.name) } } @@ -287,9 +285,9 @@ class TestProg8Parser { fun `in ParseError from bad string source code`() { val srcText = "bad * { }\n" - assertFailsWith { parseModule(SourceCode.of(srcText)) } + assertFailsWith { parseModule(SourceCode.Text(srcText)) } try { - parseModule(SourceCode.of(srcText)) + parseModule(SourceCode.Text(srcText)) } catch (e: ParseError) { assertPosition(e.position, Regex("^$"), 1, 4, 4) } @@ -299,11 +297,11 @@ class TestProg8Parser { fun `in ParseError from bad file source code`() { val path = assumeReadableFile(fixturesDir, "file_with_syntax_error.p8") - assertFailsWith { parseModule(SourceCode.fromPath(path)) } + assertFailsWith { parseModule(SourceCode.File(path)) } try { - parseModule(SourceCode.fromPath(path)) + parseModule(SourceCode.File(path)) } catch (e: ParseError) { - assertPosition(e.position, path.absolutePathString(), 2, 6) // TODO: endCol wrong + assertPosition(e.position, SourceCode.relative(path).toString(), 2, 6) // TODO: endCol wrong } } @@ -313,26 +311,24 @@ class TestProg8Parser { main { } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertPositionOf(module, Regex("^$"), 1, 0) // TODO: endCol wrong } @Test fun `of Module parsed from a file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - - val module = parseModule(SourceCode.fromPath(path)) - assertPositionOf(module, path.absolutePathString(), 1, 0) // TODO: endCol wrong + val module = parseModule(SourceCode.File(path)) + assertPositionOf(module, SourceCode.relative(path).toString(), 1, 0) // TODO: endCol wrong } @Test fun `of non-root Nodes parsed from file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) val mpf = module.position.file - - assertPositionOf(module, path.absolutePathString(), 1, 0) // TODO: endCol wrong + assertPositionOf(module, SourceCode.relative(path).toString(), 1, 0) // TODO: endCol wrong val mainBlock = module.statements.filterIsInstance()[0] assertPositionOf(mainBlock, mpf, 1, 0) // TODO: endCol wrong! val startSub = mainBlock.statements.filterIsInstance()[0] @@ -344,10 +340,9 @@ class TestProg8Parser { * TODO: this test is testing way too much at once */ @Test - @Disabled("TODO: fix .position of nodes below Module - step 8, 'refactor AST gen'") fun `of non-root Nodes parsed from a string`() { val srcText = """ - %target 16, "abc" ; DirectiveArg directly inherits from Node - neither an Expression nor a Statement..? + %zeropage basicsafe ; DirectiveArg directly inherits from Node - neither an Expression nor a Statement..? main { sub start() { ubyte foo = 42 @@ -360,7 +355,7 @@ class TestProg8Parser { } } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) val mpf = module.position.file val targetDirective = module.statements.filterIsInstance()[0] @@ -388,7 +383,7 @@ class TestProg8Parser { @Test fun `in argument position, no altEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { chrout('\n') @@ -409,7 +404,7 @@ class TestProg8Parser { @Test fun `on rhs of block-level var decl, no AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { ubyte c = 'x' } @@ -426,7 +421,7 @@ class TestProg8Parser { @Test fun `on rhs of block-level const decl, with AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { const ubyte c = @'x' } @@ -443,7 +438,7 @@ class TestProg8Parser { @Test fun `on rhs of subroutine-level var decl, no AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { ubyte c = 'x' @@ -463,7 +458,7 @@ class TestProg8Parser { @Test fun `on rhs of subroutine-level const decl, with AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { const ubyte c = @'x' @@ -487,7 +482,7 @@ class TestProg8Parser { @Test fun `in for-loops`() { - val module = parseModule(SourceCode.of(""" + val module = parseModule(SourceCode.Text(""" main { sub start() { ubyte ub diff --git a/compilerAst/test/TestSourceCode.kt b/compilerAst/test/TestSourceCode.kt index 1597b7ad7..04d8e5d99 100644 --- a/compilerAst/test/TestSourceCode.kt +++ b/compilerAst/test/TestSourceCode.kt @@ -1,13 +1,11 @@ package prog8tests -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import prog8.parser.SourceCode import prog8.parser.SourceCode.Companion.libraryFilePrefix import prog8tests.helpers.* import kotlin.io.path.Path -import kotlin.io.path.absolutePathString import kotlin.test.assertContains import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -22,7 +20,7 @@ class TestSourceCode { val text = """ main { } """.trimIndent() - val src = SourceCode.of(text) + val src = SourceCode.Text(text) val actualText = src.getCharStream().toString() assertContains(src.origin, Regex("^$")) @@ -33,28 +31,27 @@ class TestSourceCode { fun testFromPathWithNonExistingPath() { val filename = "i_do_not_exist.p8" val path = assumeNotExists(fixturesDir, filename) - assertFailsWith { SourceCode.fromPath(path) } + assertFailsWith { SourceCode.File(path) } } @Test fun testFromPathWithMissingExtension_p8() { val pathWithoutExt = assumeNotExists(fixturesDir,"simple_main") assumeReadableFile(fixturesDir,"simple_main.p8") - assertFailsWith { SourceCode.fromPath(pathWithoutExt) } + assertFailsWith { SourceCode.File(pathWithoutExt) } } @Test fun testFromPathWithDirectory() { - assertFailsWith { SourceCode.fromPath(fixturesDir) } + assertFailsWith { SourceCode.File(fixturesDir) } } @Test fun testFromPathWithExistingPath() { val filename = "simple_main.p8" val path = assumeReadableFile(fixturesDir, filename) - val src = SourceCode.fromPath(path) - - val expectedOrigin = path.normalize().absolutePathString() + val src = SourceCode.File(path) + val expectedOrigin = SourceCode.relative(path).toString() assertEquals(expectedOrigin, src.origin) assertEquals(path.toFile().readText(), src.asString()) } @@ -64,9 +61,8 @@ class TestSourceCode { val filename = "simple_main.p8" val path = Path(".", "test", "..", "test", "fixtures", filename) val srcFile = assumeReadableFile(path).toFile() - val src = SourceCode.fromPath(path) - - val expectedOrigin = path.normalize().absolutePathString() + val src = SourceCode.File(path) + val expectedOrigin = SourceCode.relative(path).toString() assertEquals(expectedOrigin, src.origin) assertEquals(srcFile.readText(), src.asString()) } @@ -75,7 +71,7 @@ class TestSourceCode { fun testFromResourcesWithExistingP8File_withoutLeadingSlash() { val pathString = "prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -85,7 +81,7 @@ class TestSourceCode { fun testFromResourcesWithExistingP8File_withLeadingSlash() { val pathString = "/prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -95,7 +91,7 @@ class TestSourceCode { fun testFromResourcesWithExistingAsmFile_withoutLeadingSlash() { val pathString = "prog8lib/math.asm" val srcFile = assumeReadableFile(resourcesDir, pathString).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -106,7 +102,7 @@ class TestSourceCode { fun testFromResourcesWithExistingAsmFile_withLeadingSlash() { val pathString = "/prog8lib/math.asm" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -116,7 +112,7 @@ class TestSourceCode { fun testFromResourcesWithNonNormalizedPath() { val pathString = "/prog8lib/../prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/prog8lib/math.p8", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -129,22 +125,13 @@ class TestSourceCode { val pathString = "/prog8lib/i_do_not_exist" assumeNotExists(resourcesDir, pathString.substring(1)) - assertFailsWith { SourceCode.fromResources(pathString) } + assertFailsWith { SourceCode.Resource(pathString) } } @Test fun testFromResourcesWithNonExistingFile_withoutLeadingSlash() { val pathString = "prog8lib/i_do_not_exist" assumeNotExists(resourcesDir, pathString) - assertFailsWith { SourceCode.fromResources(pathString) } + assertFailsWith { SourceCode.Resource(pathString) } } - - @Test - @Disabled("TODO: inside resources: cannot tell apart a folder from a file") - fun testFromResourcesWithDirectory() { - val pathString = "/prog8lib" - assumeDirectory(resourcesDir, pathString.substring(1)) - assertFailsWith { SourceCode.fromResources(pathString) } - } - } diff --git a/compilerAst/test/ast/ProgramTests.kt b/compilerAst/test/ast/ProgramTests.kt index e01e44324..5e51bf10c 100644 --- a/compilerAst/test/ast/ProgramTests.kt +++ b/compilerAst/test/ast/ProgramTests.kt @@ -11,6 +11,7 @@ import prog8.ast.Module import prog8.ast.Program import prog8.ast.base.Position import prog8.ast.internedStringsModuleName +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import kotlin.test.assertContains @@ -39,7 +40,7 @@ class ProgramTests { @Test fun withEmptyModule() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) + val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) val retVal = program.addModule(m1) @@ -52,7 +53,7 @@ class ProgramTests { assertFailsWith { program.addModule(m1) } .let { assertThat(it.message, containsString(m1.name)) } - val m2 = Module(m1.name, mutableListOf(), m1.position, m1.source) + val m2 = Module(mutableListOf(), m1.position, m1.source) assertFailsWith { program.addModule(m2) } .let { assertThat(it.message, containsString(m2.name)) } } @@ -73,15 +74,15 @@ class ProgramTests { @Test fun withForeignModule() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m = Module("bar", mutableListOf(), Position.DUMMY, null) + val m = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) assertFailsWith { program.moveModuleToFront(m) } } @Test fun withFirstOfPreviouslyAddedModules() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) - val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, null) + val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) + val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl")) program.addModule(m1) program.addModule(m2) @@ -92,8 +93,8 @@ class ProgramTests { @Test fun withSecondOfPreviouslyAddedModules() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) - val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, null) + val m1 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) + val m2 = Module(mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl")) program.addModule(m1) program.addModule(m2) diff --git a/docs/source/building.rst b/docs/source/building.rst index 3352bb974..f1dc5df90 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -118,11 +118,13 @@ They are embedded into the packaged release version of the compiler so you don't where they are, but their names are still reserved. -User defined library files and -location -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -You can create library files yourself too that can be shared among programs. -You can tell the compiler where it should look for these files, by using -the libdirs command line option. +Importing other source files and specifying search location(s) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You can create multiple source files yourself to modularize your large programs into +multiple module files. You can also create "library" modules this way with handy routines, +that can be shared among programs. By importing those module files, you can use them in other modules. +It is possible to tell the compiler where it should look for these files, by using +the ``srcdirs`` command line option. .. _debugging: diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 76ccad171..2be82798f 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,10 +3,7 @@ TODO For next compiler release ^^^^^^^^^^^^^^^^^^^^^^^^^ -- rename libdirs option to srcdirs? -- can we derive module.name from module.source (taking just the filename base)? -- can Position.file be a Path- making the source variable for nodes unnecessary? -- address more questions/issues from the testability discussions. +... Blocked by Commander-x16 v39 release @@ -18,11 +15,12 @@ Blocked by Commander-x16 v39 release Future ^^^^^^ - get rid of all TODO's and FIXME's in the code -- improve testability further, add more tests -- can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer +- improve testability further, add more tests, address more questions/issues from the testability discussions. +- replace certain uses of inferredType.getOr(DataType.UNDEFINED) by i.getOrElse({ errorhandler }) - see if we can remove more "[InferredType].getOr(DataType.UNDEFINED)" - use more of Result<> and Either<> to handle errors/ nulls better - fix the asm-labels problem (github issue #62) +- can we get rid of pieces of asmgen.AssignmentAsmGen by just reusing the AugmentableAssignment ? generated code should not suffer - c64: make the graphics.BITMAP_ADDRESS configurable (VIC banking) - optimize several inner loops in gfx2 even further? - add modes 2 and 3 to gfx2 (lowres 4 color and 16 color)? diff --git a/examples/test.p8 b/examples/test.p8 index b1146ae87..cfa7a4362 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,14 +1,18 @@ %import textio main { - str myBar = "main.bar" + sub start() { + ubyte xx -foo_bar: - %asminclude "compiler/test/fixtures/foo_bar.asm" ; FIXME: should be accessible from inside start() but give assembler error - - sub start() { - txt.print(myBar) - txt.print(&foo_bar) - return - } + when xx { + 2 -> { + } + 3 -> { + } + 50 -> { + } + else -> { + } + } + } } diff --git a/httpCompilerService/src/prog8/http/TestHttp.kt b/httpCompilerService/src/prog8/http/TestHttp.kt index 3fdcf4137..f89c38378 100644 --- a/httpCompilerService/src/prog8/http/TestHttp.kt +++ b/httpCompilerService/src/prog8/http/TestHttp.kt @@ -34,8 +34,8 @@ class RequestParser : Take { writeAssembly = true, slowCodegenWarnings = true, compilationTarget = "c64", - libdirs = emptyList(), - outputDir = Path.of(".") + sourceDirs = emptyList(), + outputDir = Path.of("") ) return RsJson(Jsonding()) }