Commit Graph

6 Commits

Author SHA1 Message Date
agra
12bf61a9fc std: restructure step 3 — ffi/ moves, build.sx, math dir spelling, fixtures
- objc.sx, objc_block.sx (from std/) + sdl3/opengl/raylib/stb/stb_truetype/
  wasm vendor bindings (from modules/ root) -> modules/ffi/
- std/uikit.sx deleted: platform/uikit.sx already declares UIApplicationMain
  and imports objc; '#framework "UIKit"' cannot live in a file imported on
  macOS targets (unconditional link directive, UIKit is iOS-only), so the
  three iOS-only examples carry the 3-line glue inline. 1607/1608/1616 also
  un-rotted (dead ns_string -> 'xx "..."' Into conversions, callconv(.c)
  msgSend fn-ptrs) — all three build for ios-sim/ios again.
- math/math.sx -> math/scalar.sx; one spelling '#import "modules/math"'
  everywhere (4 pinned IR snapshots regenerated: dir import adds Vec2/Mat4
  to the type tables).
- compiler.sx -> build.sx (imports, CLAUDE.md bundling table, specs.md).
- testpkg/ + test_c.sx -> tests/fixtures/ (resolve CWD-relative from repo
  root, same as vendors/).
- library-internal imports use full modules/... paths (std.sx tail,
  platform/bundle.sx, fixtures).
2026-06-11 08:37:22 +03:00
agra
59f0aa7716 std: restructure — std/ modules, namespace tail, std/xml.sx
allocators/fs/process/socket/log/trace/test move under modules/std/
(allocators.sx becomes std/mem.sx; the Allocator protocol moves into
the std.sx prelude, impls stay in mem.sx). New std/xml.sx holds
xml_escape as xml.escape. std.sx gains the carried namespace tail —
flat-importing std.sx now also provides mem./xml./log. — with the
remaining modules (fs/process/socket/json/cli/hash/test) deferred from
the tail until the global last-wins maps are fully own-wins (pulling
them into every closure collides bare names corpus-wide; they stay
direct imports: modules/std/fs.sx etc.). log.sx's internal emit
renamed log_emit (it clobbered consumer fns named emit program-wide).
bundle.sx uses xml.escape via the carried alias. Consumer import paths
swept mechanically; .ir snapshots recaptured for the larger std
closure. m3te + game build unchanged.
2026-06-11 06:10:59 +03:00
agra
bdd0e96d78 feat(lang): block value requires no trailing ; (Rust-style)
A block's value is now its last statement ONLY when that statement is a
trailing expression with no `;`. A trailing `;` discards the value,
leaving the block void. This makes value-vs-statement explicit and lets
the compiler reject "this block was supposed to produce a value".

Compiler:
- Parser records `Block.produces_value` (last stmt is a no-`;` trailing
  expression) + `Block.discarded_semi` (the `;` that discarded a value),
  via `expectSemicolonAfter`. A trailing expression before `}` may now
  omit its `;` (previously a parse error). Match-arm and else-arm bodies
  are built value-producing regardless of the arm `;` (arms are exempt —
  the `;` is an arm terminator).
- Lowering: `lowerBlockValue` / the block-expr path / `inferExprType`
  respect `produces_value`. A value-position block that discards its value
  is a hard error (`lowerValueBody` for function bodies; the value-context
  `.block` path for if/else branches, `catch` bodies, value bindings,
  match arms). Pure-failable `-> !` bodies (value rides the error channel)
  and a value-if whose branches are void are handled without false errors.
- `defer`/`onfail` cleanup bodies lower as statements (void), so a
  trailing `;` there is fine.

Migration (behavior-preserving — output unchanged):
- stdlib + ~210 examples: dropped the trailing `;` on value-position last
  expressions. `format` now ends with an explicit `#insert "return
  result;"` (it relied on `#insert`-as-block-value, which `;` discards).
- Two `main :: () -> s32` examples that relied on the old silent
  default-return got an explicit trailing `0`.
- Rejection snapshots 0412 / 1013 regenerated (their quoted source lines
  lost a `;`); the diagnostics themselves are unchanged.

Docs/tests: specs.md "Block values" section; examples 0040 (rules) + 0041
(rejection); 3 parser unit tests. Filed issue 0066 (pre-existing
match-arm negated-literal phi-width quirk, surfaced not caused here).

Gates: zig build, zig build test, run_examples.sh -> 343 passed,
cross_compile.sh -> 7 passed (also refreshed its stale example names).
2026-06-02 09:23:50 +03:00
agra
b31fbae757 platform/sdl3: chdir to .app bundle on macOS so CWD-relative assets resolve
A macOS .app launched with CWD=/ (Finder/open) could not find CWD-relative
assets (read_file_bytes("assets/...")) and crashed in stbtt with a null font.
SdlPlatform.init now chdirs to SDL_GetBasePath() when running from inside a
.app bundle (detected by ".app" in the base path), mirroring uikit.sx s iOS
chdir_to_bundle. Gated so the sx run dev flow (binary not bundled) keeps the
project CWD. Verified: direct-exec with CWD=/ now stays alive (was: instant
stbtt segfault). Filed issue 0051 with the analysis.

Note: launching via Finder/open additionally triggers Gatekeeper App
Translocation for the dev-signed bundle (separate code-signing concern, not
the asset path).
2026-05-30 01:10:13 +03:00
agra
4e27a7e6c9 platform: UIKitPlatform end-to-end — chess game runs on iOS sim
What works on iOS sim now:
- pure-UIKit boot via UIApplicationMain (no SDL3 on iOS)
- SxGLView (CAEAGLLayer) + EAGLContext(GLES3) + CADisplayLink
- GLES3 shader path in modules/ui/renderer.sx (was wasm-only; now
  wasm-OR-ios)
- UITouch -> ui.Event translation (mouse_down/moved/up) on touchesBegan/
  Moved/Ended/Cancelled. Verified by tapping the chess board: the
  expected pawn highlights and its legal moves show as green dots.
- chdir to NSBundle.mainBundle.resourcePath inside UIKitPlatform.init so
  the game's relative fopen("assets/...") calls resolve.

Required restructuring to fix four problems discovered along the way:

1. GL context + load_gl must happen BEFORE UIApplicationMain so the
   game's pipeline.init (which compiles shaders) doesn't crash on null
   function pointers. Pulled EAGLContext creation + load_gl out of
   didFinishLaunching: into UIKitPlatform.init via uikit_create_gl_context.

2. UIScreen.nativeScale returns CGFloat (=double on 64-bit Apple).
   Reading it through a `(*void, *void) -> f32` msgSend signature
   clobbers the value to 0 — the upper 32 bits of d0 land where the f32
   reads from. Replaced msg_f with msg_d returning f64 (and added
   msg_odbl for setContentScaleFactor: which takes CGFloat).

3. `xx <f64-call-result>` directly assigned to an f32 field through a
   sema path lowers as `sitofp` (integer→float) on the double — LLVM
   verification rejects it. Workaround: hoist into an `f64` local first.

4. The renderer was selecting the GLSL 330 core shader on every non-wasm
   target, including iOS GLES3 where it silently fails to compile and
   no quads render. Added OS == .ios to the GLES branch.

Game changes:
- main.sx: g_plat is now a boxed `Platform` (not concrete *SdlPlatform).
  Backend chosen per-target via `inline if OS == .ios { ... }`. The
  ESC-to-stop handling is OS-guarded (mobile apps don't quit on key
  press, and SDL_Keycode references would force-link SDL on iOS).
- build.sx: iOS no longer adds SDL3; it adds UIKit + OpenGLES +
  QuartzCore instead.
- delta_time and viewport dims are now mirrored to free globals so the
  dock subsystem (`g_dock_delta_time = @g_delta_time`) and build_ui
  layout decisions don't need a pointer through the boxed protocol.

Other:
- Added `stop()` to the Platform protocol (no-op on UIKitPlatform).
- examples/66-uikit-platform.sx updated: taps advance the clear color
  (red → green → blue) — smoke test for the touch IMP wiring.
- shutdown() on UIKitPlatform is a no-op (mobile apps don't tear down).

Outstanding for next session:
- The Dynamic Island notch overlaps the top of the board because we
  haven't read UIView.safeAreaInsets yet (CGRect/UIEdgeInsets struct
  returns require a different msgSend ABI than we currently express).
- Keyboard observer (UIKeyboardWillChangeFrameNotification + animation
  duration) — the load-bearing iOS feature.
- Real-device codesigning workflow for the new build.

Two more sx compiler bugs to file out of this work:
- xx(f64 call result) → f32 emits sitofp (problem #3 above).
- Inline `#import` inside `inline if` fails to parse (we worked around
  by importing both backends unconditionally; the unused-backend's
  Obj-C calls are gated by `inline if OS == .ios`).
2026-05-17 16:52:03 +03:00
agra
32da32ca66 platform: SDL3 backend (desktop + WASM) + two bug repros
- library/modules/platform/sdl3.sx: SdlPlatform impl wrapping SDL3 init,
  GL context, event pump, swap. run_frame_loop owns the loop: while loop
  on desktop, emscripten_set_main_loop on WASM. Registers an event-watch
  that re-invokes the frame closure during macOS modal resize-drag so
  content keeps rendering at the new size. safe_insets / keyboard /
  show_keyboard / hide_keyboard are no-ops (these targets have no soft
  keyboard).

Two compiler bug repros uncovered during the refactor:

- examples/issue-0020.sx: global `Foo = .{}` zero-initializes, ignoring
  struct field defaults. Local `Foo = .{}` correctly applies defaults.
  Workaround: set fields explicitly in an init method or heap-allocate
  the value.

- examples/issue-0021.sx: an enclosing function's return type bleeds
  into `xx`'s target type inside an `if-then-else` expression on the
  RHS of a struct-field assignment. The same expression in a `-> void`
  function produces the right value; in a `-> bool` function it
  silently produces 0. Bit the SX Chess game's dpi_scale calc inside
  `SdlPlatform.init` (returns bool), making all text labels render
  invisibly on retina. Workaround: hoist each `xx` cast into its own
  f32 local.

Regression gate: 50/50 examples pass, macOS chess game runs at ~2700fps
(close to the pre-refactor 2900 baseline), WASM build still emits a
working .html/.js/.wasm/.data quad.
2026-05-17 15:26:35 +03:00