parseFnDecl now calls parseOptionalExternExport() after the callconv
slot and stores the modifier on FnDecl.extern_export. For 'extern' the
body is ';' (an empty-block placeholder — the modifier carries the
linkage, no *_expr node, per the naming constraint). Both fn-decl
lookahead predicates (isFunctionDef, hasFnBodyAfterArrow) now treat
kw_extern/kw_export as fn-body markers beside kw_callconv, so
'(...) -> R extern;' is recognized as a fn def rather than a fn-type
const.
Per user feedback, decision 4 ("library separate") is REVISED: extern
carries an optional LIB + "csym" axis mirroring '#foreign LIB "csym"',
so it is a true #foreign superset (Gate A->B requirement — the Part B
migration of 466 #foreign uses across 6 libs must preserve each
symbol's library). Added FnDecl.extern_lib/extern_name and
VarDecl.extern_lib (beside is_extern/extern_name).
All unconsumed by lowering: extern parses, but a fn still errors at
sema (body produces no value). Suite green (443 unit / 633 corpus).
lock commit.
3.5 KiB
sx extern/export + #foreign retirement — Checkpoint (FFI-linkage stream)
Companion to current/PLAN-EXTERN-EXPORT.md — one merged plan: Part A adds
extern/export, Part B migrates #foreign and purges foreign. Update after
every commit, one step at a time per the cadence rule.
Last completed step
Phase 1.0a (lock, green — parse half of 1.0) — the fn-decl path now ACCEPTS
postfix extern/export. parseFnDecl calls parseOptionalExternExport() after the
callconv slot and stores it on FnDecl.extern_export; for extern the body is ;
(an empty-block placeholder — modifier carries the linkage, no *_expr node). Both
lookahead predicates (isFunctionDef + hasFnBodyAfterArrow) now treat
kw_extern/kw_export as fn-body markers (beside kw_callconv) so (...) -> R extern; is recognized as a fn def, not a fn-type const. Per user feedback (decision
4 REVISED): added extern_lib+extern_name to FnDecl and extern_lib to
VarDecl (next to is_extern/extern_name) — the optional LIB+"csym" axis
mirroring #foreign LIB "csym", so extern is a true #foreign superset (Gate A→B).
All unconsumed by lowering — extern parses but a fn still errors at sema
(body produces no value). Suite green (443 unit / 633 corpus, 0 fail).
Current state
Syntax: bare extern/export, postfix after callconv(.c), extern ⇒ callconv(.c).
Decision 4 revised (user 2026-06-14): extern carries an optional LIB+"csym"
axis (extern_lib/extern_name) like #foreign; the #library decl + build-flag
linking stays separate. Touch-points: token token.zig:45,282; parser
1950,3669,316,425,1305; lowering decl.zig:1123,387,2110,2382,2514; IR/emit already
capable (no codegen change). Part B foreign footprint to purge: 643 lines / ~57
identifiers in src/ + 28 doc lines. End-state invariant: zero foreign (Phase
9.4 gate). Done: tokens (0.0) + AST/parser plumbing (0.1) + fn-path extern parsing
- lib/name fields (1.0a), all unconsumed. Lowering not yet wired.
Next step
Phase 1.0b (xfail — example half of 1.0) — add examples/12xx-ffi-extern-fn.sx
that extern-binds a libc symbol (abs); expected files capture the SUCCESS output, so
the example is red now (parses, then errors at sema since lowering is unwired).
Then 1.1 (green): in decl.zig, when extern_export == .extern_, route the fn
through declareExtern (is_extern, .external, callconv(.c), no ctx — anchors
decl.zig:1123,387,2110,2113) instead of lowering the placeholder body → example
green. Then 1.2 (green): extern LIB "csym" rename (consume extern_lib/
extern_name) + extern-global g : T extern; (parser.zig:425). Stop at end of
Phase 1.
Open decisions
Part A ratified (bare / postfix / ⇒ callconv(.c) / lib-separate). Part B (confirm
before Phase 9): runtime-class rename target — Runtime*Class* (recommended);
historical carve-out — keep issues/*.md provenance, gate the live tree only.
Log
- (init) Plan written; FFI-linkage stream opened.
- (merge) Folded FOREIGN-MIGRATION in as Part B; deleted the split plan + checkpoint.
- (0.0) Added
kw_extern/kw_exporttokens + keyword-map entries + LSP keyword classification +lex linkage keywordstest. Suite green; no identifier collisions in the corpus.lockcommit. - (0.1) Added
ast.ExternExportModifier+FnDecl.extern_export+VarDecl.is_extern/extern_name+parseOptionalExternExport()(unconsumed) + 2 parser unit tests. Suite green (443/633).lockcommit.
Known issues
None yet.