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.
|
every commit, one step at a time per the cadence rule.
|
||||||
|
|
||||||
## Last completed step
|
## Last completed step
|
||||||
**Phase 1.0a** (lock, green — parse half of 1.0) — the fn-decl path now ACCEPTS
|
**Phase 1.0b** (xfail — example half of 1.0) — added `examples/1223-ffi-extern-fn.sx`
|
||||||
postfix `extern`/`export`. `parseFnDecl` calls `parseOptionalExternExport()` after the
|
(extern-binds libc `abs` via bare `extern`; sx name = C symbol, no rename) +
|
||||||
callconv slot and stores it on `FnDecl.extern_export`; for `extern` the body is `;`
|
hand-authored `expected/` capturing the SUCCESS output (`abs(-7) = 7` / `abs(42) =
|
||||||
(an empty-block placeholder — modifier carries the linkage, no `*_expr` node). Both
|
42`, exit 0). **RED**: 1223 is the only corpus failure (634 ran, 1 failed) — it parses
|
||||||
lookahead predicates (`isFunctionDef` + `hasFnBodyAfterArrow`) now treat
|
then errors at sema (`body produces no value`) because lowering doesn't route extern
|
||||||
`kw_extern`/`kw_export` as fn-body markers (beside `kw_callconv`) so `(...) -> R
|
yet. Phase 1.1 turns it green. (Prior: 1.0a (lock, green) wired fn-path extern
|
||||||
extern;` is recognized as a fn def, not a fn-type const. **Per user feedback (decision
|
parsing — `parseFnDecl` → `parseOptionalExternExport()` → `FnDecl.extern_export`,
|
||||||
4 REVISED):** added `extern_lib`+`extern_name` to `FnDecl` and `extern_lib` to
|
`;` body = empty-block placeholder; both lookahead predicates accept
|
||||||
`VarDecl` (next to `is_extern`/`extern_name`) — the optional `LIB`+`"csym"` axis
|
`kw_extern`/`kw_export`; per user feedback added `FnDecl.extern_lib`/`extern_name` +
|
||||||
mirroring `#foreign LIB "csym"`, so `extern` is a true `#foreign` superset (Gate A→B).
|
`VarDecl.extern_lib`, decision 4 REVISED.)
|
||||||
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).
|
|
||||||
|
|
||||||
## Current state
|
## Current state
|
||||||
Syntax: bare `extern`/`export`, postfix after `callconv(.c)`, `extern ⇒ callconv(.c)`.
|
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.
|
+ lib/name fields (1.0a), all unconsumed. Lowering not yet wired.
|
||||||
|
|
||||||
## Next step
|
## Next step
|
||||||
**Phase 1.0b** (xfail — example half of 1.0) — add `examples/12xx-ffi-extern-fn.sx`
|
**Phase 1.1** (green, turns 1223 green) — in `decl.zig`, when
|
||||||
that extern-binds a libc symbol (`abs`); expected files capture the SUCCESS output, so
|
`fn_decl.extern_export == .extern_`, route the fn through `declareExtern` (`is_extern`,
|
||||||
the example is **red** now (parses, then errors at sema since lowering is unwired).
|
`.external` linkage, `callconv(.c)`, no implicit ctx — anchors `decl.zig:1123,387,
|
||||||
Then **1.1** (green): in `decl.zig`, when `extern_export == .extern_`, route the fn
|
2110,2113`) instead of lowering the empty-block placeholder body. Treat the bare
|
||||||
through `declareExtern` (`is_extern`, `.external`, `callconv(.c)`, no ctx — anchors
|
`extern` (no `extern_lib`/`extern_name` yet) like a lib-less `#foreign` import — the
|
||||||
`decl.zig:1123,387,2110,2113`) instead of lowering the placeholder body → example
|
sx name IS the C symbol, resolves against the default-linked libc. Run, then
|
||||||
green. Then **1.2** (green): `extern LIB "csym"` rename (consume `extern_lib`/
|
`-Dupdate-goldens` to finalize 1223's snapshot byte-exact; review diff. Then **1.2**
|
||||||
`extern_name`) + extern-global `g : T extern;` (`parser.zig:425`). Stop at end of
|
(green): consume `extern LIB "csym"` rename (`extern_lib`/`extern_name`) + extern-global
|
||||||
Phase 1.
|
`g : T extern;` (`parser.zig:425`). Stop at end of Phase 1.
|
||||||
|
|
||||||
## Open decisions
|
## Open decisions
|
||||||
Part A ratified (bare / postfix / `⇒ callconv(.c)` / lib-separate). Part B (confirm
|
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` +
|
- (0.1) Added `ast.ExternExportModifier` + `FnDecl.extern_export` +
|
||||||
`VarDecl.is_extern`/`extern_name` + `parseOptionalExternExport()` (unconsumed) + 2
|
`VarDecl.is_extern`/`extern_name` + `parseOptionalExternExport()` (unconsumed) + 2
|
||||||
parser unit tests. Suite green (443/633). `lock` commit.
|
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
|
## Known issues
|
||||||
None yet.
|
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