Commit Graph

24 Commits

Author SHA1 Message Date
agra
811a280517 refactor(ffi-linkage): Phase 9.3 — purge 'foreign' from comments (src caps + examples + docs)
src/: ~21 capital-Foreign comments the case-sensitive verify grep missed
(Foreign-class→Runtime-class, Foreign path→Runtime path, Foreign decls→Extern decls,
FOREIGN function→extern function) across calls/inst/ffi_objc/jni_descriptor/emit_llvm/
c_import/lower.*/ops. src 'foreign' now = ONLY the hash_foreign token + 4 rejection
messages (9.0-delete targets). examples/*.sx comments → extern/runtime-class (1219
stdout regen; KEPT 1176). docs/inline-asm-design + debugger purged. Comments only —
no build impact. 9.0 ratified: DELETE hash_foreign token next.
2026-06-15 10:52:56 +03:00
agra
dc51c4b5bf refactor(ffi-linkage): Phase 9.3-src — purge 'foreign' from src/ comments + a user-facing diagnostic
Reword every 'foreign' comment to the extern/runtime-class vocabulary matching the
renamed identifiers (foreign call→extern call, foreign class→runtime class, foreign
path→runtime path, the #foreign-literal comment mentions → extern, etc.). Also fixes
two USER-FACING issues: the 'expected … #foreign … after type annotation' parse error
no longer advertises the removed keyword, and the Android 'no #jni_main' help
diagnostic now shows '#jni_class(…) extern' instead of the rejected '#foreign
#jni_class'. Removed the now-dead prefix-#foreign-vs-postfix conflict branch in
parseRuntimeClassDecl (the caller rejects #foreign before it runs).

src/ now contains 'foreign' ONLY in the hash_foreign token machinery + its 4
rejection messages — the deprecation mechanism (kept per the 9.0 recommendation; the
message MUST name #foreign to guide migration). Snapshot-neutral; suite green
(646 corpus / 444 unit, 0 failed).
2026-06-15 09:35:00 +03:00
agra
d27be42a93 refactor(ffi-linkage): Phase 9.2c — rename extern-ref validators → Extern (linkage)
checkForeignRefs→checkExternRefs, validateForeignRefs→validateExternRefs,
collectForeignRefTargets→collectExternRefTargets — these police 'extern LIB' library
references (linkage axis), so Extern not Runtime. Snapshot-neutral; suite green.
2026-06-15 09:03:35 +03:00
agra
7ffdc7d2a2 refactor(ffi-linkage): Phase 9.1d — eliminate the foreign_expr AST node
The last linkage-family 'foreign' carrier. Migrated c_import.zig auto-synthesis
(#import c {#include}) to build the extern shape (empty-block body + extern_export
= .extern_) instead of a foreign_expr body — the Phase 5.0 fn-body flip applied to
auto-synth. With nothing left building it, deleted the foreign_expr union variant +
ForeignExpr struct (ast.zig) and every reader: the dead-arm switch cases (sema,
resolver, generic, call, semantic_diagnostics, lsp), the coalescing reads in
decl.zig (is_foreign local, cc/rename/dedup/variadic/visibility gates) + pack.zig,
and checkForeignRefs (now reads extern_lib only). 9.1 LINKAGE PURGE COMPLETE — all
that remains in src/ is the runtime-class family (9.2) + comments. Snapshot-neutral
(the #import c examples 1215/1216/1217 + sqlite 1624 exercise the synth path); suite
green (646 corpus / 444 unit, 0 failed).
2026-06-15 08:54:56 +03:00
agra
ad6aed3d7a fix(ffi-linkage): Phase 5.0 prereq — validate extern LIB refs like #foreign
checkForeignRefs now reads a library reference from either spelling — the
legacy #foreign body (foreign_expr.library_ref) or the new extern keyword
(extern_lib) — and validates both against the declared #library / #import c
units. The diagnostic names the surface keyword the user wrote (#foreign vs
extern), so example 1620 (#foreign) is byte-unchanged and example 1231
(extern) gets the parallel 'extern library ... not declared'. Greens 1231.

647 corpus / 444 unit, 0 failed.
2026-06-15 03:53:03 +03:00
agra
9fb7290861 feat: duplicate C exports across #import c units are a compile diagnostic
All units share one link namespace (per-unit isolation is PLAN-C C3.2,
deferred), so a symbol defined by two units previously died inside the
JIT dylib link or the AOT link with raw linker spew. The clang shim
gains sx_clang_object_exported_symbols (llvm::object scan: defined +
global, format-specific excluded) and compileCToObjects cross-checks
every unit object — collisions name both source files. Scan failures
are non-fatal; the linker remains the backstop. Covers JIT and native
AOT; the emcc path still relies on wasm-ld's own error.
2026-06-12 19:01:43 +03:00
agra
6114b51073 feat: emcc C compiles go through the object cache
compileCWithEmcc now probes/saves .sx-cache/c-<key>.o with the same
content key as the native path (source + declared headers + transitive
deps + defines/flags/incdirs), keyed by the emcc --version line and the
wasm triple so emsdk upgrades and wasm32/64 variants never collide with
each other or with native objects. Cache hits hand the linker the cache
path directly. objectMagicOk accepts the wasm magic. Verified: warm
wasm build of a c-unit drops 1.85s -> 0.61s (emcc -c skipped).
2026-06-12 18:52:43 +03:00
agra
4b9324e585 feat: transitive quoted includes participate in the c-object cache key
The key previously covered the #source bytes + the block's DECLARED
headers, so a unit whose impl is a thin wrapper over an undeclared
header (vendors/kb_text_shape: two-line impl.c, all code in
kb/kb_text_shape.h) would serve STALE cached objects after an
upstream upgrade. collectIncludeDepBytes now walks the transitive
closure of quoted #include lines (includer-dir first, then -I dirs;
angle/system includes never participate; unresolvable names skip) and
the dep contents fold into the key — no sidecar, no compare logic, a
changed header is just a different key. Verified live: appending to
kb_text_shape.h mints a new cache entry; reverting hits the old one.
2026-06-12 18:48:56 +03:00
agra
8dedacb23f fix(C4): dedup c-import units by normalized content, not node identity
One module imported through several aliased chains materializes one
c_import_decl copy per chain, each carrying a differently-spelled
relative path to the same file (src/app/../repo/../db/../../vendor/x.c
vs src/db/../../vendor/x.c). Dedup now keys on lexically-normalized
sources/includes + defines + flags, so the unit compiles and links
exactly once — pointer-identity dedup linked it once per chain and
died with duplicate symbols at AOT link.
2026-06-12 17:27:06 +03:00
agra
e9b500a232 fix(C4): collectCImportSources recurses into nested namespaces
A named #import c unit declared inside an aliased module sits two
namespace levels deep in the merged tree; the one-level walk (the
extractLibraries/0130 pattern in c_import form) never collected it,
so the unit silently never compiled and its symbols resolved from
whatever process image carried the same names — surfaced by C4's
sqlite migration, where only the version pin could tell the OS copy
from the vendored one.
2026-06-12 17:16:03 +03:00
agra
1bad29e72e feat(C3.1): #foreign refs are validated — must name a #library or a named #import c unit
validateForeignRefs walks the merged tree (libraries + named c units,
nested namespaces included) and diagnoses any #foreign whose ref names
neither — a typo'd ref previously compiled and resolved silently
through whatever image carried the symbol. Decls synthesized from
#include headers carry no ref and are exempt. Flips the C0.2b pin;
zero collateral across the 608 other examples.
2026-06-12 17:09:07 +03:00
agra
0bd8f3e5ce feat(C2): unit-first JIT symbol resolution — program-owned dylibs beat process images
runJITFromObject now takes priority dylibs (the #import c unit's
linked objects first, then #library deps in declaration order) and
attaches a per-path search generator for each AHEAD of the
process-wide fallback, so a vendored symbol can never lose to a
same-named export of an image the host process happens to carry
(libz via LLVM, libsqlite3 via CoreServices). loadLibrary reports
the name dlopen succeeded on; the c-import handle records its dylib
path; temp link inputs are per-pid so concurrent runs can't clobber
each other. Flips the C0.3 shadowing pin to from_unit: true.
2026-06-12 16:56:35 +03:00
agra
053314b3ea feat(C1.2): persistent content-addressed cache for compiled #source units
compileCToObjects now probes .sx-cache/c-<key>.o before invoking the
embedded clang and writes fresh objects back (per-pid temp + copy, the
main object cache's pattern). Default on for both JIT and AOT — the
temp-compile-and-delete behavior it replaces was strictly worse. A
cached entry must carry an object-file magic (Mach-O/ELF) or it falls
back to a fresh compile; no cache failure can fail a build. Cold/warm
verified via --time: the object compile disappears on the warm run.
2026-06-12 16:48:02 +03:00
agra
10f5a4318d test(C1.1): cSourceCacheKey — content key for compiled #source units
Source bytes, declared-header CONTENT (header edits invalidate),
defines/flags/include dirs in order, LLVM version, and target
triple/sysroot all participate; section tags keep equal strings in
different roles distinct. Pure function + variance property tests;
nothing consumes it yet.
2026-06-12 16:43:42 +03:00
agra
d8076b9333 lang: rename signed integer types sN -> iN
Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.

Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).

Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.

zig build test: 426/426; examples suite: 595/595.
2026-06-12 09:31:53 +03:00
agra
2b8041a828 cleanup: drop resolved-issue citations from src comments
Sweep all src/**.zig comments that cite resolved issues (issue NNNN /
fix-NNNN / KB-N): the invariant or mechanism each comment states is
kept; the historical citation is dropped, per the no-conclusion-comments
rule. Pure-history parentheticals are removed outright. References to
the 16 still-open issues (0030, 0041-0056) are untouched, as are test
NAMES carrying regression provenance (matching the sanctioned
"Regression (issue NNNN)" example-header convention).

Also removes the issues/0019-import-non-transitive-c-scope/ fixture dir
— the issue is superseded and its behavior is covered by
examples/0706-modules-import-non-transitive.sx (the .md writeup stays).
issues/0030's repro .sx stays: that issue is an open feature request.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 16:34:17 +03:00
agra
c0e1a5db82 feat(lang): reserved-name check covers :: const/fn/type decls + scope call rewrite to raw provenance [F0.6]
A bare reserved-type-name `::` declaration was silently accepted, and the
attempt-2 lowerCall rewrite then made a bare `s2 :: (…) {…}` function callable —
bypassing the backtick rule for handwritten sx. The reserved-name binding check
covered `:=` / typed-local / param / captures but NOT the `::` declaration form.

- ast: `ConstDecl`/`FnDecl` carry `is_raw` + `name_span` threaded from the parser
  (parseConstBinding / parseFnDecl, all call sites incl. struct/impl methods).
- semantic_diagnostics: reject a bare reserved spelling at EVERY declaration-name
  site — const, function (incl. struct/impl methods), struct/enum/union/error-set,
  protocol, foreign-class, ufcs alias, namespaced/library/c-import name. Backtick
  (`is_raw`) and the compiler's `#builtin` definition (`string :: []u8 #builtin`)
  are the only exemptions; a value whose node is itself a named decl defers to
  that node's own check.
- c_import: synthesized foreign fn_decls are `is_raw = true`, so a C function
  whose own name collides with a reserved spelling (`int s2(int);`) imports and
  bare-calls unedited.
- lower: scope the `.type_expr`→`.identifier` call rewrite to a callee FnDecl of
  RAW provenance (`is_raw`) — only a backtick / `#import c` foreign fn can carry a
  reserved-name spelling, so a non-raw match never gets rewritten.
- examples: 0153 (positive — backtick `::` const + fn, bare + tick call), 1140
  (negative — bare `::` const + fn rejected).
- docs: specs.md + readme.md state the backtick is required at every binding site
  including `::` const / function / type declarations; issue 0089 banner updated.
2026-06-04 19:16:37 +03:00
agra
0dbdc530ba feat(lang): backtick raw-identifier escape + #import c foreign-name exemption [F0.6]
Reserved type-name spellings (s1, s2, u8, …) can now be used as value
identifiers two ways, resolving issue 0089:

1. Backtick raw identifier: a leading backtick (`s2) lexes to an
   .identifier token carrying a new Token.is_raw flag, with the backtick
   excluded from the text. A raw identifier is never type-classified — the
   parser skips Type.fromName for it — so it is always a value identifier.
   The flag threads to VarDecl.is_raw / Param.is_raw at binding sites, and
   the reserved-type-name check (UnknownTypeChecker) skips raw bindings.
   Because the token tag stays .identifier, the escape works in every
   position (local, global, param, field, fn name, struct member, later
   reference) with no per-site parser change.

2. #import c exemption: c_import.zig synthesizes foreign decls with
   Param.is_raw = true, so generated C param names that collide with
   reserved type names (s1, s2) import unedited.

A bare reserved-name binding in sx still errors (issue 0076 preserved):
the is_raw-gated skip only fires for backtick / foreign names, and a raw
binding's address-of / autoref lowering stays correct because every
occurrence is an .identifier, never a .type_expr.

Tests: examples/0151 (backtick, every position),
examples/1220 (foreign exemption, compiled+run), lexer unit tests.
1119 (bare-binding rejection) stays green. specs.md + readme.md updated.
2026-06-04 17:40:42 +03:00
agra
d8968ae093 android: forward NDK sysroot to embedded clang + skip auto #library/#framework
C imports (stb_image, stb_truetype) compiled via the embedded LLVM
clang library now resolve bionic headers on Android. main.zig auto-
fills target_config.sysroot with the NDK root (mirroring the iOS path
that auto-fills the iOS SDK path); c_import.zig derives the bionic
sysroot inside it and passes `--sysroot <ndk>/toolchains/llvm/prebuilt/<host>/sysroot`
to the embedded clang.

Android link branch in target.zig stops auto-appending entries from the
collected `#library` / `#framework` lists. Most `#library` directives
in the stdlib (`objc.sx`'s `objc :: #library "objc";`, frameworks set
by uikit.sx, etc.) describe Apple-specific intent that's nonsensical on
Android. Users opt into Android-side libs via `opts.add_link_flag(...)`
in build.sx — same shape as how the iOS branch already lists frameworks
in chess's configure_build.

Verified end-to-end: chess game compiles for Android, packages into a
debug-signed APK, installs and launches on Pixel 7 Pro. It crashes in
UIRenderer.init because raw GL calls run before EGL is up — same
architectural gap iOS bridges via the Metal GPU protocol. Next step
is a GLES3 GPU impl or a lazy-init in UIRenderer. 86/86 regression
tests + iOS-sim chess build clean.
2026-05-19 00:36:05 +03:00
agra
e8bd40f710 ios: framework embedding in .app + -F search paths
- `-F <dir>` CLI flag adds Apple framework search paths (parallel to `-L`).
- `TargetConfig.framework_paths` flows into the iOS link line (`-F<dir>`).
- iOS link adds `-Wl,-rpath,@executable_path/Frameworks` so embedded
  frameworks resolve at runtime.
- `createBundle` now takes the framework list; for each one it locates
  `<name>.framework` in the `-F` paths and `cp -R`s it into
  `<bundle>.app/Frameworks/`.
- `c_import.compileCToObjects` forwards `-target`/`-isysroot` to clang so
  `#c_import` works under cross-compile (was using host clang implicitly).
- iOS SDK is auto-discovered once at startup and shared by both the C
  compile and the link paths.
- `SX_DEBUG_LINK=1` prints the resolved link argv.
- `library/modules/sdl3.sx`: drop `#library "SDL3"` — linking is now
  per-target (build.sx handles `-lSDL3` on macOS, `-framework SDL3` on iOS).
2026-05-17 14:38:58 +03:00
agra
69934592d8 c import 2026-03-06 10:46:28 +02:00
agra
bbb5426777 sm 2026-03-02 21:00:55 +02:00
agra
2f4f898d54 asm... 2026-03-02 17:19:41 +02:00
agra
d3e574eae5 import c 2026-02-22 17:24:04 +02:00