diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 64f2493cc..c994948cc 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -267,8 +267,8 @@ fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget private fun processAst(program: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) { // perform initial syntax checks and processings println("Processing for target ${compilerOptions.compTarget.name}...") - program.preprocessAst(program, errors) - program.checkIdentifiers(errors, program, compilerOptions) + program.preprocessAst(errors) + program.checkIdentifiers(errors, compilerOptions) errors.report() // TODO: turning char literals into UBYTEs via an encoding should really happen in code gen - but for that we'd need DataType.CHAR // ...but what do we gain from this? We can leave it as it is now: where a char literal is no more than syntactic sugar for an UBYTE value. @@ -283,11 +283,11 @@ private fun processAst(program: Program, errors: IErrorReporter, compilerOptions errors.report() program.addTypecasts(errors, compilerOptions) errors.report() - program.variousCleanups(program, errors, compilerOptions) + program.variousCleanups(errors, compilerOptions) errors.report() program.checkValid(errors, compilerOptions) errors.report() - program.checkIdentifiers(errors, program, compilerOptions) + program.checkIdentifiers(errors, compilerOptions) errors.report() } @@ -316,7 +316,7 @@ private fun postprocessAst(program: Program, errors: IErrorReporter, compilerOpt program.desugaring(errors) program.addTypecasts(errors, compilerOptions) errors.report() - program.variousCleanups(program, errors, compilerOptions) + program.variousCleanups(errors, compilerOptions) val callGraph = CallGraph(program) callGraph.checkRecursiveCalls(errors) errors.report() diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 84da647af..67e1f1012 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -636,8 +636,6 @@ internal class AstChecker(private val program: Program, if(parameter==null) err("string var must be initialized with a string literal") } - else if (decl.type==VarDeclType.VAR && decl.value !is StringLiteralValue) - err("string var can only be initialized with a string literal") } if(compilerOptions.zeropage==ZeropageType.DONTUSE && decl.zeropage==ZeropageWish.REQUIRE_ZEROPAGE) @@ -869,8 +867,15 @@ internal class AstChecker(private val program: Program, errors.err("left operand is not numeric or str", expr.left.position) if(rightDt!in NumericDatatypes && rightDt != DataType.STR) errors.err("right operand is not numeric or str", expr.right.position) - if(leftDt!=rightDt) - errors.err("left and right operands aren't the same type", expr.left.position) + if(leftDt!=rightDt) { + if(leftDt==DataType.STR && rightDt in IntegerDatatypes) { + // only exception allowed: str * constvalue + if(expr.right.constValue(program)!=null) + errors.err("can only use string repeat with a constant number value", expr.left.position) + } else { + errors.err("left and right operands aren't the same type", expr.left.position) + } + } if(expr.operator !in ComparisonOperators) { if (leftDt == DataType.STR && rightDt == DataType.STR || leftDt in ArrayDatatypes && rightDt in ArrayDatatypes) { diff --git a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt index 382bc3bd4..08b762661 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstExtensions.kt @@ -77,17 +77,17 @@ internal fun Program.verifyFunctionArgTypes() { fixer.visit(this) } -internal fun Program.preprocessAst(program: Program, errors: IErrorReporter) { - val transforms = AstPreprocessor(program, errors) +internal fun Program.preprocessAst(errors: IErrorReporter) { + val transforms = AstPreprocessor(this, errors) transforms.visit(this) var mods = transforms.applyModifications() while(mods>0) mods = transforms.applyModifications() } -internal fun Program.checkIdentifiers(errors: IErrorReporter, program: Program, options: CompilationOptions) { +internal fun Program.checkIdentifiers(errors: IErrorReporter, options: CompilationOptions) { - val checker2 = AstIdentifiersChecker(errors, program, options.compTarget) + val checker2 = AstIdentifiersChecker(errors, this, options.compTarget) checker2.visit(this) if(errors.noErrors()) { @@ -101,8 +101,8 @@ internal fun Program.checkIdentifiers(errors: IErrorReporter, program: Program, } } -internal fun Program.variousCleanups(program: Program, errors: IErrorReporter, options: CompilationOptions) { - val process = VariousCleanups(program, errors, options) +internal fun Program.variousCleanups(errors: IErrorReporter, options: CompilationOptions) { + val process = VariousCleanups(this, errors, options) process.visit(this) if(errors.noErrors()) process.applyModifications() diff --git a/docs/source/programming.rst b/docs/source/programming.rst index cc99f3752..4d5f1abd4 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -341,7 +341,7 @@ It can be correctly displayed on the screen only if a iso-8859-15 charset has be You can concatenate two string literals using '+', which can be useful to split long strings over separate lines. But remember that the length of the total string still cannot exceed 255 characaters. -A string literal can also be repeated a given number of times using '*'. +A string literal can also be repeated a given number of times using '*', where the repeat number must be a constant value. And a new string value can be assigned to another string, but no bounds check is done so be sure the destination string is large enough to contain the new value (it is overwritten in memory):: diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 4497efb4b..9433e9e0a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,7 @@ TODO For next release ^^^^^^^^^^^^^^^^ -- allow "xxx" * constexpr (where constexpr is not a number literal, now gives expression error not same type) -- is * lower prio than bitwise & ? fix prios if so! +... Need help with @@ -22,6 +21,7 @@ Blocked by an official Commander-x16 r39 release Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ +- allow "xxx" * constexpr (where constexpr is not a number literal, now gives expression error not same type) - can we promise a left-to-right function call argument evaluation? without sacrificing performance - unify FunctioncallExpression + FunctioncallStatement and PipeExpression + Pipe statement, may require moving Expression/Statement into interfaces instead of abstract base classes - for the pipe operator: recognise a placeholder (``?`` or ``%`` or ``_``) in a non-unary function call to allow things as ``4 |> mkword(?, $44) |> print_uw``