Files
sx/current/CHECKPOINT-EXTERN-EXPORT.md
agra 62a3b46f6e 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.
2026-06-14 12:48:56 +03:00

3.0 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 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.