added string.contains().

fixed string and array containment check for length 1.
This commit is contained in:
Irmen de Jong 2024-01-05 20:46:26 +01:00
parent f2daa17b92
commit 334e6dca28
6 changed files with 82 additions and 91 deletions

View File

@ -1898,33 +1898,29 @@ internal class AssignmentAsmGen(private val program: PtProgram,
}
when(dt) {
DataType.STR -> {
// use subroutine
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.out(" pha")
asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.out(" pla")
asmgen.out(" ldy #${numElements-1}")
asmgen.out(" jsr prog8_lib.containment_bytearray")
return
}
DataType.ARRAY_F -> {
throw AssemblyError("containment check of floats not supported")
TODO("containment check of floats")
}
DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE)
asmgen.out(" pha")
asmgen.out(" pha") // need to keep the scratch var safe so we have to do it in this order
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.out(" pla")
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_bytearray")
return
}
DataType.ARRAY_W, DataType.ARRAY_UW -> {
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null)
asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_wordarray")
return
}
else -> throw AssemblyError("invalid dt")
}

View File

@ -20,22 +20,19 @@ string {
}}
}
asmsub left(uword source @R0, ubyte length @A, uword target @R1) clobbers(A, Y) {
asmsub left(uword source @AX, ubyte length @Y, uword target @R1) clobbers(A, Y) {
; Copies the left side of the source string of the given length to target string.
; It is assumed the target string buffer is large enough to contain the result.
; Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
; Modifies in-place, doesnt return a value (so cant be used in an expression).
%asm {{
; need to copy the the cx16 virtual registers to zeropage to be compatible with C64...
ldy cx16.r0
sty P8ZP_SCRATCH_W1
ldy cx16.r0+1
sty P8ZP_SCRATCH_W1+1
ldy cx16.r1
sty P8ZP_SCRATCH_W2
ldy cx16.r1+1
sty P8ZP_SCRATCH_W2+1
tay
; need to copy the the cx16 virtual registers to zeropage to be compatible with C64...
sta P8ZP_SCRATCH_W1
stx P8ZP_SCRATCH_W1+1
lda cx16.r1
sta P8ZP_SCRATCH_W2
lda cx16.r1+1
sta P8ZP_SCRATCH_W2+1
lda #0
sta (P8ZP_SCRATCH_W2),y
cpy #0
@ -51,16 +48,16 @@ _loop dey
; asmgen.out(" jsr prog8_lib.func_leftstr")
}
asmsub right(uword source @R0, ubyte length @A, uword target @R1) clobbers(A,Y) {
asmsub right(uword source @AY, ubyte length @X, uword target @R1) clobbers(A,Y) {
; Copies the right side of the source string of the given length to target string.
; It is assumed the target string buffer is large enough to contain the result.
; Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
; Modifies in-place, doesnt return a value (so cant be used in an expression).
%asm {{
; need to copy the the cx16 virtual registers to zeropage to be compatible with C64...
sta P8ZP_SCRATCH_B1
lda cx16.r0
ldy cx16.r0+1
stx P8ZP_SCRATCH_B1
sta cx16.r0
sty cx16.r0+1
jsr string.length
tya
sec
@ -128,16 +125,14 @@ _startloop dey
}}
}
asmsub find(uword string @R0, ubyte character @A) -> ubyte @A, bool @Pc {
asmsub find(uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc {
; Locates the first position of the given character in the string,
; returns Carry set if found + index in A, or A=0 + Carry clear if not found.
%asm {{
; need to copy the the cx16 virtual registers to zeropage to make this run on C64...
sta P8ZP_SCRATCH_B1
lda cx16.r0
ldy cx16.r0+1
; need to copy the the cx16 virtual registers to zeropage to make this run on C64...
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
stx P8ZP_SCRATCH_B1
ldy #0
- lda (P8ZP_SCRATCH_W1),y
beq _notfound
@ -154,6 +149,13 @@ _found tya
}}
}
asmsub contains(uword string @AY, ubyte character @X) -> bool @Pc {
; Just return true/false if the character is in the given string or not.
%asm {{
jmp find
}}
}
asmsub copy(uword source @R0, uword target @AY) clobbers(A) -> ubyte @Y {
; Copy a string to another, overwriting that one.
; Returns the length of the string that was copied.

View File

@ -65,6 +65,13 @@ string {
return 0
}
sub contains(str st, ubyte character) -> bool {
void find(st, character)
if_cs
return true
return false
}
sub copy(str source, str target) -> ubyte {
; Copy a string to another, overwriting that one.
; Returns the length of the string that was copied.

View File

@ -225,19 +225,6 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
val array = (containment.iterable as ArrayLiteral).value
return checkArray(array)
}
is IdentifierReference -> {
val variable = (containment.iterable as IdentifierReference).targetVarDecl(program)
when(variable?.datatype) {
DataType.STR -> {
val stringVal = (variable.value as StringLiteral)
return checkString(stringVal)
}
in ArrayDatatypes -> {
return checkArray(variable!!)
}
else -> {}
}
}
is RangeExpression -> {
val constValues = (containment.iterable as RangeExpression).toConstantIntegerRange()
if(constValues!=null) {

View File

@ -258,6 +258,10 @@ Provides string manipulation routines.
Simply call this and only act on the carry status with ``if_cc`` for example.
Much like the difference between len(str) and length(str).
``contains (string, char) -> bool``
Just returns true if the character is in the given string, or false if it's not.
For string literals, you can use a containment check expression instead: ``char in "hello world"``.
``compare (string1, string2) -> ubyte result``
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
Note that you can also directly compare strings and string values with each other

View File

@ -1,66 +1,61 @@
%import textio
%import string
%zeropage basicsafe
%option no_sysinit
main {
sub start() {
; is optimizing this useful? : not a1 or not a2 -> not(a1 and a2) likewise for and.
bool @shared a1 = true
bool @shared a2
bool @shared a
bool @shared b
str s = "?"
s[0] = 's'
txt.print(s)
txt.nl()
; absorbption opt:
; if a or (a and b)
; cx16.r0 ++
; if a or (b and a)
; cx16.r0 ++
; if a and (a or b)
; cx16.r0 ++
; if a and (b or a)
; cx16.r0 ++
;
; ; no opt:
; if a and (b and a)
; cx16.r0 ++
; if a or (b or a)
; cx16.r0 ++
if 's' in s {
txt.print("ok1\n")
} else {
txt.print("fail1\n")
}
bool @shared iteration_in_progress = false
ubyte @shared num_bytes = 99
void string.find(s, 's')
if_cs {
txt.print("ok2\n")
} else {
txt.print("fail2\n")
}
if not iteration_in_progress or not num_bytes
txt.print("yep1")
else
txt.print("nope1")
if string.contains(s, 's') {
txt.print("ok3\n")
} else {
txt.print("fail3\n")
}
iteration_in_progress = true
if not iteration_in_progress or not num_bytes
txt.print("yep2")
else
txt.print("nope2")
if 'q' in s {
txt.print("ok1\n")
} else {
txt.print("fail1\n")
}
;
; if a1==0 and a2==0
; cx16.r0++
;
; if (a1!=0 or a2!=0)==0
; cx16.r0++
;
; if a1==0 or a2==0
; cx16.r0++
;
; if (a1!=0 and a2!=0)==0
; cx16.r0++
void string.find(s, 'q')
if_cs {
txt.print("ok2\n")
} else {
txt.print("fail2\n")
}
if string.contains(s, 'q') {
txt.print("ok3\n")
} else {
txt.print("fail3\n")
}
str buffer="?" * 20
str name = "irmen de jong"
string.left(name, 5, buffer)
txt.print(buffer)
txt.nl()
string.right(name, 4, buffer)
txt.print(buffer)
txt.nl()
; if not a1 or not a2
; cx16.r0++
; if not (a1 and a2)
; cx16.r0++
; if not a1 and not a2
; cx16.r0++
; if not (a1 or a2)
; cx16.r0++
}
}