blaise/runtime
Graeme Geldenhuys 07aac3322f feat(string): writable string subscript S[i] := ch with copy-on-write
S[I] := <byte> was rejected by the semantic pass ('is not a static array
or dynamic array') for any string — local, global, or var-param — on both
backends.  It is now supported as the symmetric counterpart of the S[I]
read: an in-place byte store into a 0-based UTF-8 string.

Because strings are reference-counted and literals are immortal (stored in
read-only memory; the native backend put them in .rodata, so a naive store
segfaulted, while QBE silently mutated the shared literal), the write
performs copy-on-write.  New RTL helper _StringUnique(S) returns S when it
is uniquely owned (rc=1) and otherwise allocates a fresh rc=1 copy, releases
the old reference, and returns the copy.  Both backends emit
_StringUnique -> write the result back to the slot -> storeb, so the slot
keeps exactly one owned reference and mutating one alias never disturbs
another (Delphi/FPC UniqueString semantics).

The RHS accepts a numeric ordinal, Chr(n), or a single-character literal
(the byte-shaped forms used in place of a Char type).  PChar subscript
writes keep their existing in-place path (raw pointer, no ARC header).

Dual-backend e2e tests (write, copy-on-write aliasing + literal reuse,
var-param) in cp.test.e2e.stringops.  Updates language-rationale.adoc
(writable subscript + COW) and grammar.ebnf (string as a subscript-assign
base).
2026-06-18 15:39:38 +01:00
..
src feat(string): writable string subscript S[i] := ch with copy-on-write 2026-06-18 15:39:38 +01:00
Makefile feat(sets): jumbo sets — set of enum up to 256 members 2026-06-14 23:23:19 +01:00
project.xml refactor: split rtl/ into runtime/ + stdlib/, rename bcl.testing to blaise.testing 2026-05-16 00:51:18 +01:00