refactor(ffi-linkage): Phase 7.1 — migrate incidental 12xx ffi examples #foreign→extern

12 plain-C examples that use #foreign incidentally (as FFI plumbing, output
unchanged): 1200/1206/1209-1215/1220/1221/1222. Blanket keyword swap; all fn/global
markers (no class forms in 12xx). Empty snapshot diff; corpus validates directly
(all marker'd). Suite green (647 corpus / 444 unit, 0 failed).

KEPT on #foreign (deferred to Phase 8 cutover): identity-#foreign feature tests
(filename ffi-foreign-*: 1205/1207/1216/1218/1219), the equivalence test 1228, and
the diagnostics that assert on #foreign source/message (1172/1174/1620). Comment-only
provenance prose (1223/1229/1230/1231) left intact per Decision-6-recommended.
This commit is contained in:
agra
2026-06-15 06:49:36 +03:00
parent d3425fa287
commit 731fb8de64
12 changed files with 47 additions and 47 deletions

View File

@@ -1,5 +1,5 @@
// `callconv(.c)` on function pointers passed to foreign callbacks — ensures
// the function uses C ABI so it can be safely invoked from `#foreign`
// the function uses C ABI so it can be safely invoked from `extern`
// functions like SDL_AddEventWatch.
#import "modules/std.sx";

View File

@@ -1,4 +1,4 @@
// 16-byte integer-only struct passed by value through `#foreign`.
// 16-byte integer-only struct passed by value through `extern`.
//
// emit_llvm.zig's `abiCoerceParamType` routes 9..16-byte non-HFA
// structs through `[2 x i64]` for register-pair passing on AAPCS64 /
@@ -22,7 +22,7 @@
Pair64 :: struct { a: i64; b: i64; }
ffi_pair64_swap :: (p: Pair64) -> Pair64 #foreign;
ffi_pair64_swap :: (p: Pair64) -> Pair64 extern;
main :: () -> i32 {
p : Pair64 = .{ a = 1, b = 2 };

View File

@@ -1,5 +1,5 @@
// Phase 0 baseline (PLAN-FFI.md step 0.1): every primitive type passed
// in/out of a C `#foreign` fn via `#import c { #include / #source }`.
// in/out of a C `extern` fn via `#import c { #include / #source }`.
// Locks today's parameter + return ABI so Phase 1's lowering changes
// (`#objc_call` / `#jni_call`) can't silently regress us.
//

View File

@@ -1,5 +1,5 @@
// Phase 0 baseline (PLAN-FFI.md step 0.2): small structs (≤16 bytes)
// passed by value into a C `#foreign` fn and returned by value. Four
// passed by value into a C `extern` fn and returned by value. Four
// shapes that exercise distinct aggregate ABI paths:
// Vec2 — 8 B, two f32 (register pair, float)
// Vec4f — 16 B, four f32 (HFA — homogeneous float aggregate)
@@ -15,7 +15,7 @@
// `#source` only — c_import would rewrite struct-typed params/returns
// in the .h to *void (its struct/opaque pointer default), losing the
// by-value ABI. The hand-written #foreign decls below keep sx's
// by-value ABI. The hand-written extern decls below keep sx's
// struct types end-to-end.
#import c {
#source "1210-ffi-02-small-struct.c";
@@ -26,21 +26,21 @@ Vec4f :: struct { x: f32; y: f32; z: f32; w: f32; }
Pair64 :: struct { a: i64; b: i64; }
Quad32 :: struct { a: i32; b: i32; c: i32; d: i32; }
ffi_vec2_make :: (x: f32, y: f32) -> Vec2 #foreign;
ffi_vec2_swap :: (v: Vec2) -> Vec2 #foreign;
ffi_vec2_sum :: (v: Vec2) -> f32 #foreign;
ffi_vec2_make :: (x: f32, y: f32) -> Vec2 extern;
ffi_vec2_swap :: (v: Vec2) -> Vec2 extern;
ffi_vec2_sum :: (v: Vec2) -> f32 extern;
ffi_vec4f_make :: (x: f32, y: f32, z: f32, w: f32) -> Vec4f #foreign;
ffi_vec4f_reverse :: (v: Vec4f) -> Vec4f #foreign;
ffi_vec4f_sum :: (v: Vec4f) -> f32 #foreign;
ffi_vec4f_make :: (x: f32, y: f32, z: f32, w: f32) -> Vec4f extern;
ffi_vec4f_reverse :: (v: Vec4f) -> Vec4f extern;
ffi_vec4f_sum :: (v: Vec4f) -> f32 extern;
ffi_pair64_make :: (a: i64, b: i64) -> Pair64 #foreign;
ffi_pair64_swap :: (p: Pair64) -> Pair64 #foreign;
ffi_pair64_sum :: (p: Pair64) -> i64 #foreign;
ffi_pair64_make :: (a: i64, b: i64) -> Pair64 extern;
ffi_pair64_swap :: (p: Pair64) -> Pair64 extern;
ffi_pair64_sum :: (p: Pair64) -> i64 extern;
ffi_quad32_make :: (a: i32, b: i32, c: i32, d: i32) -> Quad32 #foreign;
ffi_quad32_reverse :: (q: Quad32) -> Quad32 #foreign;
ffi_quad32_sum :: (q: Quad32) -> i32 #foreign;
ffi_quad32_make :: (a: i32, b: i32, c: i32, d: i32) -> Quad32 extern;
ffi_quad32_reverse :: (q: Quad32) -> Quad32 extern;
ffi_quad32_sum :: (q: Quad32) -> i32 extern;
main :: () -> i32 {
// ── Vec2 (8 bytes, float pair) ─────────────────────────────────

View File

@@ -1,5 +1,5 @@
// Phase 0 baseline (PLAN-FFI.md step 0.3): structs >16 bytes passed
// by value into a C `#foreign` fn and returned by value. Exercises
// by value into a C `extern` fn and returned by value. Exercises
// the byval-pointer ABI path — the caller copies the struct onto its
// stack and hands a pointer to the callee; on AAPCS64 the return
// uses the indirect `x8` register; on SysV AMD64 the return is a
@@ -25,14 +25,14 @@ Big48 :: struct {
d: i64; e: i64; f: i64;
}
ffi_big24_make :: (a: i64, b: i64, c: i64) -> Big24 #foreign;
ffi_big24_rotate :: (v: Big24) -> Big24 #foreign;
ffi_big24_sum :: (v: Big24) -> i64 #foreign;
ffi_big24_make :: (a: i64, b: i64, c: i64) -> Big24 extern;
ffi_big24_rotate :: (v: Big24) -> Big24 extern;
ffi_big24_sum :: (v: Big24) -> i64 extern;
ffi_big48_make :: (a: i64, b: i64, c: i64,
d: i64, e: i64, f: i64) -> Big48 #foreign;
ffi_big48_reverse :: (v: Big48) -> Big48 #foreign;
ffi_big48_sum :: (v: Big48) -> i64 #foreign;
d: i64, e: i64, f: i64) -> Big48 extern;
ffi_big48_reverse :: (v: Big48) -> Big48 extern;
ffi_big48_sum :: (v: Big48) -> i64 extern;
main :: () -> i32 {
// ── Big24 (24 bytes, byval pointer) ────────────────────────────

View File

@@ -22,13 +22,13 @@
FQuad :: struct { a: f32; b: f32; c: f32; d: f32; }
DQuad :: struct { a: f64; b: f64; c: f64; d: f64; }
ffi_fquad_make :: (a: f32, b: f32, c: f32, d: f32) -> FQuad #foreign;
ffi_fquad_reverse :: (v: FQuad) -> FQuad #foreign;
ffi_fquad_sum :: (v: FQuad) -> f32 #foreign;
ffi_fquad_make :: (a: f32, b: f32, c: f32, d: f32) -> FQuad extern;
ffi_fquad_reverse :: (v: FQuad) -> FQuad extern;
ffi_fquad_sum :: (v: FQuad) -> f32 extern;
ffi_dquad_make :: (a: f64, b: f64, c: f64, d: f64) -> DQuad #foreign;
ffi_dquad_reverse :: (v: DQuad) -> DQuad #foreign;
ffi_dquad_sum :: (v: DQuad) -> f64 #foreign;
ffi_dquad_make :: (a: f64, b: f64, c: f64, d: f64) -> DQuad extern;
ffi_dquad_reverse :: (v: DQuad) -> DQuad extern;
ffi_dquad_sum :: (v: DQuad) -> f64 extern;
main :: () -> i32 {
// ── FQuad (16 B, 4×f32 HFA) ────────────────────────────────────

View File

@@ -14,11 +14,11 @@
#source "1213-ffi-05-string-args.c";
};
ffi_strlen :: (s: [:0]u8) -> i32 #foreign;
ffi_first_byte :: (s: [:0]u8) -> i32 #foreign;
ffi_sum_bytes :: (buf: [*]u8, len: i32) -> i32 #foreign;
ffi_write_byte :: (buf: [*]u8, idx: i32, v: u8) -> void #foreign;
ffi_static_greeting :: () -> [*]u8 #foreign;
ffi_strlen :: (s: [:0]u8) -> i32 extern;
ffi_first_byte :: (s: [:0]u8) -> i32 extern;
ffi_sum_bytes :: (buf: [*]u8, len: i32) -> i32 extern;
ffi_write_byte :: (buf: [*]u8, idx: i32, v: u8) -> void extern;
ffi_static_greeting :: () -> [*]u8 extern;
main :: () -> i32 {
// ── [:0]u8 null-terminated literal ─────────────────────────────

View File

@@ -16,8 +16,8 @@
#source "1214-ffi-06-callback.c";
};
ffi_apply_callback :: (cb: (i32) -> i32 callconv(.c), value: i32) -> i32 #foreign;
ffi_apply_callback2 :: (cb: (*void, i32) -> i32 callconv(.c), ctx: *void, v: i32) -> i32 #foreign;
ffi_apply_callback :: (cb: (i32) -> i32 callconv(.c), value: i32) -> i32 extern;
ffi_apply_callback2 :: (cb: (*void, i32) -> i32 callconv(.c), ctx: *void, v: i32) -> i32 extern;
g_callback_hits : i32 = 0;
g_callback_sum : i32 = 0;

View File

@@ -6,7 +6,7 @@
// search branch (`<exe>/../../library` etc.), not by the CWD or
// importing-file's-dir branches.
//
// `#include` triggers c_import.zig's auto-synthesis of `#foreign`
// `#include` triggers c_import.zig's auto-synthesis of `extern`
// fn decls from the C header; `#source` adds the .c to the build's
// object list. Together they let the sx side call the C functions
// by their declared names with no manual decls.

View File

@@ -1,6 +1,6 @@
// `#import c` foreign-name exemption: C names that collide with sx's reserved
// type spellings import unedited. Foreign decls are treated as RAW — their names
// are never type-classified nor reserved-checked — so the generated `#foreign`
// are never type-classified nor reserved-checked — so the generated `extern`
// bindings import and call without hand-edits (no backticks needed). This covers
// parameter names (`i1`/`i2`), a function whose own NAME is a reserved spelling
// (`i2`), and bare-calling that function (its callee spelling parses as a type

View File

@@ -6,9 +6,9 @@
#import "modules/std.sx";
libc :: #library "c";
err_text :: (code: i32) -> [:0]u8 #foreign libc "strerror";
sig_text :: (sig: i32) -> ?[:0]u8 #foreign libc "strsignal";
dlerror :: () -> ?[:0]u8 #foreign libc;
err_text :: (code: i32) -> [:0]u8 extern libc "strerror";
sig_text :: (sig: i32) -> ?[:0]u8 extern libc "strsignal";
dlerror :: () -> ?[:0]u8 extern libc;
main :: () -> i32 {
// plain: strerror(0) = "Undefined error: 0" on macOS — assert shape,

View File

@@ -1,14 +1,14 @@
// The `cstring` type: ONE pointer to a null-terminated u8 buffer — C's
// `char *`. Crosses #foreign boundaries verbatim in both directions;
// `char *`. Crosses extern boundaries verbatim in both directions;
// `?cstring` is the nullable case (null pointer = absent); string
// LITERALS coerce implicitly (terminated constants); arbitrary strings
// materialize via to_cstring; from_cstring is the zero-copy view back.
#import "modules/std.sx";
libc :: #library "c";
strerror_c :: (code: i32) -> cstring #foreign libc "strerror";
getenv_c :: (name: cstring) -> ?cstring #foreign libc "getenv";
dlerror_c :: () -> ?cstring #foreign libc "dlerror";
strerror_c :: (code: i32) -> cstring extern libc "strerror";
getenv_c :: (name: cstring) -> ?cstring extern libc "getenv";
dlerror_c :: () -> ?cstring extern libc "dlerror";
main :: () -> i32 {
// literal -> cstring param; cstring return -> view