diff --git a/compiler/res/prog8lib/compression.p8 b/compiler/res/prog8lib/compression.p8 index 195bc2885..351ed8e27 100644 --- a/compiler/res/prog8lib/compression.p8 +++ b/compiler/res/prog8lib/compression.p8 @@ -2,6 +2,8 @@ compression { + %option no_symbol_prefixing, ignore_unused + sub encode_rle_outfunc(uword data, uword size, uword output_function, bool is_last_block) { ; -- Compress the given data block using ByteRun1 aka PackBits RLE encoding. ; output_function = address of a routine that gets a byte arg in A, diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 28eac8902..c80b92bbe 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -550,10 +550,8 @@ internal class AstChecker(private val program: Program, fun checkType(target: AssignTarget, value: Expression, augmentable: Boolean) { val targetDt = target.inferType(program) val valueDt = value.inferType(program) - if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) { - if(targetDt.isIterable) - errors.err("cannot assign value to string or array", value.position) - else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) { + if(valueDt.isKnown && !(valueDt isAssignableTo targetDt) && !targetDt.isIterable) { + if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) { if(targetDt.isUnknown) { if(target.identifier?.targetStatement(program)!=null) errors.err("target datatype is unknown", target.position) @@ -1844,6 +1842,12 @@ internal class AstChecker(private val program: Program, else if(targetDatatype==DataType.BOOL && sourceDatatype!=DataType.BOOL) { errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) } + else if(targetDatatype==DataType.STR) { + if(sourceDatatype==DataType.UWORD) + errors.err("can't assign UWORD to STR. If the source is a string and you actually want to overwrite the target string, use an explicit string.copy(src,tgt) instead.", position) + else + errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) + } else { errors.err("type of value $sourceDatatype doesn't match target $targetDatatype", position) } diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 7e8b61441..cb10623ef 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -210,15 +210,11 @@ internal class StatementReorderer( val targetType = assignment.target.inferType(program) if(targetType.isArray && valueType.isArray) { - if (assignment.value is ArrayLiteral) { - errors.err("cannot assign array literal here, use separate assignment per element", assignment.position) - } else { - return copyArrayValue(assignment) - } + checkCopyArrayValue(assignment) } if(!assignment.isAugmentable) { - if (valueType.isString && (targetType istype DataType.STR || targetType istype DataType.ARRAY_B || targetType istype DataType.ARRAY_UB)) { + if (valueType istype DataType.STR && targetType istype DataType.STR) { // replace string assignment by a call to stringcopy return copyStringValue(assignment) } @@ -247,18 +243,22 @@ internal class StatementReorderer( return noModifications } - private fun copyArrayValue(assign: Assignment): List { + private fun checkCopyArrayValue(assign: Assignment) { val identifier = assign.target.identifier!! val targetVar = identifier.targetVarDecl(program)!! if(targetVar.arraysize==null) { errors.err("array has no defined size", assign.position) - return noModifications + return + } + + if(assign.value is ArrayLiteral) { + return // invalid assignment of literals will be reported elsewhere } if(assign.value !is IdentifierReference) { errors.err("invalid array value to assign to other array", assign.value.position) - return noModifications + return } val sourceIdent = assign.value as IdentifierReference val sourceVar = sourceIdent.targetVarDecl(program)!! @@ -273,7 +273,6 @@ internal class StatementReorderer( errors.err("element size mismatch", assign.position) } } - return noModifications } private fun copyStringValue(assign: Assignment): List { diff --git a/docs/source/programming.rst b/docs/source/programming.rst index 880dd08f0..ec049e9f0 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -286,8 +286,7 @@ Arrays ^^^^^^ Array types are also supported. They can be formed from a list of booleans, bytes, words, floats, or addresses of other variables (such as explicit address-of expressions, strings, or other array variables) - values in an array literal -always have to be constants. Putting variables inside an array has to be done on a value-by-value basis. -Here are some examples of arrays:: +always have to be constants. Here are some examples of arrays:: byte[10] array ; array of 10 bytes, initially set to 0 byte[] array = [1, 2, 3, 4] ; initialize the array, size taken from value @@ -300,6 +299,7 @@ Here are some examples of arrays:: value = array[3] ; the fourth value in the array (index is 0-based) char = string[4] ; the fifth character (=byte) in the string char = string[-2] ; the second-to-last character in the string (Python-style indexing from the end) + flags = [false, true] ; reset all flags in the array .. note:: Right now, the array should be small enough to be indexable by a single byte index. @@ -312,9 +312,8 @@ Note that the various keywords for the data type and variable type (``byte``, `` can't be used as *identifiers* elsewhere. You can't make a variable, block or subroutine with the name ``byte`` for instance. - -It's possible to assign a new array to another array, this will overwrite all elements in the original -array with those in the value array. The number and types of elements have to match. +It's possible to assign an array to another array; this will overwrite all elements in the target +array with those in the source array. The number and types of elements have to match for this to work! For large arrays this is a slow operation because every element is copied over. It should probably be avoided. Using the ``in`` operator you can easily check if a value is present in an array, @@ -650,10 +649,6 @@ Assignment statements assign a single value to a target variable or memory locat Augmented assignments (such as ``aa += xx``) are also available, but these are just shorthands for normal assignments (``aa = aa + xx``). -Only variables of type byte, word and float can be assigned a new value. -It's not possible to set a new value to string or array variables etc, because they get allocated -a fixed amount of memory which will not change. (You *can* change the value of elements in a string or array though). - It is possible to "chain" assignments: ``x = y = z = 42``, this is just a shorthand for the three individual assignments with the same value 42. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index fd2117481..00249f05a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,12 @@ TODO ==== +Don't allow assigning str to array! +Don't allow assigning array to str! +Don't allow assigning a word to an array or string! + +Put palette fade to white / black in. + Regenerate skeleton doc files. Improve register load order in subroutine call args assignments: @@ -12,6 +18,7 @@ Maybe this routine can be made more intelligent. See usesOtherRegistersWhileEva Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ +- The string assignment footgun should be removed in favor of just calling string.copy explicitly. Get rid of sys.internal_stringcopy asm routine. Fix docs too. - Improve the SublimeText syntax file for prog8, you can also install this for 'bat': https://github.com/sharkdp/bat?tab=readme-ov-file#adding-new-syntaxes--language-definitions - Can we support signed % (remainder) somehow? - Don't add "random" rts to %asm blocks but instead give a warning about it? (but this breaks existing behavior that others already depend on... command line switch? block directive?) diff --git a/examples/test.p8 b/examples/test.p8 index afa348dc7..45293072b 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,46 +1,30 @@ %import textio +%import string %zeropage basicsafe main { sub start() { - routine(11,22,33) - txt.nl() - cx16.r0 = callfar2(0, &routine, 11, 22, 33, true) - txt.nl() - txt.print_uwhex(cx16.r0, true) - txt.nl() - cx16.r0 = callfar(0, &routine, 11*256 + 22) - txt.nl() - txt.print_uwhex(cx16.r0, true) - txt.nl() - } + str name1 = "irmen" + str name2 = "other" + bool[2] flags = [true, false] - asmsub routine(ubyte v1 @A, ubyte v2 @X, ubyte v3 @Y) -> uword @AY { - %asm {{ - sta cx16.r8L - stx cx16.r9L - sty cx16.r10L - lda #0 - rol a - sta cx16.r11L + txt.print(name1) + txt.nl() + name1 = name2 + txt.print(name1) + txt.nl() + flags = [false, true] - lda cx16.r8L - jsr txt.print_ub - lda #' ' - jsr txt.chrout - lda cx16.r9L - jsr txt.print_ub - lda #' ' - jsr txt.chrout - lda cx16.r10L - jsr txt.print_ub - lda #' ' - jsr txt.chrout - lda cx16.r11L - jsr txt.print_ub - lda #$31 - ldy #$ea - rts - }} + ubyte[10] array + ubyte[10] array2 + + void string.copy(name2, name1) + array = array2 + name2 = "zzz" + array = [1,2,3,4,5,6,7,8,9,10] + ;; array = cx16.r0 + ;; array = name1 + ;; name1 = array + ;; name1 = cx16.r0 } }