feat(ffi-linkage): extern/export parser+AST plumbing, unconsumed (Phase 0.1)

Add ast.ExternExportModifier { none, extern_, export_ } beside
CallingConvention; FnDecl.extern_export and VarDecl.is_extern/extern_name
fields (all defaulting to absent); and Parser.parseOptionalExternExport()
mirroring parseOptionalCallConv.

None of this is consumed by a decl path yet — no user-facing behavior
change, corpus diff empty. Two inline parser unit tests pin the helper's
keyword mapping and the field defaults. Phase 1.0 wires the helper into
the fn-decl path. lock commit.
This commit is contained in:
agra
2026-06-14 12:48:56 +03:00
parent bf6ef8370f
commit 62a3b46f6e
3 changed files with 100 additions and 14 deletions

View File

@@ -5,13 +5,14 @@ Companion to `current/PLAN-EXTERN-EXPORT.md` — one merged plan: **Part A** add
every commit, one step at a time per the cadence rule.
## Last completed step
**Phase 0.0** (lock) — added `kw_extern`/`kw_export` to `token.Tag` + the
`keywords` `StaticStringMap` (beside `kw_callconv`, `token.zig:45,282`); classified
both as `ST.keyword` in the LSP `classifyToken` exhaustive switch
(`lsp/server.zig`); added `test "lex linkage keywords"` in `lexer.zig`. Suite green
(441 unit / 633 corpus, 0 fail). `extern`/`export` are now reserved words; corpus
sweep confirmed no `.sx` identifier used either (only comments + the unpinned
`issues/0030-*` repro, which doesn't run in the suite).
**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)`
@@ -20,15 +21,17 @@ slot, `extern ⇒ callconv(.c)`, library separate. Touch-points mapped — token
`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). Tokens exist (0.0); parser/AST not yet plumbed.
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 0.1** (lock) — `parseOptionalExternExport()` (mirror `parseOptionalCallConv`,
`parser.zig:3669`) + `ast.ExternExportModifier` enum + `FnDecl.extern_export` +
`VarDecl.is_extern`/`extern_name` fields; **parsed but not yet consumed**; unit AST
test. Then Phase 1 (`extern` working: 1.0 xfail accept postfix, 1.1 green lower via
`declareExtern`, 1.2 green rename + extern-global). See the plan's **"Kickoff
prompt"**. Stop at end of Phase 1.
**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
@@ -41,6 +44,9 @@ historical carve-out — keep `issues/*.md` provenance, gate the live tree only.
- (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.