test(ffi-linkage): xfail example for extern fn binding (Phase 1.0b)
Add examples/1223-ffi-extern-fn.sx — binds libc 'abs' via bare 'extern'
(sx name = C symbol, no rename). Hand-authored expected/ captures the
SUCCESS output (abs(-7)=7 / abs(42)=42, exit 0).
RED: 1223 is the sole corpus failure (634 ran, 1 failed) — it parses
then errors at sema ('body produces no value') because lowering does
not yet route extern fns through declareExtern. Phase 1.1 wires the
lowering and turns this green.
xfail commit per the cadence rule (no commit both adds a test and makes
it pass).
This commit is contained in:
@@ -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.
|
||||
|
||||
14
examples/1223-ffi-extern-fn.sx
Normal file
14
examples/1223-ffi-extern-fn.sx
Normal file
@@ -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
|
||||
}
|
||||
1
examples/expected/1223-ffi-extern-fn.exit
Normal file
1
examples/expected/1223-ffi-extern-fn.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/1223-ffi-extern-fn.stderr
Normal file
1
examples/expected/1223-ffi-extern-fn.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/expected/1223-ffi-extern-fn.stdout
Normal file
2
examples/expected/1223-ffi-extern-fn.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
abs(-7) = 7
|
||||
abs(42) = 42
|
||||
Reference in New Issue
Block a user