Commit Graph

41 Commits

Author SHA1 Message Date
agra
e86e41b719 ERR/E5.3: specs.md §12 Error Handling (fold locked design into spec)
Add a top-level §12 Error Handling distilling the locked error design +
surface syntax: failable signatures (-> (T,!) / -> ! / multi-value),
named `error { }` + inferred `!` sets, raise/try/catch/or/onfail, the
path-marker rule, set widening, error.X as a value, discard rejection +
flow-check, closures-with-!, return traces, and the u32-last-slot ABI.

Renumber Grammar §12→§13 and Open Questions §13→§14 (insert sits after
§10.5, so §3/§10.5 — the only section numbers referenced from CLAUDE.md
— stay valid). Cross-link the `!` channel from the Keywords list,
Operator Precedence, Function Definition, and §11 Program Structure;
extend the §13 grammar with error_decl, raise_stmt, onfail_stmt, a
catch_expr tier, `try` in unary, and failable type productions.

Pure docs; no compiler change. Gates: build, test, run_examples (293/0).
2026-06-01 18:19:26 +03:00
agra
6b5edc77b4 lang: require ':' before a for-loop range cursor
The cursor clause now matches the collection form's ': (capture)' — 'for 0..N: (i)' instead of 'for 0..N (i)'. The colon is required when a cursor is present; the no-cursor form 'for 0..N { }' is unchanged. Updated examples/200, the pack-index doc comment, and the spec.
2026-05-31 10:57:21 +03:00
agra
d70a7084ff specs: document for-loop by-reference capture (for xs: (*elem))
Covers the *elem pointer binding: zero-copy pass to *T params, write-back via elem.*, value-position auto-deref, and pointer-subject match.
2026-05-31 10:32:05 +03:00
agra
8a875d354c lang F1 2.7: pack-as-value diagnostics (Phase 2 complete)
Using a bare pack name where a runtime value is required was silent garbage
(f(xs)/return xs produced a stray pointer). Now a clear, context-tailored
compile error: isPackName + diagPackAsValue, caught at lowerVarDecl (storage),
lowerReturn (return), lowerFor (iterate), and an identifier-arm catch-all for
call/other. Storage binds a placeholder so there is no cascade error.

Suggestions point at WORKING fixes -- materialize (..xs), or declare the slice
form ..xs: []P for runtime use. The plan category-B "spread ..xs" is broken
(spreading a comptime pack into a []Any param crashes the LLVM verifier; filed
issue 0053), so the diagnostics steer to the slice-of-protocol variadic instead.

Repurposed examples/162-pack-bare-args.sx (was an aspirational bare-$args->[]Any
auto-materialise, contradicting Decision 1) into the slice-form forward
(..args: []Any). examples/203 is the four-category negative test. specs.md "Pack
as value" updated. 238 examples + unit green.
2026-05-30 02:09:41 +03:00
agra
ab572359ae lang: slice-of-protocol variadic ..xs: []P erases each arg to the protocol
packVariadicCallArgs stored the raw concrete arg into a [N x P] array when the
element type was a protocol, so an 8-byte struct landed in a 16-byte {ctx,
vtable} slot -> garbage vtable -> Bus error on dispatch. Now, when the slice
element type is a protocol, each arg is xx-erased to the protocol value via
buildProtocolErasure (same impl-driven machinery as the xx cast). This makes
..xs: []P the runtime, protocol-erased counterpart to the comptime
heterogeneous pack ..xs: P (which stays comptime-only): xs[runtime_i].method()
now works in an ordinary loop.

specs.md: full variadic/pack form-comparison table (concrete-vs-erased,
comptime-vs-runtime). Regression: examples/202. Issue 0052 (FIXED). 237 green.
2026-05-30 01:50:29 +03:00
agra
27c88d4d26 lang F1: range-based for + inline-for unroll over packs
Add range loop syntax:
- runtime  for start..end (i) { }   counting loop, cursor optional, end exclusive
- comptime inline for start..end (i) { }   comptime-unrolled body

The inline form binds the cursor as an int_val comptime constant per
iteration, so xs[i] over a heterogeneous pack substitutes the concrete
per-position element -- the canonical's pack-iteration vehicle
(inline for 0..sources.len (i) { sources[i].addListener(...) }).

- AST: ForExpr.range_end, ForExpr.is_inline
- parser: parseForExpr range vs collection form; suppress_call flag so
  N (i) is not read as a call N(i) while parsing a range bound
- lower: lowerRuntimeRangeFor / lowerInlineRangeFor; evalComptimeInt;
  comptimeIndexOf extends pack-index resolution beyond int literals

Revises spec's inline for i in 0..N to the no-in, range-first, paren-cursor
form. Regression: examples/200-for-range.sx.
2026-05-29 21:36:17 +03:00
agra
934585ac74 lang 2.4: lock protocol-pack access semantics (interface-only)
Design decision: a protocol-constrained pack element is viewed THROUGH the
constraint protocol — only the protocol's interface (its methods, and the
projections xs.T / xs.value) is accessible, not arbitrary concrete members,
exactly like a constrained generic `T: Show`. So `xs[i].v` (a field on the
concrete IntBox, not declared on Show) is an error; the constraint is enforced
and bounds the body regardless of the concrete arg types at a call site.

The previous example 191 demonstrated `xs[i].v` — which only compiled because
the constraint is not yet enforced. Trimmed it to the protocol-agnostic part
that's correct today (per-shape binding + comptime `xs.len` across arities /
heterogeneous shapes); protocol-interface access + projection are the remaining
2.4 work. specs.md records the access rule.
2026-05-29 17:55:11 +03:00
agra
4c15fd55bb specs: add Variadic Heterogeneous Type Packs section
Specs the Feature 1 language surface: the three variadic forms
(`[]T` / `..$xs: []Type` / `..xs: Protocol`), the pack-ops table
(`xs.len`, `xs[i]`, `inline for` index + element forms, projection, and
the four spread targets — call args / tuple value / tuple type / closure
sig), position-driven pack projection with the same-name soft warning,
the tuple spread/projection parallels, N=0 semantics, the pack-as-value
diagnostic rule, tuple-based storage + the impl-driven `xx` requirement,
and the canonical Combined/map example. Cross-references from the Tuple
Types and Closure Type sections.
2026-05-29 12:03:51 +03:00
agra
952dc0e161 ffi: drop legacy name: ..T variadic syntax
Parser hard-rejects the legacy `name: ..T` form with a one-line
migration message pointing at the new `..name: []T` shape. The
leading-`..` form is the one the lowering paths
(`resolveParamType` / `packVariadicCallArgs`) treat as canonical
post-issue-0049; leaving both forms accepted invited the same
class of cross-module emit crashes any time a `..T`-form decl in
stdlib crossed an import boundary.

`specs.md` updated alongside: the Variadic Functions section now
documents `..name: []T` as the surface form, with notes on
homogeneous vs `[]Any` boxing and the `..` spread at call sites.
Inline references to `args: ..Any` in §7 and §8 refreshed.
2026-05-27 21:32:45 +03:00
agra
b710a0a42a lang: xx <lvalue> borrows the operand's storage instead of heap-copying
`xx <struct-typed local>` used to heap-copy the value through context.allocator.
The protocol value's `ctx` pointed at the heap copy; the original local was
left behind, untouched. Mutations through the protocol never reached the
original, and direct reads of the original never saw protocol mutations.
Two-fork bug, silent, easy to write by mistake.

New rule (Option 3 in the discussion):

- `xx <lvalue>` — identifier, field access, index expression, deref —
  borrows the operand's storage. No heap copy, no `free` needed.
- `xx <rvalue>` — struct literal, function-call result, arithmetic, etc. —
  heap-copies through context.allocator. Unchanged from today.
- `xx @ptr` and `xx <pointer-typed value>` — borrows the pointee. Unchanged.

Single switch in `buildProtocolErasure` ([lower.zig:10334](src/ir/lower.zig#L10334))
gated by a new `isLvalueExpr` helper ([lower.zig:10322](src/ir/lower.zig#L10322)).
Struct-typed operand: if the AST shape is identifier/field/index/deref,
emit `lowerExprAsPtr(operand_node)` and skip the heap-copy; otherwise
keep the alloca-store-heap_copy path.

specs.md §3 ownership table extended to three rows (rvalue, lvalue,
pointer) with examples and rationale per row.

Regressions:

- `examples/130-xx-value-routes-through-context-allocator.sx` — the
  Phase 1.1 witness for heap-copy-via-context-allocator. Previous shape
  (`xx <local-value>`) is now a borrow under Option 3 and no longer
  exercises the heap-copy path. Rewritten to use a struct literal
  (`xx ByValue.{...}`) which still heap-copies through context.allocator
  — Tracer.count = 1 as before.
- `examples/135-xx-lvalue-borrows.sx` — new test. Dereferences a
  TrackingAllocator into a stack value, does `xx tracker` inside a
  push Context, and asserts alloc_count/dealloc_count on the LOCAL go
  up. Under old semantics this would have stayed at 0 (heap copy got
  the increments, local stayed stale).

157/157 example tests pass; chess clean on macOS / iOS sim / Android
(`tools/verify-step.sh` ran green immediately before this work).
2026-05-25 15:23:13 +03:00
agra
72593db953 mem: List(T) mutations gain optional alloc: Allocator = context.allocator
The chess panel-text regression (text vanished after the first move on
macOS) had a single root cause: GlyphCache's entries List, hash table,
and shaped_buf grew through `context.allocator` — which during render
is the per-frame arena. On the next arena reset the backing died, and
subsequent glyph lookups read garbage / wrote into freshly-allocated
view-tree memory.

Fix is shaped as the user proposed: `List(T)`'s mutations take an
optional trailing `alloc: Allocator = context.allocator` argument. No
allocator stored on the container, no init ceremony, every existing
`list.append(item)` callsite keeps working unchanged. Long-lived
owners now write `list.append(item, self.parent_allocator)` and the
arena-leak bug becomes impossible to write accidentally.

Default-arg substitution previously only fired for identifier callees
(`expandCallDefaults` at lower.zig:7978). Extended to the generic
struct-method dispatch path (`list.append(...)` lands here) via a new
`appendDefaultArgs` helper that lowers fd.params[i].default_expr in
the caller's scope and appends to the lowered args slice.

Long-lived owners updated to capture `parent_allocator: Allocator` at
init and use it for every internal growth:

- GlyphCache (the chess bug) — entries, shaped_buf, hash_keys,
  hash_vals, atlas bitmap.
- DockInteraction — drops the existing `push Context` workaround in
  `ensure_capacity` for the explicit-arg form.
- StateStore — entries list + per-entry data buffer.
- Gles3Gpu, MetalGPU — shaders, buffers, textures (atlas-grow during
  render would otherwise leak resources into the frame arena).

Also kept: an operator-precedence fix in pipeline.sx
(`(self.frame_index & 1) == 0` instead of
`self.frame_index & 1 == 0`, which parses as
`self.frame_index & (1 == 0)` = always 0). That was a stealth
single-arena-only bug that masked the GlyphCache one for a long time.

Docs:
- specs.md §11 documents `param: T = expr` default parameter values.
  The parser already supported it — formalised in the spec now.
- current/CHECKPOINT-MEM.md logs the change.
- CLAUDE.md REJECTED PATTERNS gains a "Long-lived containers growing
  through context.allocator" section with the `parent_allocator`
  capture template and the list of existing examples to mirror.

155/155 example tests pass — zero-diff against snapshots since every
existing callsite still resolves to `context.allocator`.
2026-05-25 14:41:17 +03:00
agra
4c6c29b299 specs: §10.5 Bundling and Post-Link Callbacks
Documents the post-link callback model that the bundling-in-sx campaign
landed (Weeks 6 + 7):

  - Explicit opt-in via `BuildOptions.set_post_link_callback(fn)` or
    `set_post_link_module(name)` from a user `#run` block. No stdlib
    default; no implicit prelude. CLI `--bundle` / `--apk` auto-fallback
    to `post_link_module = "platform.bundle"` so existing CLI invocations
    keep working without an in-source registration.

  - `BuildOptions` surface: setters (link_flag / framework / output_path
    / wasm_shell / asset_dir / post_link_callback / post_link_module /
    bundle_path / bundle_id / codesign_identity / provisioning_profile /
    manifest_path / keystore_path) + accessors (binary_path / target_triple
    / is_macos / is_ios / is_ios_device / is_ios_simulator / is_android /
    framework / framework_path / jni_main / asset_dir families). Returned
    strings are "" when unset; counts are 0.

  - `fs.sx` / `process.sx` stdlib modules. Both work in two execution
    contexts: at runtime via the dynamic linker, and at #run / post-link
    via `src/ir/host_ffi.zig`'s dlsym(RTLD_DEFAULT) trampolines.

  - Per-target Apple `.app` flow: stage + Info.plist (macOS minimal vs
    iOS-shaped UIDeviceFamily/LSRequiresIPhoneOS/UIApplicationSceneManifest/
    DTPlatformName) + provisioning embed (iOS device) + Frameworks/ embed
    (iOS) + entitlements extraction (`security cms` + 3× `plutil`) +
    codesign with --entitlements when present.

  - Android `.apk` flow: SDK discovery → highest build-tools / platforms
    via `ls -1 | sort -V | tail -1` → stage lib/arm64-v8a/<libfoo.so> →
    manifest synth (NativeActivity vs `#jni_main` Activity) → javac + d8
    per `#jni_main` decl → aapt2 link → zip lib/dex/assets → zipalign →
    keytool debug keystore (first use) → apksigner sign.
2026-05-23 01:35:05 +03:00
agra
f9ecf9d00e iOS lock step keyboard + metal 2026-05-18 17:40:10 +03:00
agra
67e02a20a5 ... 2026-03-04 09:18:24 +02:00
agra
6c5672c7df trailing commas 2026-03-03 09:42:01 +02:00
agra
bbb5426777 sm 2026-03-02 21:00:55 +02:00
agra
566121c45a more forward declarations 2026-02-24 17:37:52 +02:00
agra
b98711a1d3 imports 2026-02-24 13:37:27 +02:00
agra
170e236764 vtables, protocol 2026-02-24 06:20:38 +02:00
agra
0cc7b69441 closures 2026-02-23 13:45:44 +02:00
agra
1cc67f9b5a optionals 2026-02-22 22:16:30 +02:00
agra
6f927361aa pipes 2026-02-20 13:28:38 +02:00
agra
1ecac79642 bit ops 2026-02-20 12:12:51 +02:00
agra
e0e655cd36 tuples 2026-02-19 01:26:04 +02:00
agra
fbf8a62362 comptime format 2026-02-18 18:57:51 +02:00
agra
4aff004118 http server 2026-02-17 19:49:01 +02:00
agra
4fd87309d9 http server 2026-02-17 16:57:12 +02:00
agra
c8ceceed0f ... 2026-02-16 01:58:30 +02:00
agra
58e2a5bdb1 multiple assign 2026-02-16 01:13:34 +02:00
agra
fb60818424 for arr: (it) {} 2026-02-16 00:55:03 +02:00
agra
e7d2abdf0c layout 2026-02-14 21:28:49 +02:00
agra
d61c6488f3 @ enum type 2026-02-14 14:52:39 +02:00
agra
fe7efeadb0 flags 2026-02-14 14:03:22 +02:00
agra
025b790411 enum, union 2026-02-14 13:17:22 +02:00
agra
4ff828fd1a sdl phase 2 2026-02-12 21:37:25 +02:00
agra
dab162bfe4 strings 2026-02-12 16:23:42 +02:00
agra
25e1372731 extend default to s64 2026-02-11 01:05:21 +02:00
agra
70435d3c85 pointers 2026-02-10 22:47:43 +02:00
agra
ef14144d49 ... 2026-02-10 21:03:56 +02:00
agra
3fde080092 quick sort 2026-02-10 18:58:04 +02:00
agra
55fc5790e4 so... jai :D 2026-02-09 18:07:41 +02:00