package ffi_test; // @symbol FFI codegen observers. Port of the retired native carrier // test/wcc/800_ffi.c; every assertion preserved, two strengthened. // // symbolredirect — @symbol("cout") on a body-less fn redirects the // CALL at the codegen layer: the emitted .s must reference the // external name (`CALL\tcout(SB)`) and must NOT reference the ww-side // ident (`CALL\twriteit(SB)`). The C carrier scraped cstage w6c // stdout only, with no exit-code check; the port compiles via -o on // BOTH frontends, gates the exits, and adds the rule-10 cs==ww // byte-id (residual-carrier-audit.json 800 port note). The inline // source gains an explicit `package main;`: the carrier fed it // through wwtest_fputs, which prepended the clause. // // libcsmoke — lib/c/libc/libc.ww (the real libc binding module, // body-less fns, no TEXT directives) parses+checks+cgens to exit 0; // strengthened from cstage-only to both frontends. Not wired as a // LIBRARY_STANDALONE_SOURCE because this observer owns the claim. import os; import os.exec; import strings; import testenv; import time; fn fail(label: str, why: str) void = { let m: str = strings.concat("ffi FAIL: ", label, " -- ", why, "\n"); os.write(2, m.ptr, m.len: u64); assert(false); }; fn tmo() time.duration = { return (60i64 * (time.second: i64)): time.duration; }; fn runcode(dir: str, name: str, argv: []str) i32 = { let co: testenv.commandout; testenv.runcommand(dir, dir, name, argv, tmo(), &co); if (co.termination != exec.termination.EXIT) { return -1; }; return co.code; }; @test fn symbolredirect() void = { let td: str = testenv.fresh(); let src: str = strings.concat(td, "/ffi.ww"); testenv.writefile(src, strings.concat( "package main;\n", "@symbol(\"cout\") fn writeit(b: *u8, n: u64) i64;\n", "fn main() i32 = { writeit(nil, 0); return 0; };\n")); let comps: []str = ["w6c", "w6c_ww"]; let asms: []str = ["", ""]; let c: i32 = 0; for (c < 2) { let asmf: str = strings.concat(td, "/ffi.", comps[c], ".s"); let av: []str = [testenv.driver(comps[c]), src, "-o", asmf]; if (runcode(td, strings.concat("cc_", comps[c]), av) != 0) { fail("symbolredirect", strings.concat(comps[c], " rejected the @symbol declaration")); }; asms[c] = testenv.readfile(asmf); c += 1; }; if (!testenv.has(asms[0], "CALL\tcout(SB)")) { fail("symbolredirect", "missing CALL cout(SB) in the cstage .s"); }; if (testenv.has(asms[0], "CALL\twriteit(SB)")) { fail("symbolredirect", "call emitted by ident name, not @symbol name"); }; if (!testenv.same(asms[0], asms[1])) { fail("symbolredirect", "cs .s != ww .s (rule 10)"); }; testenv.clean(td); }; @test fn libcsmoke() void = { let td: str = testenv.fresh(); let libc: str = strings.concat(testenv.repo(), "/lib/c/libc/libc.ww"); let comps: []str = ["w6c", "w6c_ww"]; let c: i32 = 0; for (c < 2) { let av: []str = [testenv.driver(comps[c]), libc, "-o", strings.concat(td, "/libc.", comps[c], ".s")]; if (runcode(td, strings.concat("smoke_", comps[c]), av) != 0) { fail("libcsmoke", strings.concat(comps[c], " failed on lib/c/libc/libc.ww")); }; c += 1; }; testenv.clean(td); };