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.ast.walk.IAstModification
import prog8.code.core.AssociativeOperators import prog8.code.core.AssociativeOperators
import prog8.code.core.DataType import prog8.code.core.DataType
import prog8.code.core.IErrorReporter
import kotlin.math.floor 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> { override fun before(memread: DirectMemoryRead, parent: Node): Iterable<IAstModification> {
// @( &thing ) --> thing (but only if thing is a byte type!) // @( &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) { else if(expr.operator=="*" && rightconst!=null && expr.left is StringLiteral) {
// mutiply a string. // mutiply a string.
val part = expr.left as StringLiteral 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) val newStr = StringLiteral(part.value.repeat(rightconst.number.toInt()), part.encoding, expr.position)
return listOf(IAstModification.ReplaceNode(expr, newStr, parent)) return listOf(IAstModification.ReplaceNode(expr, newStr, parent))
} }

View File

@@ -22,7 +22,7 @@ fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget)
if(errors.noErrors()) { if(errors.noErrors()) {
valuetypefixer.applyModifications() valuetypefixer.applyModifications()
val optimizer = ConstantFoldingOptimizer(this) val optimizer = ConstantFoldingOptimizer(this, errors)
optimizer.visit(this) optimizer.visit(this)
while (errors.noErrors() && optimizer.applyModifications() > 0) { while (errors.noErrors() && optimizer.applyModifications() > 0) {
optimizer.visit(this) 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)) val elementDt = ArrayToElementTypes.getValue(dt.getOr(DataType.UNDEFINED))
NumericLiteral.optimalInteger(program.memsizer.memorySize(elementDt) * length, position) 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 -> NumericLiteral(DataType.UBYTE, program.memsizer.memorySize(dt.getOr(DataType.UNDEFINED)).toDouble(), position)
} }
} else { } 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 try { // just *try* if it can be encoded, don't actually do it
val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding) val bytes = compilerOptions.compTarget.encodeString(string.value, string.encoding)
if(0u in bytes) 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) { } catch (cx: CharConversionException) {
errors.err(cx.message ?: "can't encode string", string.position) 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:: 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`` ``find (string, char) -> ubyte index + carry bit``
Locates the first position of the given character in the string, returns carry bit set if found 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. 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`` ``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.

View File

@@ -44,3 +44,7 @@ Various things:
`Prog8 code for ZSMkit <https://github.com/mooinglemur/zsmkit/tree/main/p8demo>`_ `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. 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") 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: ``&`` address of: ``&``
This is a prefix operator that can be applied to a string or array variable or literal value. 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`` It results in the memory address (UWORD) of that string or array in memory: ``uword a = &stringvar``

View File

@@ -2,6 +2,9 @@
TODO 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 .... - [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? - 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) - (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? - 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: 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 - 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 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) - 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)
- postincrdecr as expression, preincrdecr expression (`y = x++`, `y = ++x`) .... is this even possible, expression with side effects like this?
- 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 - 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 kotlin.code.style=official
javaVersion=11 javaVersion=11
kotlinVersion=1.9.20 kotlinVersion=1.9.20
version=9.7 version=9.8-SNAPSHOT