From f2d27403c55f06af4ba23e645dcb4d7d2cee6fac Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 21 Jul 2022 00:38:30 +0200 Subject: [PATCH] add string.endswith() to efficiently test for a suffix without copying add string.startswith() to efficiently test for string prefix without copying --- .../prog8/codegen/virtual/AssignmentGen.kt | 5 +++++ .../codegen/virtual/VariableAllocator.kt | 4 ++-- compiler/res/prog8lib/string.p8 | 21 ++++++++++++++++++- compiler/res/prog8lib/virtual/string.p8 | 20 ++++++++++++++++++ compiler/res/version.txt | 2 +- docs/source/libraries.rst | 10 +++++++++ docs/source/todo.rst | 2 ++ 7 files changed, 60 insertions(+), 4 deletions(-) diff --git a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt index 9e0dffba9..8b2860bec 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/AssignmentGen.kt @@ -165,6 +165,11 @@ internal class AssignmentGen(private val codeGen: CodeGen, private val expressio throw AssemblyError("non-array var indexing requires bytes index") val idxReg = codeGen.vmRegisters.nextFree() code += expressionEval.translateExpression(array.index, idxReg, -1) + if(zero) { + // there's no STOREZIX instruction + resultRegister = codeGen.vmRegisters.nextFree() + code += VmCodeInstruction(Opcode.LOAD, vmDt, reg1=resultRegister, value=0) + } code += VmCodeInstruction(Opcode.STOREIX, vmDt, reg1=resultRegister, reg2=idxReg, value = variableAddr) return code } diff --git a/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt b/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt index 2eb7bbf9d..ad66afaca 100644 --- a/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt +++ b/codeGenVirtual/src/prog8/codegen/virtual/VariableAllocator.kt @@ -60,8 +60,8 @@ class VariableAllocator(private val st: SymbolTable, private val program: PtProg DataType.FLOAT -> (variable.initialNumericValue ?: 0.0).toString() in NumericDatatypes -> (variable.initialNumericValue ?: 0).toHex() DataType.STR -> { - val encoded = program.encoding.encodeString(variable.initialStringValue!!.first, variable.initialStringValue!!.second) - encoded.joinToString(",") { it.toInt().toHex() } + ",0" + val encoded = program.encoding.encodeString(variable.initialStringValue!!.first, variable.initialStringValue!!.second) + listOf(0u) + encoded.joinToString(",") { it.toInt().toHex() } } DataType.ARRAY_F -> { if(variable.initialArrayValue!=null) { diff --git a/compiler/res/prog8lib/string.p8 b/compiler/res/prog8lib/string.p8 index 52bad608d..ff4054fd0 100644 --- a/compiler/res/prog8lib/string.p8 +++ b/compiler/res/prog8lib/string.p8 @@ -223,6 +223,26 @@ _done rts }} } + sub startswith(str st, str prefix) -> bool { + ubyte prefix_len = length(prefix) + ubyte str_len = length(st) + if prefix_len > str_len + return false + cx16.r9L = st[prefix_len] + st[prefix_len] = 0 + cx16.r9H = compare(st, prefix) as ubyte + st[prefix_len] = cx16.r9L + return cx16.r9H==0 + } + + sub endswith(str st, str suffix) -> bool { + ubyte suffix_len = length(suffix) + ubyte str_len = length(st) + if suffix_len > str_len + return false + return compare(st + str_len - suffix_len, suffix) == 0 + } + asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> ubyte @A { %asm {{ ; pattern matching of a string. @@ -293,5 +313,4 @@ fail clc ; yes, no match found, return with c=0 rts }} } - } diff --git a/compiler/res/prog8lib/virtual/string.p8 b/compiler/res/prog8lib/virtual/string.p8 index dbe2cbb4e..fa88e11c6 100644 --- a/compiler/res/prog8lib/virtual/string.p8 +++ b/compiler/res/prog8lib/virtual/string.p8 @@ -113,4 +113,24 @@ string { ix++ } } + + sub startswith(str st, str prefix) -> bool { + ubyte prefix_len = length(prefix) + ubyte str_len = length(st) + if prefix_len > str_len + return false + cx16.r9L = st[prefix_len] + st[prefix_len] = 0 + cx16.r9H = compare(st, prefix) as ubyte + st[prefix_len] = cx16.r9L + return cx16.r9H==0 + } + + sub endswith(str st, str suffix) -> bool { + ubyte suffix_len = length(suffix) + ubyte str_len = length(st) + if suffix_len > str_len + return false + return compare(st + str_len - suffix_len, suffix) == 0 + } } diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 56b6be4eb..47ea0f6ff 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -8.3.1 +8.4-dev diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 79f6120e6..2cacd156e 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -190,6 +190,16 @@ Provides string manipulation routines. ``upper(string)`` Uppercases the petscii-string in place. +``startswith(string, prefix) -> bool`` + Returns true if string starts with prefix, otherwise false + +``endswith(string, suffix) -> bool`` + Returns true if string ends with suffix, otherwise false + +``pattern_match(string, pattern) -> ubyte`` (not on Virtual target) + Returns 1 (true) if the string matches the pattern, 0 (false) if not. + '?' in the pattern matches any one character. '*' in the pattern matches any substring. + floats ------ diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 30d374e9f..a1108c451 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,6 +3,8 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- can the recursive cycle detector print the actual LINES that do the call? + ...