feat(ffi-linkage): add kw_extern/kw_export tokens (Phase 0.0)

Lex 'extern' and 'export' as keywords beside 'callconv': new token.Tag
variants + keywords StaticStringMap entries + LSP semantic-token keyword
classification. Adds a 'lex linkage keywords' unit test.

Tokens only — parser/AST plumbing and lowering land in later phases.
Corpus sweep confirmed no .sx identifier collides with the new reserved
words. lock commit per the cadence rule.
This commit is contained in:
agra
2026-06-14 12:40:35 +03:00
parent 78f7bb7857
commit bf6ef8370f
4 changed files with 32 additions and 6 deletions

View File

@@ -5,8 +5,13 @@ 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
None — plan authored, not yet started. (Merged the former EXTERN-EXPORT +
FOREIGN-MIGRATION plans into this single plan.)
**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).
## Current state
Syntax decided + ratified: bare `extern`/`export`, postfix in the `callconv(.c)`
@@ -15,12 +20,15 @@ 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). No code written.
the live tree (Phase 9.4 gate). Tokens exist (0.0); parser/AST not yet plumbed.
## Next step
**Phase 0.0** — add `kw_extern`/`kw_export` tokens + keyword-map entries (beside
`kw_callconv`) + unit lex test. Then 0.1 (parser plumbing, unconsumed), then Phase 1
(`extern` working). See the plan's **"Kickoff prompt"** section.
**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.
## Open decisions
Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B (confirm
@@ -30,6 +38,9 @@ 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.
## Known issues
None yet.