concerns with in for strings

This commit is contained in:
Irmen de Jong 2023-12-11 20:50:56 +01:00
parent e98e951834
commit 08a079a96e
11 changed files with 33 additions and 8 deletions

View File

@ -12,10 +12,11 @@ import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.code.core.AssociativeOperators
import prog8.code.core.DataType
import prog8.code.core.IErrorReporter
import kotlin.math.floor
class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
class ConstantFoldingOptimizer(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
override fun before(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
// @( &thing ) --> thing (but only if thing is a byte type!)
@ -79,6 +80,8 @@ class ConstantFoldingOptimizer(private val program: Program) : AstWalker() {
else if(expr.operator=="*" && rightconst!=null && expr.left is StringLiteral) {
// mutiply a string.
val part = expr.left as StringLiteral
if(part.value.isEmpty())
errors.warn("resulting string has length zero", part.position)
val newStr = StringLiteral(part.value.repeat(rightconst.number.toInt()), part.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, newStr, parent))
}

View File

@ -22,7 +22,7 @@ fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget)
if(errors.noErrors()) {
valuetypefixer.applyModifications()
val optimizer = ConstantFoldingOptimizer(this)
val optimizer = ConstantFoldingOptimizer(this, errors)
optimizer.visit(this)
while (errors.noErrors() && optimizer.applyModifications() > 0) {
optimizer.visit(this)

View File

@ -125,7 +125,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
val elementDt = ArrayToElementTypes.getValue(dt.getOr(DataType.UNDEFINED))
NumericLiteral.optimalInteger(program.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, or perhaps string.length?", position)
else -> NumericLiteral(DataType.UBYTE, program.memsizer.memorySize(dt.getOr(DataType.UNDEFINED)).toDouble(), position)
}
} else {

View File

@ -928,7 +928,7 @@ internal class AstChecker(private val program: Program,
try { // just *try* if it can be encoded, don't actually do it
val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding)
if(0u in bytes)
errors.warn("a character in the string encodes into the 0-byte, which will terminate the string prematurely", string.position)
errors.warn("a character in the string encodes as 0-byte, which will terminate the string prematurely", string.position)
} catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode string", string.position)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@ -348,5 +348,5 @@ to compile and run the Commodore 64 rasterbars example program, use this command
or::
$ ./p8compile.sh -target c64 -emu examples/rasterbars.p8
$ /path/to/p8compile -target c64 -emu examples/rasterbars.p8

View File

@ -238,6 +238,11 @@ Provides string manipulation routines.
``find (string, char) -> ubyte index + carry bit``
Locates the first position of the given character in the string, returns carry bit set if found
and the index in the string. Or 0+carry bit clear if the character was not found.
You can consider this a safer way of checking if a character occurs
in a string than using an `in` containment check - because the find routine
properly stops at the first 0-byte string terminator it encounters.
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).
``compare (string1, string2) -> ubyte result``
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.

View File

@ -44,3 +44,7 @@ Various things:
`Prog8 code for ZSMkit <https://github.com/mooinglemur/zsmkit/tree/main/p8demo>`_
ZSMkit is an advanced music and sound effects engine for the Commander X16.
.. image:: _static/curious.png
:align: center
:alt: Curious

View File

@ -616,6 +616,12 @@ containment check: ``in``
txt.print("email address seems ok")
}
.. caution::
This check compares the needle against *all* elements in the haystack.
For byte arrays and strings(!), this means it considers *all* elements in the array or string with the length as it was declared.
Even when a string was changed and is terminated early with a 0-byte early.
Consider using ``string.find`` followed by ``if_cs`` (for instance) to do a "safer" containment check in such strings.
address of: ``&``
This is a prefix operator that can be applied to a string or array variable or literal value.
It results in the memory address (UWORD) of that string or array in memory: ``uword a = &stringvar``

View File

@ -2,6 +2,9 @@
TODO
====
- [on branch: call-pointers] allow calling a subroutine via a pointer variable (indirect JSR, optimized form of callfar())
modify programs (shell, paint) that now use callfar
- [on branch: shortcircuit] investigate McCarthy evaluation again? this may also reduce code size perhaps for things like if a>4 or a<2 ....
...
@ -25,6 +28,11 @@ Compiler:
- OR.... make all this more generic and use some %segment option to create real segments for 64tass?
- (need separate step in codegen and IR to write the "golden" variables)
- [on branch: no-vardecls]
remove astNode from StNode in the symboltable
remove IPtVariable and the 3 derived types (var, constant, memmapped) in the codegen ast
remove VarDecls in compiler ast
- do we need (array)variable alignment tag instead of block alignment tag? You want to align the data, not the code in the block?
- ir: getting it in shape for code generation
- ir: related to the one above: block alignment doesn't translate well to variables in the block (the actual stuff that needs to be aligned in memory) but: need variable alignment tag instead of block alignment tag, really
@ -78,6 +86,5 @@ What if we were to re-introduce Structs in prog8? Some thoughts:
Other language/syntax features to think about
---------------------------------------------
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`) BUT this changes the semantics of what it is right now ! (x==(y==z) 0> x==true)
- postincrdecr as expression, preincrdecr expression (`y = x++`, `y = ++x`) .... is this even possible, expression with side effects like this?
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`) BUT this changes the semantics of what it is right now ! (x==(y==z) --> x==true)
- negative array index to refer to an element from the end of the array. Python `[-1]` or Raku syntax `[\*-1]` , `[\*/2]` .... \*=size of the array

View File

@ -5,4 +5,4 @@ org.gradle.daemon=true
kotlin.code.style=official
javaVersion=11
kotlinVersion=1.9.20
version=9.7
version=9.8-SNAPSHOT