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) { when(dt) {
DataType.STR -> { DataType.STR -> {
// use subroutine
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) 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) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position,"P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.out(" pla") asmgen.out(" pla")
asmgen.out(" ldy #${numElements-1}") asmgen.out(" ldy #${numElements-1}")
asmgen.out(" jsr prog8_lib.containment_bytearray") asmgen.out(" jsr prog8_lib.containment_bytearray")
return
} }
DataType.ARRAY_F -> { DataType.ARRAY_F -> {
throw AssemblyError("containment check of floats not supported") TODO("containment check of floats")
} }
DataType.ARRAY_B, DataType.ARRAY_UB -> { DataType.ARRAY_B, DataType.ARRAY_UB -> {
assignExpressionToRegister(containment.element, RegisterOrPair.A, elementDt == DataType.BYTE) 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) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W1"), symbolName, null, null)
asmgen.out(" pla") asmgen.out(" pla")
asmgen.out(" ldy #$numElements") asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_bytearray") asmgen.out(" jsr prog8_lib.containment_bytearray")
return
} }
DataType.ARRAY_W, DataType.ARRAY_UW -> { DataType.ARRAY_W, DataType.ARRAY_UW -> {
assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt) assignExpressionToVariable(containment.element, "P8ZP_SCRATCH_W1", elementDt)
assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null) assignAddressOf(AsmAssignTarget(TargetStorageKind.VARIABLE, asmgen, DataType.UWORD, containment.definingISub(), containment.position, "P8ZP_SCRATCH_W2"), symbolName, null, null)
asmgen.out(" ldy #$numElements") asmgen.out(" ldy #$numElements")
asmgen.out(" jsr prog8_lib.containment_wordarray") asmgen.out(" jsr prog8_lib.containment_wordarray")
return
} }
else -> throw AssemblyError("invalid dt") 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. ; 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. ; 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. ; 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). ; Modifies in-place, doesnt return a value (so cant be used in an expression).
%asm {{ %asm {{
; need to copy the the cx16 virtual registers to zeropage to be compatible with C64... ; need to copy the the cx16 virtual registers to zeropage to be compatible with C64...
ldy cx16.r0 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1 stx P8ZP_SCRATCH_W1+1
ldy cx16.r0+1 lda cx16.r1
sty P8ZP_SCRATCH_W1+1 sta P8ZP_SCRATCH_W2
ldy cx16.r1 lda cx16.r1+1
sty P8ZP_SCRATCH_W2 sta P8ZP_SCRATCH_W2+1
ldy cx16.r1+1
sty P8ZP_SCRATCH_W2+1
tay
lda #0 lda #0
sta (P8ZP_SCRATCH_W2),y sta (P8ZP_SCRATCH_W2),y
cpy #0 cpy #0
@ -51,16 +48,16 @@ _loop dey
; asmgen.out(" jsr prog8_lib.func_leftstr") ; 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. ; 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. ; 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. ; 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). ; Modifies in-place, doesnt return a value (so cant be used in an expression).
%asm {{ %asm {{
; need to copy the the cx16 virtual registers to zeropage to be compatible with C64... ; need to copy the the cx16 virtual registers to zeropage to be compatible with C64...
sta P8ZP_SCRATCH_B1 stx P8ZP_SCRATCH_B1
lda cx16.r0 sta cx16.r0
ldy cx16.r0+1 sty cx16.r0+1
jsr string.length jsr string.length
tya tya
sec 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, ; 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. ; returns Carry set if found + index in A, or A=0 + Carry clear if not found.
%asm {{ %asm {{
; need to copy the the cx16 virtual registers to zeropage to make this run on C64... ; 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
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1 sty P8ZP_SCRATCH_W1+1
stx P8ZP_SCRATCH_B1
ldy #0 ldy #0
- lda (P8ZP_SCRATCH_W1),y - lda (P8ZP_SCRATCH_W1),y
beq _notfound 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 { asmsub copy(uword source @R0, uword target @AY) clobbers(A) -> ubyte @Y {
; Copy a string to another, overwriting that one. ; Copy a string to another, overwriting that one.
; Returns the length of the string that was copied. ; Returns the length of the string that was copied.

View File

@ -65,6 +65,13 @@ string {
return 0 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 { sub copy(str source, str target) -> ubyte {
; Copy a string to another, overwriting that one. ; Copy a string to another, overwriting that one.
; Returns the length of the string that was copied. ; 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 val array = (containment.iterable as ArrayLiteral).value
return checkArray(array) 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 -> { is RangeExpression -> {
val constValues = (containment.iterable as RangeExpression).toConstantIntegerRange() val constValues = (containment.iterable as RangeExpression).toConstantIntegerRange()
if(constValues!=null) { 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. 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). 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`` ``compare (string1, string2) -> ubyte result``
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2. 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 Note that you can also directly compare strings and string values with each other

View File

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