diff --git a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt index b1b4581fb..f31ed8a07 100644 --- a/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/codeOptimizers/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -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 { // @( &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)) } diff --git a/codeOptimizers/src/prog8/optimizer/Extensions.kt b/codeOptimizers/src/prog8/optimizer/Extensions.kt index e5542b627..5467241ea 100644 --- a/codeOptimizers/src/prog8/optimizer/Extensions.kt +++ b/codeOptimizers/src/prog8/optimizer/Extensions.kt @@ -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) diff --git a/compiler/src/prog8/compiler/BuiltinFunctions.kt b/compiler/src/prog8/compiler/BuiltinFunctions.kt index 7758725c3..57646ff68 100644 --- a/compiler/src/prog8/compiler/BuiltinFunctions.kt +++ b/compiler/src/prog8/compiler/BuiltinFunctions.kt @@ -125,7 +125,7 @@ private fun builtinSizeof(args: List, 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 { diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 2cb5ab60c..cbacbc48e 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -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) } diff --git a/docs/source/_static/curious.png b/docs/source/_static/curious.png new file mode 100644 index 000000000..b14a99a53 Binary files /dev/null and b/docs/source/_static/curious.png differ diff --git a/docs/source/compiling.rst b/docs/source/compiling.rst index b56871d44..7b2c77cde 100644 --- a/docs/source/compiling.rst +++ b/docs/source/compiling.rst @@ -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 diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 6edfd3302..f67310fce 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -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. diff --git a/docs/source/software.rst b/docs/source/software.rst index 1b5504d71..b7a548889 100644 --- a/docs/source/software.rst +++ b/docs/source/software.rst @@ -44,3 +44,7 @@ Various things: `Prog8 code for ZSMkit `_ ZSMkit is an advanced music and sound effects engine for the Commander X16. + +.. image:: _static/curious.png + :align: center + :alt: Curious diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 04f80c1d7..7ca6f5eda 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -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`` diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 2f8247868..1e3191a92 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -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==true) -- postincrdecr as expression, preincrdecr expression (`y = x++`, `y = ++x`) .... is this even possible, expression with side effects like this? +- chained comparisons `10 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 diff --git a/gradle.properties b/gradle.properties index 716be00a1..9408d3f86 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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