Date 2026-09-28 (second save). Suite 122/122; self-hosting
fixpoint OK (bootstrap/fixpoint.sh, image 2,062,392 bytes).
master, tree clean except the user's uncommitted compiler/toto.mod.
Tags this session: v3-unicode-1, v3-unicode-2,
v3-stdlib-conversions, v3-unicode-stdlib-summary (this doc).
Implemented in two increments (docs/summary_unicode.md).
Increment 1 — types, literals, conversions (af09dc6, v3-unicode-1)
UCHAR: 32-bit codepoint 0..1114111 (QBE w), a distinct type
(ClUChar/FUChar), usable in declarations and ARRAY OF UCHAR.U'..' / U".." literals (ustring token). One codepoint → UCHAR
immediate; otherwise a UString descriptor
data $ustrN = { l count, w cp0, … } — which is a V3
length-prefixed array, so a literal is a valid actual for an open
ARRAY OF UCHAR formal.QbeGen.DeclUStr): overlong, surrogate
(D800..DFFF), >10FFFF, truncation → semantic error
234 invalid UTF-8 in U-literal.UCHR, CHR8 (l-domain 0..255 check → trap), UORD.Increment 2 — codec + output (f1bfd76, v3-unicode-2)
runtime/syslib/Utf8 — Decode/Encode (MaxUTF8Length = 4,
MaxCodePoint = 1114111).TextIO.UWriteChar / UWriteString(VAR u: ARRAY OF UCHAR) /
UWriteLn — real UTF-8 on stdout (verified byte-for-byte).Flagged deviations from the locked design
UORD returns INTEGER, not LONGCARD: V3 has no LONGCARD type
name and no 64→32-bit conversion, so a LONGCARD result would be
unusable in codegen; a codepoint fits in 32 bits.UCHR also accepts an integer-family operand (the UCHAR
constructor), so a computed codepoint can be built without a literal.QbeGen.DeclUStr: Stage 1 is gm2-built
and does not know UCHAR, so the compiler cannot import Utf8..ssa is still written when error 234 fires (image gate pending).(2f80422, v3-stdlib-conversions; docs/summary_stdlib-conversions.md.)
Conversions: IntToStr/CardToStr (M2), RealToStr (shim
%.6E), StrToInt/StrToCard (whole-string parse), StrToReal
(shim strtod) — BOOLEAN results.RealIO: WriteReal, WriteRealF(x, width), ReadReal.runtime/syslib/shim.c: m2realstr, m2strreal,
m2writereal(f), m2readreal.Conversions uses BOOLEAN rather than the ISO ConvResults
enumeration (V3 enumeration values in expressions are still 230).
t_unicode.mod (exit 31) — U'é', U'😀', U'€', UCHR, CHR8,
UORD.t_trap_chr8.mod — CHR8(U'😀') aborts (rc 134).t_bad_overlong.mod, t_bad_surrogate.mod, t_bad_utf8big.mod,
t_bad_truncutf.mod — expect error 234 (raw invalid bytes; .LST
output git-ignored).utf8_prog.mod (exit 127) — Utf8 round-trips.utext_prog.mod — TextIO.UWriteString(U"héllo") → stdout héllo.conv_prog.mod (exit 127) — Conversions round-trips.realio_prog.mod (exit 42) — WriteReal→3.500000E+00, reads
1.25.v3-unicode-1 — af09dc6 (types/literals/conversions).v3-unicode-2 — f1bfd76 (codec + UTF-8 output).v3-stdlib-conversions — 2f80422 (Conversions/RealIO).v3-fixpoint, v3-bootstrap,
v3-stdlib-broaden, v3-selfhosting.cd .../m2compiler-V3
./bootstrap/fixpoint.sh # FIXPOINT OK
cd compiler && ./build.sh && ./run_tests.sh # 122/122
UString whole-string assignment to a fixed array
(the count check traps, as it does for CHAR arrays today);
UString =/+/concat.ProgramArgs (shim m2argc/m2arg already exist),
IOChan; ConvResults once enumerations are usable in
expressions.CASE labels; strict
231 def/impl signature checks; suppressing .ssa on error 234.