Explicit type-casts (Char/Boolean/String and a general TypeName(expr))
- Type: feature
- Status: done
- Resolved: 2026-06-18 (commits a7e8dd4, 9ff4ac1) — Char/Boolean/String casts wired; general TypeName() reinterpret split to a separate future ticket.
- Owner: —
- Opened: 2026-06-18
Motivation
Type-casting in PXX is ad-hoc: the factor parser (parser.inc ~2372) has a
hardcoded allowlist of cast tokens, not a general TypeName(expr) mechanism.
Surveyed 2026-06-18 (surfaced while wiring managed strings on ESP, but
target-independent — same char/shortstring/ansistring typing family as the
literal-concat fold fix):
| Cast | Parses | Notes |
|---|---|---|
Integer/LongWord/Byte/Word/Cardinal |
✓ | collapse to tkInteger_T, passthrough |
Pointer |
✓ | passthrough |
Ord / Chr |
✓ | char<->int passthrough builtins |
PChar(s) |
✓ | inline-string -> const char* adapter |
Char(x) |
✗ | tkChar_T cast not wired -> "expected expression" |
Boolean(x) |
✗ | tkBoolean_T not wired |
String(x) |
✗ | tkString_T not wired |
Not urgent: Boolean and Char are easily worked around today (Ord/Chr,
or arithmetic), and String(x) has little use until external-library interop
grows (PChar->string already works for imports). Filed so the gap is tracked.
Scope
- Add
tkChar_T,tkBoolean_T,tkString_Tto the factor parser's cast cases (mirrortkInteger_T): build anAN_CALLwithASTIVal = -Ord(tk*_T)and the rightASTTk. - Codegen passthrough: add those ids to each backend's type-pun passthrough list
(
Ord/Chr/tkInteger_T/tkLongWord_Talready passthrough on x86-64 line ~1300 and the ESP backends).Char(x)= low-byte (mask/passthrough on the value model),Boolean(x)= passthrough (nonzero semantics already hold),String(x)= char/PChar -> managed string (route to PXXStrFromLit / PCharToString as the existing inline-string store does). - Consider a real general
TypeName(expr)cast (named record/class/pointer reinterpret) instead of the token allowlist — larger, separate sub-task.
Acceptance
Char(i),Boolean(i),String(c)compile on all targets and produce the FPC-equivalent value;make test+make cross-bootstrapstay byte-identical.
Notes
- Additive / target-independent, so byte-identity-safe.
- Related: the ESP literal-string-concat fold (commit e1c9198) and the managed-string typing work — same family of char/string conversions.
Log
- 2026-06-18 — Char(x) + Boolean(x) landed (commit a7e8dd4). Factor-parser
cases tkChar_T/tkBoolean_T → AN_CALL value-pun (result tyChar/tyBoolean);
passthrough id added to all backends (x86-64/i386/aarch64/arm32/riscv32/xtensa).
Test test_cast_char_bool.pas byte-identical to FPC; make test +
cross-bootstrap byte-identical.
String(x) still open: unlike the int/char puns, it must materialise a
string value from an arbitrary expression. The frozen-string model only
builds a string at assignment store sites (
s := cworks); there is no helper turning a Char/ordinal into a string rvalue (PCharToString/PXXStrFromLit cover PChar/literal only). Belongs with the managed-string right-sizing arc ([[project_managed_string_f2_direction]]). GeneralTypeName(expr)reinterpret cast also still open (separate larger sub-task). - 2026-06-18 — String(x) landed (commit 9ff4ac1). Solved the rvalue-
materialisation: new AN_STR_FROM_CHAR node desugars
String(c)(parse time) to a hidden tyString temp +__t := cstore + temp read; IR lowers Left then yields Right (no backend code).String(s)identity = value-pun passthrough (tkString_T added to all six backends). Temp is tyString (matches theStringkeyword, always frozen even under managed mode — a managed temp mismatched on copy). All three table gaps (Char/Boolean/String) now closed; FPC byte-identical; cross-bootstrap byte-identical i386+aarch64+arm32. Resolved. The generalTypeName(expr)named-record/class/pointer reinterpret cast (scope §3) is split out as its own future ticket — the cast token allowlist gap (the actual motivation) is fully closed.