# 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 0.1** (lock) — added `ast.ExternExportModifier = enum { none, extern_, export_ }` (beside `CallingConvention`), `FnDecl.extern_export` (default `.none`), `VarDecl.is_extern`/`extern_name` (defaults absent), and `parser.parseOptionalExternExport()` (mirrors `parseOptionalCallConv`, just below it at `parser.zig:~3683`). **Helper + fields defined but NOT consumed by any decl path** — no user-facing behavior change, corpus diff empty. Two inline parser unit tests (`parseOptionalExternExport recognizes linkage keywords`, `extern/export AST fields default to absent`). Suite green (443 unit [+2] / 633 corpus, 0 fail). ## Current state Syntax decided + ratified: bare `extern`/`export`, postfix in the `callconv(.c)` slot, `extern ⇒ callconv(.c)`, library separate. Touch-points mapped — 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). Export gap = 4 lowering conditions. Part B `foreign` footprint to purge: 643 lines / ~57 identifiers in `src/` + 28 doc lines. End-state invariant: **zero `foreign`** in the live tree (Phase 9.4 gate). **Phase 0 done**: tokens (0.0) + AST/parser plumbing (0.1) exist, unconsumed. Phase 1 wires `extern` into the fn/global decl paths. ## Next step **Phase 1.0** (xfail) — accept postfix `extern` after the callconv slot in the fn-decl path (`parser.zig:1950`: call `parseOptionalExternExport()`, store on `FnDecl.extern_export`); add `examples/12xx-ffi-extern-fn.sx` that extern-binds a libc symbol — **red** (parses, but lowering not wired yet). Then 1.1 green (lower via `declareExtern`: `is_extern`, `.external`, `callconv(.c)`, no ctx — anchors `decl.zig:1123,387,2110,2113`), 1.2 green (`extern "csym"` rename + 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_export` tokens + keyword-map entries + LSP keyword classification + `lex linkage keywords` test. Suite green; no identifier collisions in the corpus. `lock` commit. - (0.1) Added `ast.ExternExportModifier` + `FnDecl.extern_export` + `VarDecl.is_extern`/`extern_name` + `parseOptionalExternExport()` (unconsumed) + 2 parser unit tests. Suite green (443/633). `lock` commit. ## Known issues None yet.