diff --git a/current/CHECKPOINT-EXTERN-EXPORT.md b/current/CHECKPOINT-EXTERN-EXPORT.md index 4cd71ee..b6a033c 100644 --- a/current/CHECKPOINT-EXTERN-EXPORT.md +++ b/current/CHECKPOINT-EXTERN-EXPORT.md @@ -5,18 +5,16 @@ 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 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). +**Phase 1.0b** (xfail — example half of 1.0) — added `examples/1223-ffi-extern-fn.sx` +(extern-binds libc `abs` via bare `extern`; sx name = C symbol, no rename) + +hand-authored `expected/` capturing the SUCCESS output (`abs(-7) = 7` / `abs(42) = +42`, exit 0). **RED**: 1223 is the only corpus failure (634 ran, 1 failed) — it parses +then errors at sema (`body produces no value`) because lowering doesn't route extern +yet. Phase 1.1 turns it green. (Prior: 1.0a (lock, green) wired fn-path extern +parsing — `parseFnDecl` → `parseOptionalExternExport()` → `FnDecl.extern_export`, +`;` body = empty-block placeholder; both lookahead predicates accept +`kw_extern`/`kw_export`; per user feedback added `FnDecl.extern_lib`/`extern_name` + +`VarDecl.extern_lib`, decision 4 REVISED.) ## Current state Syntax: bare `extern`/`export`, postfix after `callconv(.c)`, `extern ⇒ callconv(.c)`. @@ -30,15 +28,15 @@ identifiers in `src/` + 28 doc lines. End-state invariant: **zero `foreign`** (P + 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. +**Phase 1.1** (green, turns 1223 green) — in `decl.zig`, when +`fn_decl.extern_export == .extern_`, route the fn through `declareExtern` (`is_extern`, +`.external` linkage, `callconv(.c)`, no implicit ctx — anchors `decl.zig:1123,387, +2110,2113`) instead of lowering the empty-block placeholder body. Treat the bare +`extern` (no `extern_lib`/`extern_name` yet) like a lib-less `#foreign` import — the +sx name IS the C symbol, resolves against the default-linked libc. Run, then +`-Dupdate-goldens` to finalize 1223's snapshot byte-exact; review diff. Then **1.2** +(green): consume `extern LIB "csym"` rename (`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 @@ -54,6 +52,12 @@ historical carve-out — keep `issues/*.md` provenance, gate the live tree only. - (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. +- (1.0a) Wired fn-path extern parsing (`parseFnDecl` + both lookahead predicates) + + added `FnDecl.extern_lib`/`extern_name` + `VarDecl.extern_lib` per user feedback + (decision 4 revised: extern carries an optional lib axis). Unconsumed by lowering. + Suite green (443/633). `lock` commit. +- (1.0b) Added `examples/1223-ffi-extern-fn.sx` + hand-authored success snapshots. + RED (634 ran, 1 failed — sema `body produces no value`). `xfail` commit; 1.1 greens it. ## Known issues None yet. diff --git a/examples/1223-ffi-extern-fn.sx b/examples/1223-ffi-extern-fn.sx new file mode 100644 index 0000000..a5070f0 --- /dev/null +++ b/examples/1223-ffi-extern-fn.sx @@ -0,0 +1,14 @@ +// extern function binding (FFI-linkage stream, Phase 1): bind libc's `abs` +// directly via the bare `extern` linkage modifier — no `#foreign`, no +// `#library`. `extern` ⇒ external linkage + C ABI + no sx ctx; the symbol +// resolves against the default-linked libc at link time. The sx name `abs` +// IS the C symbol (no rename — the `extern LIB "csym"` forms land in 1.2). +#import "modules/std.sx"; + +abs :: (n: i32) -> i32 extern; + +main :: () -> i32 { + print("abs(-7) = {}\n", abs(xx -7)); + print("abs(42) = {}\n", abs(xx 42)); + 0 +} diff --git a/examples/expected/1223-ffi-extern-fn.exit b/examples/expected/1223-ffi-extern-fn.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/examples/expected/1223-ffi-extern-fn.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/1223-ffi-extern-fn.stderr b/examples/expected/1223-ffi-extern-fn.stderr new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/examples/expected/1223-ffi-extern-fn.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/1223-ffi-extern-fn.stdout b/examples/expected/1223-ffi-extern-fn.stdout new file mode 100644 index 0000000..6e4c6a5 --- /dev/null +++ b/examples/expected/1223-ffi-extern-fn.stdout @@ -0,0 +1,2 @@ +abs(-7) = 7 +abs(42) = 42