Commit Graph

8 Commits

Author SHA1 Message Date
6525e137ae wwi: derive decl-less module's .wwi package leaf from parse-stamped path (#11)
wwi_emit took the .wwi `package` leaf from the first primary decl's module tag;
a fully empty primary module body (zero decls) had none, so the leaf stayed the
literal default "main" and the importer rejected it ("package main does not
match import path <leaf>"). The module identity is only available at parse time
(curmod is overwritten by imported //ww:module sections before emit), so stamp
the primary path onto the N_FILE node (TK_MODULE and TK_MODRESET rp!=NULL sites,
only-if-empty so a bare-reset `package main` root stays "main") and, when the
decl-scan finds no leaf, fall back to that stamped path. Symmetric cstage+
selfhost; both detect scan-miss via the same found-flag so the emitted .wwi
stays byte-identical.

Regression: test/wcc/989_wwileaf_run.c, table-driven over {empty body,
comment-only, nested a.b.c} decl-less shapes, non-vacuity proven.
2026-06-22 21:17:30 +09:00
027f90c572 parse,check,type,wwi: @packed struct attribute, both stages (#51)
Hare/harec @packed struct layout: no inter-field or trailing padding, align =
max field align (NOT forced to 1) — matches harec type_store.c + types.c:621
(packed{u8,u64}=size 9/align 8). Parser consumes inline @packed (loud-rejects
unknown struct attrs, both stages); layout gates padding on !packed; cstage
type_eq enforces packed type-distinctness; the .wwi producer round-trips
"struct @packed {". wwstage sets slotsize=size for packed so its composite-ABI
copy matches cstage byte-for-byte. cstage identity is faithful; wwstage identity
rides the deferred #224 nominal-resolvealias arc (#108). Both stages byte-id;
447 tests pass.
2026-06-19 00:17:49 +09:00
0197dfb9e6 lex,wwi: \u/\U unicode escapes + wide-rune .wwi round-trip, both stages (#50)
Hare-faithful \u (4 hex) / \U (8 hex) escapes; \x/\u/\U share one codepoint
path (ref/hare/hare/lex/lex.ha lex_unicode); string literals UTF-8-encode
multi-byte codepoints (cstage inline utf8enc, wwstage utf8.encoderune). The
.wwi producer rune serializer now emits \u/\U so exported wide-rune defs
round-trip (was a fatal >0xFF). Reject >0x10FFFF and surrogates with Hare-
verbatim error strings. Closes the int-cast spelling divergence (#48 RUNE_MAX).
Both stages byte-identical; 446 tests pass.
2026-06-18 22:47:53 +09:00
24ca570a7e w6c,ww: re-emit ... union-spread marker in .wwi producer (M4 E3, #95)
The N_TTAGGED serializer emitted each variant via wwi_type but never
re-emitted the `...` prefix for TK_ELLIPSIS spread variants, so an
exported `(...inner | str)` round-tripped through .wwi as `(inner | str)`.
The consumer's checker then could not flatten inner's members into the
alias and variadic-assignability rejected bare members — under separate
compilation this broke fmt/log/getopt. Re-emit `...` before the variant
type, both stages; the producer stays purely syntactic (flatten/dedup
remain the consumer's type-store job, per ref/hare/hare/unparse/type.ha:290-300).

Gate: test/wcc/989_wwispread_sep.c — table-driven (2-arm + 3-arm spreads)
x both stages, asserts the marker survives the .wwi, the consumer binds
bare members under --sep (exit 0), and cs==ww .wwi byte-identity.
2026-06-18 09:52:19 +09:00
10d005ef58 wcc/ww: serialize aggregate exported defs as value-less .wwi prototypes (BUG-2, #70)
The .wwi (separate-compile interface) producer could not serialize an
exported def whose initializer is a struct/array literal (N_STRUCTLIT/
N_ARRLIT) — `export def f64info: floatinfo = floatinfo{...}` aborted with
"unhandled const-expr node kind 15". Such a def is a DATA-global per the
#52 model, so its value lives once in the defining package's .o; the
interface needs only the type+symbol. Emit a value-less prototype
`export def X: T;` for aggregate-initializer defs; scalar fold-eligible
defs keep their value (the importer const-folds those). The parser gains
an optional-init arm so the importer can parse the prototype — value-less
`def X: T;` is now legal in any source, symmetric with the existing
bodyless-fn prototype `fn f();` (USER ruling: unconditional; a value-less
def with no defining .o is a loud undefined-symbol error at link, never
silent). Both stages; producer + parser fold into one commit (the
producer's output is unparseable without the parser arm).

M3-tail commit-6 prerequisite #2 (surfaced by the c6 scout). The
aggregate-def-field const-fold boundary is documented inline (#71). Gate
989_sepstructdef_run proves struct+array exported defs sep-build, link,
and run via external DATA refs, cs==ww, with a value-less .wwi.
2026-06-16 18:04:54 +09:00
f69ef9b9da lib/types,wcc/ww: export the limit constants (#48)
lib/types limit consts were bare `def`s, so the .wwi (sep-compile's
interface) correctly omitted them while the flat combined.ww let a
cross-package user (lib/strings splitn → types.I32_MAX) reach the
private def — sep-compile then failed (wwstage `asserttyped: dot
'I32_MAX'`; cstage undefined-ref). Hare exports types::I32_MAX and the
whole limit family (ref/hare/types/limits.ha, arch+x86_64.ha); ww not
exporting them was the divergence.

export the 24 existing limit defs ({I,U}{8,16,32,64}_{MIN,MAX},
INT/UINT/SIZE/UINTPTR_{MIN,MAX}) and the existing RUNE_MIN, and add
exported RUNE_MAX. ww's derived machine-word int/uint/size/uintptr
VALUES are kept verbatim (user-ratified 64-bit-int divergence); fidelity
here is the NAME SET + export-visibility, not the values. RUNE_MAX is
written `0x10ffff: rune` — same codepoint as Hare's '\U0010ffff', forced
because ww's lexer has no \u/\U escape (#50).

Exporting the consts made `w6c -I` walk them and fatal on RUNE_MIN
('\0'): the .wwi const-expr unparser had no N_RUNELIT arm. Add one,
both stages (wwi_rune / wwirune), rendering a \xHH-escaped rune literal
(>0xFF fails loud, #50). Const casts need no arm — the checker folds
them to integer literals before the producer runs. 989_m2wwi_run gains
a types.wwi gate (byte-id + re-parse + asserts export def I32_MAX and
RUNE_MAX reach the interface). byte-id-neutral: a def emits no symbol.
2026-06-15 23:10:35 +09:00
4622556c62 wcc/ww: round-trip @symbol in the .wwi producer (#47)
The M2 .wwi producer rendered an exported fn carrying @symbol("...")
as a bare prototype, dropping the FFI link-symbol binding. A
sep-compiled consumer reading the .wwi then emitted `CALL malloc`
instead of `CALL rt_malloc` for `@symbol("rt_malloc") export fn
malloc`, breaking the bodies-vs-.wwi byte-id and the link. Affects
every package whose closure reaches rt/os.

Emit codegen/link-relevant attributes through a single named
predicate (wwi_attr_relevant / wwiattrrelevant), today true iff the
name is "symbol" — the only such attribute that exists. @align/@offset
are NOT field attributes in ww (the parser parses no field attrs, the
N_TFIELD node has no attr slot); the predicate is named for the class
so they slot in if ww ever grows them (#51). attr is assigned at
exactly one site per stage (parse.c:1351 / decl.ww:168), both inside
parsefn, so only N_FNDECL carries attrs and the fn-decl render path
covers the whole class.

Both stages, byte-identical (rule 10). 989_m2wwi_run synth gate gains
an @symbol fn + a content assertion that the .wwi carries it verbatim.
2026-06-15 22:56:12 +09:00
e8d3d89fef wcc/ww: .wwi export-data producer + check_exported_type (#22 M2)
New `w6c -I <out.wwi>` flag (both stages) writes a re-parseable
ww-prototype rendering of a package's EXPORTED surface. M2 dead-code:
nothing consumes .wwi yet (combined.ww stays the live path); the flag is
off on every existing invocation, so the 990-997 byte-id gates and all
prior tests are unperturbed.

The unparse walks the AST type-expr subtree (N_T* nodes), not the
tinfo Type* (which collapses nominal pkg.Name identity). Deterministic
output: package line, byte-sorted imports, byte-sorted decls — a pure
function of the exported API. cmd/w6c/wwi.c + selfhost/cmd/wcc/wwi.ww
emit byte-identical .wwi (new cross-stage byte-id substrate, rule 10).

check_exported_type (drew) rides the producer entry, flag-gated: an
exported signature naming a non-exported nominal is loud-rejected before
any byte is written, identically on both stages. Ports harec
check.c:4092-4168, recursing the type-AST and gating on the resolved
SK_TYPE sym's decl export flag (Sym.exported is vestigial in both
stages; the predeclared synthetic `nomem` decl carries no source
position and is treated as a builtin leaf — cstage parity).

Two wwstage checker AST-mutations are normalized to cstage's pristine
view for byte-id: the N_TPARAM tuple-element wrapper (unwrapped) and the
variadic `T...`→`[]T` param desugar (peeled).

Gate 989_m2wwi_run: ascii/strings/getopt each produce a .wwi that
re-parses (wwdump -a) and is cs==ww byte-identical; a private-type-leak
fixture is rejected identically by both stages (non-vacuous check).
2026-06-15 20:58:08 +09:00