From c1018d87c51d6cb639498741a218984fb212bd29 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 26 Sep 2026 18:13:56 +0700 Subject: [PATCH] Every reference to the removed .flan files is updated, generated.fln's stale banner line is regenerated, and the ported .fln files read like handwritten Flan. --- README.md | 4 +- examples/core-2d-camera.fln | 28 +++-- examples/core-3d-picking.fln | 16 +-- examples/core-basic-window.fln | 2 +- examples/core-delta-time.fln | 2 +- examples/core-input-gamepad.fln | 8 +- examples/core-input-gestures-testbed.fln | 8 +- examples/core-input-gestures.fln | 4 +- examples/core-input-keys.fln | 4 +- examples/core-input-mouse.fln | 2 +- examples/core-input-multitouch.fln | 8 +- examples/core-input-virtual-controls.fln | 20 ++-- examples/core-scissor-test.fln | 2 +- examples/core-window-flags.fln | 12 +- examples/core-window-should-close.fln | 13 +-- examples/core-world-screen.fln | 4 +- examples/digits.fln | 10 +- examples/models-box-collisions.fln | 10 +- examples/shapes-basic-shapes.fln | 6 +- examples/shapes-collision-area.fln | 14 +-- examples/shapes-following-eyes.fln | 8 +- examples/text-codepoints-loading.fln | 10 +- examples/text-input-box.fln | 8 +- examples/text-rectangle-bounds.fln | 13 +-- examples/text-writing-anim.fln | 10 +- examples/textures-fog-of-war.fln | 14 +-- examples/textures-image-generation.fln | 2 +- examples/textures-image-processing.fln | 18 +-- examples/textures-mouse-painting.fln | 18 ++- lib/build.ml | 2 +- lib/dev.ml | 4 +- lib/load.ml | 4 +- lib/prelude.ml | 8 +- lib/session.ml | 2 +- runtime/flan_dyn.c | 4 +- sand.fln | 4 +- test/programs/pkg-hidden-main.flan | 4 +- test/programs/pkg-shared.flan | 4 +- test/programs/raylib-codepoints.flan | 2 +- test/programs/raylib-image-processing.flan | 2 +- test/programs/virtual-controls-headless.flan | 2 +- test/test_acceptance.ml | 41 +++---- test/test_dev.ml | 6 +- test/test_flan.ml | 5 +- test/test_session.ml | 47 ++++---- test/test_syntax.ml | 4 +- test/test_web.ml | 8 +- vendor/agent/flan_agent.web.c | 6 +- vendor/edn/edn.fln | 22 ++-- vendor/edn/provide.fln | 113 ++++++++++++------- vendor/edn/read.fln | 8 +- vendor/json/json.fln | 18 +-- vendor/json/provide.fln | 78 ++++++++----- vendor/raylib/bindings | 20 ++-- vendor/raylib/generated.fln | 2 +- vendor/raylib/headers | 6 +- vendor/raylib/modes.fln | 16 +-- vendor/raylib/raylib.fln | 52 ++++----- vendor/raylib/vector.fln | 16 +-- web/examples/quotes.sh | 4 +- web/index.html | 4 +- 61 files changed, 423 insertions(+), 373 deletions(-) diff --git a/README.md b/README.md index 28161a4b..836afe5f 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ dune exec ./bin/main.exe -- build web/examples/hello.flan -o hello The falling-sand demo uses raylib: ```sh -dune exec ./bin/main.exe -- run sand.flan +dune exec ./bin/main.exe -- run sand.fln ``` Once you are iterating regularly, put the built executable on your `PATH` if @@ -77,7 +77,7 @@ you want to use the shorter `flan` commands shown below. Start a long-lived development session: ```sh -flan dev sand.flan +flan dev sand.fln ``` The program runs normally and publishes a local socket beside the source file. diff --git a/examples/core-2d-camera.fln b/examples/core-2d-camera.fln index 07a4a6ce..e88eca53 100644 --- a/examples/core-2d-camera.fln +++ b/examples/core-2d-camera.fln @@ -2,22 +2,22 @@ ;;;; ;;;; examples/core/core_2d_camera.c. Needed no new binding at all, which is ;;;; the reason to port it: Camera2D, begin-mode-2d and end-mode-2d have been -;;;; in vendor/raylib/raylib.flan since the beginning and nothing in the +;;;; in vendor/raylib/raylib.fln since the beginning and nothing in the ;;;; corpus had ever passed a whole Camera2D across the FFI on a frame's path. ;;;; Two Vector2s, a float and a float, by value, sixty times a second — the ;;;; acceptance table pins that layout with get-screen-to-world-2d, and this ;;;; is the same struct going into the call that actually draws with it. ;;;; -;;;; The hundred buildings are a `defonce` of fixed arrays rather than a Vec: +;;;; The hundred buildings are a `once` of fixed arrays rather than a Vec: ;;;; a global cannot hold a Vec (docs/PORTING.md §3) and does not need to here, -;;;; because the count is a constant in the C too. `(array n T)` is the zeroed +;;;; because the count is a constant in the C too. `array(n, T)` is the zeroed ;;;; fixed array, and the C's `= { 0 }` is exactly that. ;;;; ;;;; get-random-value comes from the generated half of the bindings. It is on ;;;; no frame's path — it runs once, before the loop — and its Flan face is ;;;; the C one, so docs/PORTING.md §1's rule does not reach it. ;;;; -;;;; One deliberate difference from the C: `(- camera.rotation 1.0)` and the +;;;; One deliberate difference from the C: `camera.rotation - 1.0` and the ;;;; clamp after it are written with the prelude's `clamp` macro rather than ;;;; two ifs. It is the same arithmetic; the C spells it out because C has no ;;;; clamp. @@ -38,7 +38,7 @@ fn main() -> () rl/init-window(screen-width, screen-height, "raylib [core] example - 2d camera") defer rl/close-window() - player = rl/Rectangle{.x 400.0 .y 280.0 .width 40.0 .height 40.0} + player = rl/Rectangle{.x 400.0, .y 280.0, .width 40.0, .height 40.0} buildings = array(max-buildings, rl/Rectangle) build-colors = array(max-buildings, rl/Color) ;; The skyline: each building is as wide as the last one left room for, so @@ -47,13 +47,13 @@ fn main() -> () for i in range(max-buildings) let w = f32(rl/get-random-value(50, 200)) h = f32(rl/get-random-value(100, 800)) - buildings[i] = rl/Rectangle({.x -6000.0 + f32(spacing), .y (f32(screen-height) - 130.0) - h, .width w, .height h}) + buildings[i] = rl/Rectangle{.x -6000.0 + f32(spacing), .y (f32(screen-height) - 130.0) - h, .width w, .height h} spacing += i32(w) - build-colors[i] = rl/Color({.r u8(rl/get-random-value(200, 240)) .g u8(rl/get-random-value(200, 240)) .b u8(rl/get-random-value(200, 250)) .a 255}) + build-colors[i] = rl/Color{.r u8(rl/get-random-value(200, 240)) .g u8(rl/get-random-value(200, 240)) .b u8(rl/get-random-value(200, 250)) .a 255} ;; A fresh Camera2D is all zeroes and a zoom of 0 makes the transform - ;; singular, so the zoom is the one field that must be set — raylib.flan's + ;; singular, so the zoom is the one field that must be set — raylib.fln's ;; own comment on the struct says so. - camera = rl/Camera2D({.offset rl/Vector2{.x f32(screen-width) / 2.0, .y f32(screen-height) / 2.0} .target rl/Vector2{.x player.x + 20.0, .y player.y + 20.0} .rotation 0.0 .zoom 1.0}) + camera = rl/Camera2D{.offset rl/Vector2{.x f32(screen-width) / 2.0, .y f32(screen-height) / 2.0} .target rl/Vector2{.x player.x + 20.0, .y player.y + 20.0} .rotation 0.0 .zoom 1.0} rl/set-target-fps(60) until rl/window-should-close() ;; Update @@ -61,16 +61,14 @@ fn main() -> () ;; right, which is the else-if and not an accident. if rl/is-key-down(:key-right) player.x += 2.0 - else - if rl/is-key-down(:key-left) - player.x -= 2.0 + elif rl/is-key-down(:key-left) + player.x -= 2.0 ;; The camera follows the player's centre. camera.target = rl/Vector2{.x player.x + 20.0, .y player.y + 20.0} if rl/is-key-down(:key-a) camera.rotation -= 1.0 - else - if rl/is-key-down(:key-s) - camera.rotation += 1.0 + elif rl/is-key-down(:key-s) + camera.rotation += 1.0 camera.rotation = clamp(camera.rotation, -40.0, 40.0) camera.zoom += rl/get-mouse-wheel-move() * 0.05 camera.zoom = clamp(camera.zoom, 0.1, 3.0) diff --git a/examples/core-3d-picking.fln b/examples/core-3d-picking.fln index 708c2eb3..ffdcc627 100644 --- a/examples/core-3d-picking.fln +++ b/examples/core-3d-picking.fln @@ -5,7 +5,7 @@ ;;;; anywhere upstream that uses Ray and RayCollision without also loading a ;;;; Model, so it is the only way those two structs get a caller at all. ;;;; -;;;; Picking is the round trip the corpus was missing. core-world-screen.flan +;;;; Picking is the round trip the corpus was missing. core-world-screen.fln ;;;; already runs get-world-to-screen — a point in the scene to a pixel. This ;;;; is the inverse and it is a different shape: a pixel does not name a ;;;; point, it names a *line* through the scene, which is what a Ray is, and @@ -13,7 +13,7 @@ ;;;; something, which is what a RayCollision is. Two structs the package could ;;;; not describe, for one operation that cannot be written without them. ;;;; -;;;; What was added, all in vendor/raylib/raylib.flan: +;;;; What was added, all in vendor/raylib/raylib.fln: ;;;; ;;;; - `Ray` — two Vector3s, origin and direction. ;;;; - `RayCollision` — a C `bool`, a float and two Vector3s. This is the @@ -21,7 +21,7 @@ ;;;; `hit` is one byte and `distance` is four, so there are three padding ;;;; bytes between them that a permutation destroys. BoundingBox's two ;;;; Vector3s are interchangeable and nothing would catch swapping them. -;;;; - `BoundingBox` — shared with examples/models-box-collisions.flan. +;;;; - `BoundingBox` — shared with examples/models-box-collisions.fln. ;;;; - get-screen-to-world-ray and draw-ray, hand-written beside ;;;; get-world-to-screen and the cube draws for the reasons `bindings` ;;;; gives: the first reads the same camera as its inverse, and the second @@ -53,12 +53,12 @@ once ray: rl/Ray once collision: rl/RayCollision ;; The same centre/size to min/max conversion as in -;; examples/models-box-collisions.flan. Written out here rather than shared +;; examples/models-box-collisions.fln. Written out here rather than shared ;; because an example is a single file the reader can follow end to end. ;; ;; It used to be eight expressions of field arithmetic; it is the half-extent ;; subtracted and added, which is what the C means, now that the package -;; carries vector arithmetic — see vendor/raylib/vector.flan. That file +;; carries vector arithmetic — see vendor/raylib/vector.fln. That file ;; exists because raymath is `static inline` and has no symbol to bind, so ;; v3-sub and v3-add are Flan and not C. fn box-around(centre: rl/Vector3, size: rl/Vector3) -> rl/BoundingBox @@ -69,14 +69,14 @@ fn main() -> () rl/init-window(screen-width, screen-height, "raylib [core] example - 3d picking") defer rl/close-window() - camera = rl/Camera3D({.position rl/Vector3{.x 10.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective}) + camera = rl/Camera3D{.position rl/Vector3{.x 10.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective} cube-position = rl/Vector3{.x 0.0 .y 1.0 .z 0.0} cube-size = rl/Vector3{.x 2.0 .y 2.0 .z 2.0} ;; Both start zeroed, which is the C's `= { 0 }`. A zero Ray draws as a ;; degenerate line at the origin and a zero RayCollision has hit false, so ;; neither needs a "not yet" flag beside it. - ray = rl/Ray({.position rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .direction rl/Vector3{.x 0.0 .y 0.0 .z 0.0}}) - collision = rl/RayCollision({.hit false .distance 0.0 .point rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .normal rl/Vector3{.x 0.0 .y 0.0 .z 0.0}}) + ray = rl/Ray{.position rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .direction rl/Vector3{.x 0.0 .y 0.0 .z 0.0}} + collision = rl/RayCollision{.hit false .distance 0.0 .point rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .normal rl/Vector3{.x 0.0 .y 0.0 .z 0.0}} rl/set-target-fps(60) until rl/window-should-close() ;; Update. The first-person controls only run while the cursor is diff --git a/examples/core-basic-window.fln b/examples/core-basic-window.fln index 5a663392..61050807 100644 --- a/examples/core-basic-window.fln +++ b/examples/core-basic-window.fln @@ -6,7 +6,7 @@ ;;;; ;;;; The one structural difference from the C is the loop: the C writes ;;;; `while (!WindowShouldClose())` and Flan has `until`, which is the same -;;;; thing without the negation. sand.flan does likewise. +;;;; thing without the negation. sand.fln does likewise. ;;;; ;;;; `defer` closes the window. It is function-scoped — it runs when `main` ;;;; returns and not at the end of any inner block — which is exactly what the diff --git a/examples/core-delta-time.fln b/examples/core-delta-time.fln index 7a2aeb79..f7a341f0 100644 --- a/examples/core-delta-time.fln +++ b/examples/core-delta-time.fln @@ -19,7 +19,7 @@ ;;;; here rather than instead of it, so the file is not quietly asserting that ;;;; the original was right. ;;;; -;;;; The two circle positions are `defonce`s for the usual reason: they are +;;;; The two circle positions are `once`s for the usual reason: they are ;;;; state between frames and a `let` inside the loop would reset them. import rl "vendor:raylib" diff --git a/examples/core-input-gamepad.fln b/examples/core-input-gamepad.fln index 4ffa356d..e9b40bd8 100644 --- a/examples/core-input-gamepad.fln +++ b/examples/core-input-gamepad.fln @@ -21,7 +21,7 @@ ;;;; branches that matched on it are the artwork's and are gone with it. ;;;; ;;;; **The VIBRATE button is drawn and inert.** SetGamepadVibration is the one -;;;; call in the C this refuses to bind, and vendor/raylib/raylib.flan already +;;;; call in the C this refuses to bind, and vendor/raylib/raylib.fln already ;;;; carries the paragraph saying why: its arity differs between raylib ;;;; versions with no 5.5 header here to settle it, so a guess is a corrupted ;;;; stack frame rather than a link error — and the symbol in libraylib.so.550 @@ -51,7 +51,7 @@ fn deadzone(v: f32, limit: f32) -> f32 if v > 0.0 - limit and v < limit then 0.0 else v ;; The triggers rest at -1 rather than 0, which raylib does not normalise — -;; see the note on GamepadAxis in vendor/raylib/raylib.flan. So their deadzone +;; see the note on GamepadAxis in vendor/raylib/raylib.fln. So their deadzone ;; is a floor near the resting end and not a band around the middle. fn trigger-deadzoned(v: f32) -> f32 if v < trigger-deadzone then -1.0 else v @@ -162,7 +162,7 @@ fn main() -> () if rl/is-key-pressed(:key-right) gamepad += 1 let axis-count = min(6, rl/get-gamepad-axis-count(gamepad)) - let vibrate-rect = rl/Rectangle({.x 10.0, .y 90.0 + 20.0 * f32(axis-count), .width 75.0, .height 24.0}) + let vibrate-rect = rl/Rectangle{.x 10.0, .y 90.0 + 20.0 * f32(axis-count), .width 75.0, .height 24.0} ;; Draw rl/with-drawing: rl/clear-background(rl/raywhite) @@ -225,7 +225,7 @@ fn main() -> () ;; has type i32 while its sibling has type () and the `if` will not ;; typecheck — "expected i32, found ()". Both arms end in a ;; draw-text here, which is the tidy way out; where that is awkward a - ;; trailing `(do)` is the other. + ;; trailing `()` is the other. let b = rl/get-gamepad-button-pressed() if b >= 0 rl/draw-text("DETECTED BUTTON: ", 10, 430, 10, rl/red) diff --git a/examples/core-input-gestures-testbed.fln b/examples/core-input-gestures-testbed.fln index efc95e60..33d8bc69 100644 --- a/examples/core-input-gestures-testbed.fln +++ b/examples/core-input-gestures-testbed.fln @@ -24,11 +24,11 @@ ;;;; The rule the refusal came from is unchanged and worth keeping: an enum is ;;;; its own type in the checker, so `:tpa` is an error at the call site ;;;; instead of a number that is wrong later, and a bare integer still does not -;;;; fit an `rl/Gesture` parameter. `(i32 g)` does not weaken that — it is +;;;; fit an `rl/Gesture` parameter. `i32(g)` does not weaken that — it is ;;;; named, and it is at the site. The rule was "an integer must not arrive ;;;; silently", not "an integer is dangerous". ;;;; -;;;; The `!= 4` stays a keyword comparison, `(not (= g :gesture-hold))`. That +;;;; The `!= 4` stays a keyword comparison, `not g == :gesture-hold`. That ;;;; one was never a range test; it is a single member, and the C's 4 is a ;;;; magic number the keyword reads better than. ;;;; @@ -48,9 +48,9 @@ ;;;; ;;;; **No local fixed arrays.** The C declares `char gestureLog[20][12]` and ;;;; `Vector2 touchPosition[32]` inside main. A `let` binding takes no type -;;;; annotation, so a fixed array can only be a top-level `defonce` or a literal +;;;; annotation, so a fixed array can only be a top-level `once` or a literal ;;;; with every element written out — thirty-two Vector2s, here. They are -;;;; `defonce`s, which is what the C's storage amounts to anyway. +;;;; `once`s, which is what the C's storage amounts to anyway. ;;;; ;;;; The log itself came out simpler than the C's: the names are compile-time ;;;; literals, so a slot holds a `string` and there is no TextCopy and no diff --git a/examples/core-input-gestures.fln b/examples/core-input-gestures.fln index 703d6eb9..b0c4dd64 100644 --- a/examples/core-input-gestures.fln +++ b/examples/core-input-gestures.fln @@ -18,7 +18,7 @@ ;;;; has nothing to catch. ;;;; ;;;; A slot that has not been written yet holds a zero-length string, because a -;;;; `defonce` with no initialiser is all-bytes-zero and a string is ptr+len — +;;;; `once` with no initialiser is all-bytes-zero and a string is ptr+len — ;;;; a null pointer with a length of 0. draw-text draws nothing for it. That is ;;;; the C's `{ "" }` initialiser arriving by a different route, and it is why ;;;; resetting the log below only has to reset the counter. @@ -67,7 +67,7 @@ fn main() -> () "raylib [core] example - input gestures") defer rl/close-window() rl/set-target-fps(60) - let touch-area = rl/Rectangle({.x 220.0, .y 10.0, .width f32(screen-width) - 230.0, .height f32(screen-height) - 20.0}) + let touch-area = rl/Rectangle{.x 220.0, .y 10.0, .width f32(screen-width) - 230.0, .height f32(screen-height) - 20.0} until rl/window-should-close() ;; Update last-gesture = current-gesture diff --git a/examples/core-input-keys.fln b/examples/core-input-keys.fln index 5cec7bc9..1f872cd5 100644 --- a/examples/core-input-keys.fln +++ b/examples/core-input-keys.fln @@ -5,13 +5,13 @@ ;;;; ;;;; The C moves the ball by writing `ballPosition.x += 2.0f` on a local ;;;; struct. Flan has the same thing — a local IS an assignable place -;;;; (spec-memory.md) — but the local has to be a `defonce` here rather than a +;;;; (spec-memory.md) — but the local has to be a `once` here rather than a ;;;; `let` inside the loop, because a `let` binding is rebound every iteration ;;;; and the position has to survive between frames. The C's variable is ;;;; outside its while loop for the same reason; this is that, spelled with the ;;;; storage the language has. ;;;; -;;;; `(set (.x ball) ...)` works on a struct field of a global: a field of an +;;;; `ball.x = ...` works on a struct field of a global: a field of an ;;;; assignable place is itself one. import rl "vendor:raylib" diff --git a/examples/core-input-mouse.fln b/examples/core-input-mouse.fln index 24d2141a..192c3c0a 100644 --- a/examples/core-input-mouse.fln +++ b/examples/core-input-mouse.fln @@ -9,7 +9,7 @@ ;;;; matters in both — two buttons pressed on the same frame give the earlier ;;;; one, which is the C's behaviour and not an accident of the port. ;;;; -;;;; The colour has to be a `defonce` rather than a `let`, for the reason +;;;; The colour has to be a `once` rather than a `let`, for the reason ;;;; core-input-keys' position does: it is state between frames. import rl "vendor:raylib" diff --git a/examples/core-input-multitouch.fln b/examples/core-input-multitouch.fln index a2757a80..d39cf16f 100644 --- a/examples/core-input-multitouch.fln +++ b/examples/core-input-multitouch.fln @@ -1,19 +1,19 @@ ;;;; raylib [core] example - input multitouch ;;;; ;;;; examples/core/core_input_multitouch.c. No new bindings: the whole touch -;;;; surface was already there for sand.flan's read-out. +;;;; surface was already there for sand.fln's read-out. ;;;; ;;;; The C keeps `Vector2 touchPositions[MAX_TOUCH_POINTS]`, and this is the ;;;; first example that needs a fixed array whose element type is a STRUCT ;;;; rather than a number. That works — `[10 rl/Vector2]` is ten Vector2s laid -;;;; out flat, no headers, and `(at touch-positions i)` is a place that can be +;;;; out flat, no headers, and `touch-positions[i]` is a place that can be ;;;; assigned a whole struct. Nothing in the repository used one before, so it ;;;; is worth saying that it does. ;;;; -;;;; It is a top-level `defonce` and not a local, which is NOT a stylistic +;;;; It is a top-level `once` and not a local, which is NOT a stylistic ;;;; choice. A `let` binding takes no type annotation, so the only way to make ;;;; a fixed array inside a function is to initialise it from a literal with -;;;; every element written out — ten `(rl/Vector2 {.x 0.0 .y 0.0})`s here, and +;;;; every element written out — ten `rl/Vector2{.x 0.0 .y 0.0}`s here, and ;;;; thirty-two in the gestures testbed. A zeroed local array of a given type ;;;; cannot be spelled. Static storage is what the C's `= { 0 }` gets anyway. ;;;; diff --git a/examples/core-input-virtual-controls.fln b/examples/core-input-virtual-controls.fln index e69eaa91..fa0bb74b 100644 --- a/examples/core-input-virtual-controls.fln +++ b/examples/core-input-virtual-controls.fln @@ -2,7 +2,7 @@ ;;;; ;;;; examples/core/core_input_virtual_controls.c. No new bindings. ;;;; -;;;; Split the way sand.flan is split: everything above the second banner is +;;;; Split the way sand.fln is split: everything above the second banner is ;;;; arithmetic with no raylib calls in it, so test/programs/virtual-controls- ;;;; headless.flan can import this file as a package, drive the pointer over a ;;;; scripted path and hash where the player ended up. That is the only one of @@ -18,7 +18,7 @@ ;;;; ;;;; for (i = 0; i < BUTTON_MAX; i++) { if (...) { pressedButton = i; break; } } ;;;; -;;;; and `(break)` is refused: "break is not implemented yet (see the build +;;;; and `break()` is refused: "break is not implemented yet (see the build ;;;; sequence in plan.org)". `return` from the function works and is what this ;;;; uses — which is why the search is its own `defn` and not written inline ;;;; the way the C has it. That is not a loss: the function is the thing the @@ -26,14 +26,14 @@ ;;;; function, the shape left is a flag and a compound loop condition. ;;;; ;;;; **No `fabsf`.** The prelude has sqrt-f32 and sign-f32 but no absolute -;;;; value for floats, and the comment there says why for integers. `(max v -;;;; (- 0.0 v))` is it, and unlike the integer case it has no edge: there is no -;;;; float whose negation is itself except -0.0, whose absolute value is 0.0 -;;;; either way. +;;;; value for floats, and the comment there says why for integers. +;;;; `max(v, 0.0 - v)` is it, and unlike the integer case it has no edge: there +;;;; is no float whose negation is itself except -0.0, whose absolute value is +;;;; 0.0 either way. ;;;; -;;;; The button geometry is `defconst` arrays of struct literals. That works — +;;;; The button geometry is `const` arrays of struct literals. That works — ;;;; and it is the only way a fixed array can be made inside anything but a -;;;; top-level `defonce`, since a `let` binding takes no type annotation. +;;;; top-level `once`, since a `let` binding takes no type annotation. import rl "vendor:raylib" @@ -41,7 +41,7 @@ const screen-width = 800 const screen-height = 450 ;; The C's PadButton enum. -1 is BUTTON_NONE and the four directions are 0..3, -;; in the order the arrays below are written. A `defenum` would not help: the +;; in the order the arrays below are written. An `enum` would not help: the ;; value is used as an index and an enum does not convert to an integer ;; ("i32 converts a number, found ..."), so it would have to be turned back ;; into one at every use. @@ -56,7 +56,7 @@ const button-radius: f32 = 30.0 ;; padPosition is {100, 350} and the buttons sit a radius and a half away from ;; it on each axis. The C computes these at run time from padPosition; they are -;; written out here because a defconst is compile-time and the numbers are. +;; written out here because a const is compile-time and the numbers are. const button-positions: [button-max rl/Vector2] = [rl/Vector2{.x 100.0 .y 305.0} ; up ; left ; right diff --git a/examples/core-scissor-test.fln b/examples/core-scissor-test.fln index 74070788..a6f32c2a 100644 --- a/examples/core-scissor-test.fln +++ b/examples/core-scissor-test.fln @@ -1,7 +1,7 @@ ;;;; raylib [core] example - scissor test ;;;; ;;;; examples/core/core_scissor_test.c. Needed begin-scissor-mode and -;;;; end-scissor-mode, now hand-written in vendor/raylib/raylib.flan: they are +;;;; end-scissor-mode, now hand-written in vendor/raylib/raylib.fln: they are ;;;; a begin/end pair inside a frame, which is the class docs/PORTING.md §1 says ;;;; belongs in the hand-written half and not in the importer's. get-mouse-x ;;;; and get-mouse-y come from the generated half — their Flan face is the C diff --git a/examples/core-window-flags.fln b/examples/core-window-flags.fln index a16845d6..6cfdf12f 100644 --- a/examples/core-window-flags.fln +++ b/examples/core-window-flags.fln @@ -1,14 +1,14 @@ ;;;; raylib [core] example - window flags ;;;; ;;;; examples/core/core_window_flags.c. The reason to port this one is the -;;;; flags themselves: raylib.flan carried four of ConfigFlags' sixteen -;;;; members — the four sand.flan sets before the window exists — and this +;;;; flags themselves: raylib.fln carried four of ConfigFlags' sixteen +;;;; members — the four sand.fln sets before the window exists — and this ;;;; example reads and writes eleven of them after it exists. All sixteen are -;;;; in raylib.flan now, read off raylib.h 5.5, in the header's order and not +;;;; in raylib.fln now, read off raylib.h 5.5, in the header's order and not ;;;; in bit order (FLAG_VSYNC_HINT is 0x40 and FLAG_FULLSCREEN_MODE is 0x02, ;;;; which is the kind of thing nobody remembers correctly). ;;;; -;;;; They are `defconst u32`s and not a `defenum` for the reason the file +;;;; They are `const u32`s and not an `enum` for the reason the file ;;;; already gives about gestures: raylib wants the OR of several and a ;;;; keyword can only ever name one member. ;;;; @@ -16,7 +16,7 @@ ;;;; minimize-window, maximize-window and restore-window all come from the ;;;; generated half. That is the line drawn in vendor/raylib/bindings and it ;;;; is worth saying why it falls here: the rule in docs/PORTING.md §1 exists so -;;;; that a build with no header set can still draw, and generated.flan is +;;;; that a build with no header set can still draw, and generated.fln is ;;;; committed, so it can. What a hand-written line adds on top of that is a ;;;; Flan face the C signature does not have — a Key instead of an int, a ;;;; (Ptr Camera3D) instead of a raw pointer — and these seven have no such @@ -71,7 +71,7 @@ fn main() -> () rl/init-window(screen-width, screen-height, "raylib [core] example - window flags") defer rl/close-window() - ball-pos = rl/Vector2({.x f32(rl/get-screen-width()) / 2.0, .y f32(rl/get-screen-height()) / 2.0}) + ball-pos = rl/Vector2{.x f32(rl/get-screen-width()) / 2.0, .y f32(rl/get-screen-height()) / 2.0} ball-speed = rl/Vector2{.x 5.0 .y 4.0} ;; No set-target-fps, as in the C: with FLAG_VSYNC_HINT among the flags the ;; example toggles, a frame limiter on top of it would hide what V-Sync diff --git a/examples/core-window-should-close.fln b/examples/core-window-should-close.fln index 22bfd1a1..2cb008c2 100644 --- a/examples/core-window-should-close.fln +++ b/examples/core-window-should-close.fln @@ -1,22 +1,22 @@ ;;;; raylib [core] example - window should close ;;;; ;;;; examples/core/core_window_should_close.c. Needed set-exit-key, and one -;;;; enum member to go with it: raylib.flan's `Key` now has `null 0`, read off +;;;; enum member to go with it: raylib.fln's `Key` now has `null 0`, read off ;;;; KEY_NULL in raylib.h. The binding is hand-written rather than taken from ;;;; the generated half because the Flan face differs — raylib declares ;;;; `void SetExitKey(int key)` and the generated line therefore takes an i32, -;;;; where this one takes a Key, so `(rl/set-exit-key :key-null)` is checked +;;;; where this one takes a Key, so `rl/set-exit-key(:key-null)` is checked ;;;; against the enum and `:nul` is a compile error instead of a 0. ;;;; ;;;; The whole example is about what window-should-close means. It is not a ;;;; flag raylib latches: it is "the close button was clicked, or the exit key ;;;; is down", recomputed each frame, and it goes back to false on its own. ;;;; That is what lets this program ask for confirmation and then carry on — -;;;; and it is also why the loop is driven by a `defonce` of its own rather +;;;; and it is also why the loop is driven by a `once` of its own rather ;;;; than by the predicate, which is the one structural difference from every ;;;; other example in this directory. ;;;; -;;;; `(set-exit-key :null)` takes ESC away from raylib so the program can read +;;;; `set-exit-key(:null)` takes ESC away from raylib so the program can read ;;;; it itself. The window's X button still works and is still what ;;;; window-should-close reports. @@ -47,9 +47,8 @@ fn main() -> () if exit-requested if rl/is-key-pressed(:key-y) exiting = true - else - if rl/is-key-pressed(:key-n) - exit-requested = false + elif rl/is-key-pressed(:key-n) + exit-requested = false ;; Draw rl/with-drawing: rl/clear-background(rl/raywhite) diff --git a/examples/core-world-screen.fln b/examples/core-world-screen.fln index 24e0c0a9..2e6cfe1a 100644 --- a/examples/core-world-screen.fln +++ b/examples/core-world-screen.fln @@ -8,7 +8,7 @@ ;;;; none of them, and the generated half grew the cubes, spheres, cylinders ;;;; and billboards along with the eight lines this example needs. ;;;; -;;;; Hand-written in raylib.flan rather than generated, and why each: +;;;; Hand-written in raylib.fln rather than generated, and why each: ;;;; ;;;; begin-mode-3d / end-mode-3d a begin/end pair inside a frame, the ;;;; class docs/PORTING.md §1 names, and taken @@ -51,7 +51,7 @@ fn main() -> () ;; enum's members right here and a misspelt projection is a compile error ;; rather than a 0. raylib's field is `int` and the layout is unchanged — ;; an enum is four bytes either way. - camera = rl/Camera3D({.position rl/Vector3{.x 10.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective}) + camera = rl/Camera3D{.position rl/Vector3{.x 10.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective} cube = rl/Vector3{.x 0.0 .y 0.0 .z 0.0} ;; The mouse becomes the camera's, not a pointer's. rl/disable-cursor() diff --git a/examples/digits.fln b/examples/digits.fln index c4d8e8ce..611b14b7 100644 --- a/examples/digits.fln +++ b/examples/digits.fln @@ -7,12 +7,12 @@ ;;;; allocator to build one in. So a number was drawn one glyph at a time out ;;;; of a `[10 string]` table. ;;;; -;;;; `(string b)` closed that. It is the mirror of `(bytes-view s)` and costs no +;;;; `string(b)` closed that. It is the mirror of `bytes-view(s)` and costs no ;;;; instructions — a `string` and a `[u8]` are the same 16-byte %slice — so -;;;; `(string (i64->bytes n))` draws in one call and the table, the per-glyph +;;;; `string(i64->bytes(n))` draws in one call and the table, the per-glyph ;;;; pen and the digit arithmetic behind them are gone. ;;;; -;;;; What is left is the part `(string ...)` does not answer, which is +;;;; What is left is the part `string(...)` does not answer, which is ;;;; *formatting*: `i64->bytes` has no field width, so "%03i" still has to be ;;;; assembled, and `f64->bytes` is `%g` and not "%.02f", so a fixed number of ;;;; decimal places still has to be split and drawn in two pieces. Those two @@ -25,8 +25,8 @@ ;;;; name anyway. ;;;; ;;;; `i64->bytes` and `f64->bytes` put their text in the temp allocator, where -;;;; it lasts until the next `(free-temp)`. A program drawing these every frame -;;;; calls `(free-temp)` once per frame, after drawing, and clones any text it +;;;; it lasts until the next `free-temp()`. A program drawing these every frame +;;;; calls `free-temp()` once per frame, after drawing, and clones any text it ;;;; keeps longer. ;;;; ;;;; Everything here needs a window: `measure-text` answers 0 for every string diff --git a/examples/models-box-collisions.fln b/examples/models-box-collisions.fln index 520125b4..1fd87926 100644 --- a/examples/models-box-collisions.fln +++ b/examples/models-box-collisions.fln @@ -10,11 +10,11 @@ ;;;; ;;;; That aggregate is BoundingBox, and it is two Vector3s and nothing else — ;;;; no owned pointer, no array, no lifetime. One `defstruct` in -;;;; vendor/raylib/raylib.flan un-refuses four raylib functions at once +;;;; vendor/raylib/raylib.fln un-refuses four raylib functions at once ;;;; (CheckCollisionBoxes, CheckCollisionBoxSphere, DrawBoundingBox and ;;;; GetRayCollisionBox), and that is the cheapest widening of the 3D surface ;;;; available anywhere in the tree. Ray and RayCollision went in beside it -;;;; for examples/core-3d-picking.flan and for the same reason. +;;;; for examples/core-3d-picking.fln and for the same reason. ;;;; ;;;; So the answer to "is a models example just a binding exercise" is: the ;;;; ones that need Model are, and this one is the counterexample. What @@ -57,7 +57,7 @@ const enemy-sphere-size: f32 = 1.5 ;; ;; It used to be eight expressions of field arithmetic here too; it is the ;; half-extent subtracted and added now that the package carries vector -;; arithmetic — see vendor/raylib/vector.flan, which is Flan and not C +;; arithmetic — see vendor/raylib/vector.fln, which is Flan and not C ;; because raymath is `static inline` and has no symbol to bind. fn box-around(centre: rl/Vector3, size: rl/Vector3) -> rl/BoundingBox let half = rl/v3-scale(size, 0.5) @@ -68,9 +68,9 @@ fn main() -> () "raylib [models] example - box collisions") defer rl/close-window() ;; The C writes this camera as a brace initialiser with a trailing 0 for the - ;; projection, which is CAMERA_PERSPECTIVE. Named here, because the defenum + ;; projection, which is CAMERA_PERSPECTIVE. Named here, because the enum ;; exists precisely so that the 0 does not have to be remembered. - camera = rl/Camera3D({.position rl/Vector3{.x 0.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective}) + camera = rl/Camera3D{.position rl/Vector3{.x 0.0 .y 10.0 .z 10.0} .target rl/Vector3{.x 0.0 .y 0.0 .z 0.0} .up rl/Vector3{.x 0.0 .y 1.0 .z 0.0} .fovy 45.0 .projection :projection-perspective} player-position = rl/Vector3{.x 0.0 .y 1.0 .z 2.0} player-size = rl/Vector3{.x 1.0 .y 2.0 .z 1.0} player-color = rl/green diff --git a/examples/shapes-basic-shapes.fln b/examples/shapes-basic-shapes.fln index c8c73906..af34d674 100644 --- a/examples/shapes-basic-shapes.fln +++ b/examples/shapes-basic-shapes.fln @@ -7,17 +7,17 @@ ;;;; poly draws — in one frame, beside the four the core examples already ;;;; exercise. Every one of them came out of the generated half of the ;;;; bindings and none needed a new line anywhere; that is the result worth -;;;; recording, because the whole point of a committed generated.flan is that +;;;; recording, because the whole point of a committed generated.fln is that ;;;; a build with no FLAN_RAYLIB_H set can draw with all of it. ;;;; ;;;; What it is actually a test of. The gradient calls are the first thing in ;;;; the corpus to pass *two* Colors in one call, and draw-triangle is the ;;;; first to pass three Vector2s. A struct argument crosses the FFI by -;;;; pointer into a generated shim (vendor/raylib/raylib.flan's header note), +;;;; pointer into a generated shim (vendor/raylib/raylib.fln's header note), ;;;; so the arity of that copying is what a call with several small structs in ;;;; a row puts under load. Nothing here can be asserted headless — every line ;;;; needs a GL context — so the check is the link and the screen, which is -;;;; what the Shapes comment in raylib.flan already says about this family. +;;;; what the Shapes comment in raylib.fln already says about this family. ;;;; ;;;; The one deliberate difference from the C: the C writes `screenWidth/4*2` ;;;; and `screenWidth/4.0f*3.0f` for the same column and gets 400 and 600 out diff --git a/examples/shapes-collision-area.fln b/examples/shapes-collision-area.fln index 7709409c..183939ba 100644 --- a/examples/shapes-collision-area.fln +++ b/examples/shapes-collision-area.fln @@ -40,9 +40,9 @@ fn main() -> () rl/init-window(screen-width, screen-height, "raylib [shapes] example - collision area") defer rl/close-window() - box-a = rl/Rectangle({.x 10.0, .y f32(screen-height) / 2.0 - 50.0, .width 200.0, .height 100.0}) + box-a = rl/Rectangle{.x 10.0, .y f32(screen-height) / 2.0 - 50.0, .width 200.0, .height 100.0} box-a-speed-x = 4 - box-b = rl/Rectangle({.x f32(screen-width) / 2.0 - 30.0, .y f32(screen-height) / 2.0 - 30.0, .width 60.0, .height 60.0}) + box-b = rl/Rectangle{.x f32(screen-width) / 2.0 - 30.0, .y f32(screen-height) / 2.0 - 30.0, .width 60.0, .height 60.0} ;; A fresh Rectangle is four zeroes, which is the C's `= { 0 }`. It is never ;; drawn before the first collision sets it. box-collision = rl/Rectangle{.x 0.0 .y 0.0 .width 0.0 .height 0.0} @@ -63,14 +63,12 @@ fn main() -> () box-b.y = f32(rl/get-mouse-y()) - box-b.height / 2.0 if box-b.x + box-b.width >= f32(rl/get-screen-width()) box-b.x = f32(rl/get-screen-width()) - box-b.width - else - if box-b.x <= 0.0 - box-b.x = 0.0 + elif box-b.x <= 0.0 + box-b.x = 0.0 if box-b.y + box-b.height >= f32(rl/get-screen-height()) box-b.y = f32(rl/get-screen-height()) - box-b.height - else - if box-b.y <= f32(screen-upper-limit) - box-b.y = f32(screen-upper-limit) + elif box-b.y <= f32(screen-upper-limit) + box-b.y = f32(screen-upper-limit) collision = rl/check-collision-recs(box-a, box-b) ;; Only meaningful while they touch: raylib answers a zero rectangle for ;; two boxes that do not, and the C leaves the previous one in place diff --git a/examples/shapes-following-eyes.fln b/examples/shapes-following-eyes.fln index fd9683f1..de59be58 100644 --- a/examples/shapes-following-eyes.fln +++ b/examples/shapes-following-eyes.fln @@ -18,7 +18,7 @@ ;;;; file. ;;;; ;;;; That measurement is what decided the answer, and the answer landed: -;;;; vendor/raylib/vector.flan is raymath written in Flan, since a C shim +;;;; vendor/raylib/vector.fln is raymath written in Flan, since a C shim ;;;; re-exporting the inlines would have bought identical arithmetic at the ;;;; price of a compilation unit and a second place raylib's semantics live. ;;;; The measurement is left standing rather than rewritten away — one @@ -69,7 +69,7 @@ fn track(mouse: rl/Vector2, centre: rl/Vector2) -> rl/Vector2 else let d = rl/v2-sub(mouse, centre) angle = atan2-f32(d.y, d.x) - rl/Vector2({.x centre.x + limit * cos-f32(angle), .y centre.y + limit * sin-f32(angle)}) + rl/Vector2{.x centre.x + limit * cos-f32(angle), .y centre.y + limit * sin-f32(angle)} fn main() -> () rl/init-window(screen-width, screen-height, @@ -78,8 +78,8 @@ fn main() -> () ;; The C reads these off get-screen-width/get-screen-height after the window ;; is open rather than off the constants, and so does this: on a high-DPI ;; display the two can differ. - sclera-left = rl/Vector2({.x f32(rl/get-screen-width()) / 2.0 - 100.0, .y f32(rl/get-screen-height()) / 2.0}) - sclera-right = rl/Vector2({.x f32(rl/get-screen-width()) / 2.0 + 100.0, .y f32(rl/get-screen-height()) / 2.0}) + sclera-left = rl/Vector2{.x f32(rl/get-screen-width()) / 2.0 - 100.0, .y f32(rl/get-screen-height()) / 2.0} + sclera-right = rl/Vector2{.x f32(rl/get-screen-width()) / 2.0 + 100.0, .y f32(rl/get-screen-height()) / 2.0} iris-left = sclera-left iris-right = sclera-right rl/set-target-fps(60) diff --git a/examples/text-codepoints-loading.fln b/examples/text-codepoints-loading.fln index feb51819..2709bf20 100644 --- a/examples/text-codepoints-loading.fln +++ b/examples/text-codepoints-loading.fln @@ -19,7 +19,7 @@ ;;;; come back out of LoadCodepoints as the right 54, and as 49 distinct ones. ;;;; Nothing in the ;;;; language claims to know what a character is — a `string` is bytes and a -;;;; `[u8]` is the same bytes, which `(string ...)` and `(bytes-view ...)` say in +;;;; `[u8]` is the same bytes, which `string(...)` and `bytes-view(...)` say in ;;;; both directions — and that turns out to be exactly the right amount of ;;;; opinion for this. The count below is a count of codepoints because raylib ;;;; decoded them, not because Flan did. @@ -37,7 +37,7 @@ ;;;; the bytes in front of that pointer belong to the allocator and not ;;;; to the text. It did not crash; it read rubbish and answered 0, which ;;;; is the worst of the available outcomes. The repair is a binding that -;;;; says `(Ptr u8)` and means it, which the header check refused until +;;;; says `Ptr(u8)` and means it, which the header check refused until ;;;; lib/cimport.ml's `agrees` grew the pointer arm its own comment had ;;;; been promising. `rl/get-codepoint-previous` is that binding and ;;;; `step-back` below is now one call to it. @@ -126,7 +126,7 @@ fn collect-unique(codepoints: [i32]) -> () ;; The codepoint starting at `off`, and its size in bytes through `size-out`. ;; -;; `(string (slice b off (length b)))` is the whole of what the C's `ptr` +;; `string(slice(b, off, length(b)))` is the whole of what the C's `ptr` ;; is: the tail of the text from here on. It costs nothing to say — a `string` and a ;; `[u8]` are the same two words — and the shim NUL-terminates a copy of it ;; for the duration of the call, which is all GetCodepointNext wants, because @@ -160,7 +160,7 @@ fn step-forward(off: i32) -> i32 ;; string — which reaches C as a copy — is the one thing it must not be ;; handed. `rl/get-codepoint-previous` takes the bytes and an offset instead ;; and builds the interior pointer itself; see the note beside it in -;; vendor/raylib/raylib.flan. What comes back through `size` is the length of +;; vendor/raylib/raylib.fln. What comes back through `size` is the length of ;; the codepoint *behind* `off`, so the previous offset is the difference. ;; ;; This used to be a hand-written walk over continuation bytes — step back one @@ -179,7 +179,7 @@ fn step-back(off: i32) -> i32 once font: rl/Font -;; Whether the TTF was there, asked once. A `defonce` and not the call itself +;; Whether the TTF was there, asked once. A `once` and not the call itself ;; in the draw loop: is-path-file is a stat, and a syscall per frame to answer a ;; question whose answer cannot change while the program runs is exactly what ;; the per-frame rule in docs/PORTING.md is about. diff --git a/examples/text-input-box.fln b/examples/text-input-box.fln index b2a4ce66..a1fcc0ce 100644 --- a/examples/text-input-box.fln +++ b/examples/text-input-box.fln @@ -13,7 +13,7 @@ ;;;; the second character of a fast pair. ;;;; ;;;; raylib says "empty" by answering 0, and rl/get-char-pressed is now a -;;;; Flan wrapper that says it with None instead — see raylib.flan, "Draining +;;;; Flan wrapper that says it with None instead — see raylib.fln, "Draining ;;;; raylib's two input queues". What that buys is visible below: the C ;;;; shape, which this file had, reads the queue in *two* places, once to ;;;; prime the loop and once at the bottom of the body, and a `> 0` in @@ -21,9 +21,9 @@ ;;;; Option shape reads it in one place, and the case where there is no ;;;; character is a branch the checker knows about rather than a comparison. ;;;; -;;;; The second is set-mouse-cursor, which needed a new defenum. raylib's +;;;; The second is set-mouse-cursor, which needed a new enum. raylib's ;;;; header says `int cursor` and means one of eleven MOUSE_CURSOR_ values, so -;;;; the Flan face is `MouseCursor` — hand-written in raylib.flan beside the +;;;; the Flan face is `MouseCursor` — hand-written in raylib.fln beside the ;;;; other cursor calls, excluded from the generated half, and mapped in ;;;; `bindings` so the eleven members are checked against the header. See the ;;;; comment there: this call is made on every frame off a hover test, and the @@ -66,7 +66,7 @@ fn main() -> () defer rl/close-window() name = array(max-input-chars, u8) letter-count = 0 - text-box = rl/Rectangle({.x f32(screen-width) / 2.0 - 100.0, .y 180.0, .width 225.0, .height 50.0}) + text-box = rl/Rectangle{.x f32(screen-width) / 2.0 - 100.0, .y 180.0, .width 225.0, .height 50.0} mouse-on-text = false frames-counter = 0 rl/set-target-fps(60) diff --git a/examples/text-rectangle-bounds.fln b/examples/text-rectangle-bounds.fln index 6f995874..2c2f86d4 100644 --- a/examples/text-rectangle-bounds.fln +++ b/examples/text-rectangle-bounds.fln @@ -5,9 +5,9 @@ ;;;; form was built rather than an application found for it afterwards. ;;;; ;;;; Its inner loop reads `font.recs[index]` and `font.glyphs[index]`. Both -;;;; fields are `(Ptr T)` — that is what raylib hands back and there is nothing +;;;; fields are `Ptr(T)` — that is what raylib hands back and there is nothing ;;;; else it could hand back — and a pointer from C carries no length, so -;;;; `(at (.recs font) i)` answered `(Ptr rl/Rectangle) cannot be indexed` and +;;;; `font.recs[i]` answered `Ptr(rl/Rectangle) cannot be indexed` and ;;;; the whole example stopped there. Element 0 through `deref` was the entire ;;;; readable surface of a two-hundred-glyph array. ;;;; @@ -35,7 +35,7 @@ ;;;; wrap, which is the thing the example is about. ;;;; ;;;; - `GetCodepoint` wants a pointer into the middle of the text, and Flan has -;;;; the operation the C is spelling by hand: `(string (slice b i n))` is the +;;;; the operation the C is spelling by hand: `string(slice(b, i, n))` is the ;;;; tail from `i` with no copy and no pointer arithmetic. It is not free: ;;;; the shim NUL-terminates a copy on the way into C, into a 256-byte stack ;;;; buffer or a malloc when the tail is longer — and this message is 284 @@ -158,7 +158,7 @@ fn main() -> () let text = bytes-view(message) is-resizing = false is-word-wrap = true - let container = rl/Rectangle({.x 25.0, .y 25.0, .width f32(screen-width) - 50.0, .height f32(screen-height) - 250.0}) + let container = rl/Rectangle{.x 25.0, .y 25.0, .width f32(screen-width) - 50.0, .height f32(screen-height) - 250.0} let resizer = rl/Rectangle{.x 0.0 .y 0.0 .width 14.0 .height 14.0} let min-width = f32(60.0) min-height = f32(60.0) @@ -185,9 +185,8 @@ fn main() -> () let h = container.height + (mouse.y - last-mouse.y) container.width = clamp(w, min-width, max-width) container.height = clamp(h, min-height, max-height) - else - if rl/is-mouse-button-down(:mouse-left) and rl/check-collision-point-rec(mouse, resizer) - is-resizing = true + elif rl/is-mouse-button-down(:mouse-left) and rl/check-collision-point-rec(mouse, resizer) + is-resizing = true resizer.x = container.x + container.width - 17.0 resizer.y = container.y + container.height - 17.0 last-mouse = mouse diff --git a/examples/text-writing-anim.fln b/examples/text-writing-anim.fln index fd52795b..2d3ac3e6 100644 --- a/examples/text-writing-anim.fln +++ b/examples/text-writing-anim.fln @@ -6,14 +6,14 @@ ;;;; DrawText(TextSubtext(message, 0, framesCounter/10), ...) ;;;; ;;;; TextSubtext is in raylib.h and is not in the bindings, on the rule -;;;; raylib.flan states for the whole Text* family: it answers a `char *` into +;;;; raylib.fln states for the whole Text* family: it answers a `char *` into ;;;; a rotating static buffer, and declare-c refuses a returned pointer to ;;;; memory the caller does not own. There is no missing line to add — the ;;;; binding would be wrong at any signature. ;;;; ;;;; And it does not matter, because Flan has the operation as a primitive. -;;;; `(slice a lo hi)` takes a view of an array, `(string b)` reinterprets the -;;;; bytes as a string at no cost, and `(string (slice message 0 n))` is +;;;; `slice(a, lo, hi)` takes a view of an array, `string(b)` reinterprets the +;;;; bytes as a string at no cost, and `string(slice(message, 0, n))` is ;;;; TextSubtext with the static buffer removed — no copy, no shared state, no ;;;; rotation to run out of. Porting the example is therefore how the gap gets ;;;; *closed* rather than reported: the C's workaround for not having slices @@ -28,8 +28,8 @@ ;;;; the C's, and it costs one `min`. ;;;; ;;;; The message is a `[u8]` and not a `string` because `slice` takes an array -;;;; or a slice; `(bytes-view "…")` is the bridge in the other direction from -;;;; `(string …)` and costs nothing either. The embedded newline is written as +;;;; or a slice; `bytes-view("…")` is the bridge in the other direction from +;;;; `string(…)` and costs nothing either. The embedded newline is written as ;;;; an escape, and raylib's draw-text breaks the line on it. import rl "vendor:raylib" diff --git a/examples/textures-fog-of-war.fln b/examples/textures-fog-of-war.fln index b8f25460..29011030 100644 --- a/examples/textures-fog-of-war.fln +++ b/examples/textures-fog-of-war.fln @@ -8,8 +8,8 @@ ;;;; bilinear sampler doing the interpolation. With the default ;;;; :filter-point the same program draws 32-pixel squares. ;;;; -;;;; That is what needed adding: `TextureFilter`, a new defenum in -;;;; vendor/raylib/raylib.flan, with set-texture-filter moved from the +;;;; That is what needed adding: `TextureFilter`, a new enum in +;;;; vendor/raylib/raylib.fln, with set-texture-filter moved from the ;;;; generated half to the hand-written one and mapped in `bindings` so its ;;;; six members are checked against raylib.h. The header says `int filter` ;;;; and there is nothing in an `int` to say that 1 is the interesting value; @@ -117,14 +117,14 @@ fn main() -> () ;; Light the square around the player, skipping anything off the map. ;; Without that test this reads and writes outside the array, which in the ;; C is undefined and here is a bounds trap — the same bug, reported. - let y-2 = player-tile-y - player-tile-visibility - while y-2 < player-tile-y + player-tile-visibility + let vis-y = player-tile-y - player-tile-visibility + while vis-y < player-tile-y + player-tile-visibility let x = player-tile-x - player-tile-visibility while x < player-tile-x + player-tile-visibility - if x >= 0 and x < tiles-x and y-2 >= 0 and y-2 < tiles-y - tile-fog[y-2 * tiles-x + x] = 1 + if x >= 0 and x < tiles-x and vis-y >= 0 and vis-y < tiles-y + tile-fog[vis-y * tiles-x + x] = 1 x += 1 - y-2 += 1 + vis-y += 1 ;; Draw the fog into its own little target first, at one pixel per tile. ;; blank is alpha 0, so a tile that is neither unseen nor remembered ;; leaves nothing behind and the map below shows through unmodified. diff --git a/examples/textures-image-generation.fln b/examples/textures-image-generation.fln index fba55d12..4d1c992c 100644 --- a/examples/textures-image-generation.fln +++ b/examples/textures-image-generation.fln @@ -8,7 +8,7 @@ ;;;; of its pixels. ;;;; ;;;; What it puts under load that nothing else does. An Image is the one -;;;; struct in raylib.flan that carries a pointer to memory raylib owns — +;;;; struct in raylib.fln that carries a pointer to memory raylib owns — ;;;; `data (Ptr u8)` — and it is returned by value, so every one of these nine ;;;; calls hands back a 24-byte aggregate through the shim's out-pointer with ;;;; a live heap block inside it. The corpus had crossed an Image before diff --git a/examples/textures-image-processing.fln b/examples/textures-image-processing.fln index dfcf3973..d5d12931 100644 --- a/examples/textures-image-processing.fln +++ b/examples/textures-image-processing.fln @@ -9,16 +9,16 @@ ;;;; had ever handed raylib a buffer and asked it to rewrite the buffer. ;;;; ;;;; What that puts under load, and it is a different thing from the nine -;;;; Gen* calls in examples/textures-image-generation.flan: **in-place +;;;; Gen* calls in examples/textures-image-generation.fln: **in-place ;;;; mutation of an Image through a (Ptr Image)**. Eight of the nine filters ;;;; take the image by pointer and change `data` under the caller — ;;;; image-format and image-blur-gaussian *reallocate* it, so the pointer the -;;;; caller held before the call is freed by it. raylib.flan's Images section +;;;; caller held before the call is freed by it. raylib.fln's Images section ;;;; already says that the by-value/by-pointer split is raylib's own and is ;;;; kept deliberately so a caller can see which calls change what they are ;;;; given; this is the example that depends on it being right. ;;;; -;;;; What needed adding: `PixelFormat`, a defenum in vendor/raylib/raylib.flan, +;;;; What needed adding: `PixelFormat`, a enum in vendor/raylib/raylib.fln, ;;;; with image-format moved from the generated half to the hand-written one ;;;; and mapped in `bindings` so its twenty-four members are checked against ;;;; raylib.h. The C's line is @@ -67,9 +67,9 @@ const screen-height = 450 const num-processes = 9 -;; The C's ImageProcess enum. Flan's defenum lowers to an i32 for C's benefit -;; and these never cross to C, so they are defconsts — the same choice -;; examples/textures-image-generation.flan made for its texture index. +;; The C's ImageProcess enum. Flan's enum lowers to an i32 for C's benefit +;; and these never cross to C, so they are consts — the same choice +;; examples/textures-image-generation.fln made for its texture index. const proc-none = 0 const proc-color-grayscale = 1 const proc-color-tint = 2 @@ -109,7 +109,7 @@ fn make-source-image() -> rl/Image img ;; The C's `switch (currentProcess)`. A cond here, as in -;; examples/textures-image-generation.flan, and for the same reason: Flan has +;; examples/textures-image-generation.fln, and for the same reason: Flan has ;; no switch and the chain reads the same. ;; ;; Every arm takes the image by pointer and every arm rewrites the buffer the @@ -188,14 +188,14 @@ fn main() -> () mouse-hover-rec = -1 toggle-recs = array(num-processes, rl/Rectangle) for i in range(num-processes) - toggle-recs[i] = rl/Rectangle({.x 40.0 .y f32(50 + 32 * i) .width 150.0 .height 30.0}) + toggle-recs[i] = rl/Rectangle{.x 40.0 .y f32(50 + 32 * i) .width 150.0 .height 30.0} rl/set-target-fps(60) until rl/window-should-close() ;; Update ;; ;; The C computes mouseHoverRec with a loop whose `else` clause resets it ;; on every miss and whose `break` leaves it set on a hit. As in - ;; examples/textures-mouse-painting.flan the reset is lifted out in front + ;; examples/textures-mouse-painting.fln the reset is lifted out in front ;; and the loop only ever sets it, which is the same answer said plainly — ;; the nine rectangles do not overlap, so there is no first-hit-wins rule ;; to preserve. diff --git a/examples/textures-mouse-painting.fln b/examples/textures-mouse-painting.fln index 60fcaa06..799ec463 100644 --- a/examples/textures-mouse-painting.fln +++ b/examples/textures-mouse-painting.fln @@ -7,14 +7,14 @@ ;;;; load-image-from-texture → image-flip-vertical → export-image ;;;; ;;;; Nothing in the corpus had run it. image-from-image has a headless -;;;; acceptance case and sand.flan loads images the other way, but the path +;;;; acceptance case and sand.fln loads images the other way, but the path ;;;; that reads a render target's pixels back into CPU memory, corrects for ;;;; GL's bottom-up rows and encodes a PNG had never been exercised at all. ;;;; All three came out of the generated half of the bindings; nothing needed ;;;; adding for this file. ;;;; ;;;; The flip is the same fact as the negative source height in -;;;; examples/textures-fog-of-war.flan, met from the other side: on screen the +;;;; examples/textures-fog-of-war.fln, met from the other side: on screen the ;;;; canvas is drawn with a negative-height source rectangle so GL's bottom-up ;;;; rows come out the right way up, and on save there is no source rectangle ;;;; to negate, so the pixels are turned over in memory instead. A program @@ -92,7 +92,7 @@ fn main() -> () ;; 30 wide with a 2-pixel gap, starting 10 from the left. colors-recs = array(max-colors-count, rl/Rectangle) for i in range(max-colors-count) - colors-recs[i] = rl/Rectangle({.x 10.0 + 32.0 * f32(i), .y 10.0, .width 30.0, .height 30.0}) + colors-recs[i] = rl/Rectangle{.x 10.0 + 32.0 * f32(i), .y 10.0, .width 30.0, .height 30.0} color-selected = 0 color-selected-prev = 0 color-mouse-hover = 0 @@ -117,9 +117,8 @@ fn main() -> () let mouse-pos = rl/get-mouse-position() if rl/is-key-pressed(:key-right) color-selected += 1 - else - if rl/is-key-pressed(:key-left) - color-selected -= 1 + elif rl/is-key-pressed(:key-left) + color-selected -= 1 color-selected = clamp(color-selected, 0, max-colors-count - 1) ;; Which swatch the pointer is over, or -1. See the header comment: the ;; reset is here rather than in an else branch inside the loop. @@ -156,10 +155,9 @@ fn main() -> () if mouse-pos.y > 50.0 rl/draw-circle(i32(mouse-pos.x), i32(mouse-pos.y), brush-size, colors[0]) - else - if rl/is-mouse-button-released(:mouse-right) and mouse-was-pressed - color-selected = color-selected-prev - mouse-was-pressed = false + elif rl/is-mouse-button-released(:mouse-right) and mouse-was-pressed + color-selected = color-selected-prev + mouse-was-pressed = false btn-save-mouse-hover = rl/check-collision-point-rec(mouse-pos, btn-save-rec) ;; The round trip. See the header comment for why the flip is here and ;; not on the draw. diff --git a/lib/build.ml b/lib/build.ml index af69d4be..af4f255f 100644 --- a/lib/build.ml +++ b/lib/build.ml @@ -919,7 +919,7 @@ let executable ?(opts = default) ?(csrcs = []) ?(lflags = []) ?(pnames = []) a release build calls into it — the compiler only emits a registry lookup for a name the host was not built with, which cannot arise without cells — but the agent package's C refers to it, and a package's C sources are - collected whatever [main] does. Leaving it out made [flan build sand.flan] + collected whatever [main] does. Leaving it out made [flan build sand.fln] fail at the link with an undefined symbol, which reads as a compiler bug rather than as a missing flag. The table is BSS, so this costs address space and not binary size, and [-rdynamic] and the cells are still what diff --git a/lib/dev.ml b/lib/dev.ml index 6897d2a8..de4aa469 100644 --- a/lib/dev.ml +++ b/lib/dev.ml @@ -1427,7 +1427,7 @@ let eval_expr_at t ~code ~origin ~pause ~at = and its only other reader is the select in [accept_loop] — which is not running, because it is further up this very call stack, inside [serve]. A program that prints as it goes (and a - game loop prints as it goes; sand.flan does) fills those 64K + game loop prints as it goes; sand.fln does) fills those 64K while the module below was being built, and the game thread is then stopped inside [flan_write_stdout], in an [fwrite] that will not return until somebody reads. It never reaches the @@ -3344,7 +3344,7 @@ let reg_listing t ~verb ~note = Locals were the half the shadow stack was built for; these are arguably the more useful half in this language. A game keeps most of its state in - top-level [defonce]s and sand.flan holds its entire grid that way, so "what + top-level [defonce]s and sand.fln holds its entire grid that way, so "what is the program's state right now" is a question about globals and there was nowhere to ask it. diff --git a/lib/load.ml b/lib/load.ml index 1ac7734c..95420256 100644 --- a/lib/load.ml +++ b/lib/load.ml @@ -45,7 +45,7 @@ type t = { owns. A file on disk does not say what it is called from outside — the *importer* chooses that — so this is the only place the answer exists, and a REPL editing a package's source needs it to know that [poll] typed in - vendor/agent/agent.flan means [agent/poll] to the running program. *) + vendor/agent/agent.fln means [agent/poll] to the running program. *) pkgs : pkg list; (* Every [defmacro] the imported packages declare, qualified under the alias each was imported as and quasiquote-desugared, ready for @@ -95,7 +95,7 @@ let rec find_collection dir name = if String.equal parent dir then None else find_collection parent name (* A package is a directory, or a single source file named outright. The file - form is for the program that is also a library: sand.flan sits beside three + form is for the program that is also a library: sand.fln sits beside three other loose .flan files, so naming its directory would import all four, and moving it into one of its own would be arranging the tree around a limitation. A file carries no [.c] and no [link] — those belong to a diff --git a/lib/prelude.ml b/lib/prelude.ml index 8a227ded..d2f0041a 100644 --- a/lib/prelude.ml +++ b/lib/prelude.ml @@ -106,7 +106,7 @@ let source = {flan| ;; what it buys is a *different element*, silently. ;; ;; The restarts that matter are the ones the program already established — a -;; frame loop's `continue`, sand.flan's shape — and they are on the restart +;; frame loop's `continue`, sand.fln's shape — and they are on the restart ;; stack and reachable from a handler or from the break loop without anything ;; being pushed here. That is plan.org's "restarts go at the resync point, ;; once", with allocation and file failure as the named exceptions and this on @@ -985,7 +985,7 @@ let source = {flan| ;; ;; They are here anyway, because the alternative on offer today is worse: a ;; caller that wants an angle writes the same two `declare` lines at the top -;; of its own file (examples/core-input-gestures-testbed.flan did, before +;; of its own file (examples/core-input-gestures-testbed.fln did, before ;; this), which is the identical libm call with the identical caveat and ;; nobody's name on it. One copy with the caveat written down beats a copy per ;; file with none. @@ -1217,7 +1217,7 @@ let source = {flan| ;; **Which face to use.** The i64 of nanoseconds is exact and is what a ;; difference should be taken in. The f64 of seconds is what a frame loop ;; wants, and it is the shape raylib's `get-time` already answers with -;; (vendor/raylib/raylib.flan, `(declare-c get-time [] f64 "GetTime")`), so the +;; (vendor/raylib/raylib.fln, `(declare-c get-time [] f64 "GetTime")`), so the ;; two mix without a conversion at every site. The monotonic origin is latched ;; at the first read rather than being boot — see runtime/flan_rt.c — so that ;; the f64 stays integer-exact in nanoseconds for a hundred days of process @@ -2469,7 +2469,7 @@ let source = {flan| ;; Whether a form is the empty list, (). [form-items] cannot answer this: it ;; returns the empty slice for a non-list too, so "no items" and "not a list" ;; arrive the same. A macro that has to tell `()` from a name needs the -;; difference — see vendor/raylib/modes.flan, where a lone () argument is a +;; difference — see vendor/raylib/modes.fln, where a lone () argument is a ;; body that was not written rather than a body of one form. (defn is-form-empty-list [f Form] bool (match f diff --git a/lib/session.ml b/lib/session.ml index 30f426b2..54910f12 100644 --- a/lib/session.ml +++ b/lib/session.ml @@ -398,7 +398,7 @@ let package_decls t = (* Which package a file being edited belongs to, if any. - A form typed into vendor/agent/agent.flan declares [poll], but the running + A form typed into vendor/agent/agent.fln declares [poll], but the running program only ever knew it as [agent/poll]: the alias is chosen by whatever imported the directory, and is written nowhere in the file itself. Without this the form splices as a brand-new unrelated name, the evaluation reports diff --git a/runtime/flan_dyn.c b/runtime/flan_dyn.c index d3c8fcbf..6c72f526 100644 --- a/runtime/flan_dyn.c +++ b/runtime/flan_dyn.c @@ -116,7 +116,7 @@ int8_t flan_vec_push(void *v, const void *elem, int64_t size, int64_t align, * * NaN-boxed, in a word. A double is *itself*: the 2^64 minus a NaN's worth of * bit patterns that are not quiet NaNs are read straight back as f64, at no - * cost, which is what a language where f64 is first class and where sand.flan + * cost, which is what a language where f64 is first class and where sand.fln * runs a physics loop wants. Everything else hides inside the quiet-NaN space. * * The box is sign bit + all-ones exponent + quiet bit, which is @@ -2927,7 +2927,7 @@ uint8_t flan_dyn_need_bool(flan_dyn v) { * box's kind was not what the program apparently expected. * * Once per *site*, not per value. These casts sit in per-cell-per-frame - * loops — sand.flan runs at 120fps — and a per-occurrence line would be a + * loops — sand.fln runs at 120fps — and a per-occurrence line would be a * flood rather than a diagnostic. The site is the [loc] text [check.ml] * passes in, and the table below is keyed on its *bytes* rather than its * address: the two backends emit their own constants for it and neither diff --git a/sand.fln b/sand.fln index 0489adb7..552c7817 100644 --- a/sand.fln +++ b/sand.fln @@ -64,8 +64,10 @@ fn settle(row: i32, col: i32) -> () 1 elif not is-right -1 + elif f32(rand()) < 0.5 + 1 else - if f32(rand()) < 0.5 then 1 else -1 + -1 grid[y, col + side] = grid[row, col] grid[row, col] = 0 velocity[y, col + side] = vel diff --git a/test/programs/pkg-hidden-main.flan b/test/programs/pkg-hidden-main.flan index 7d247f31..084ed18c 100644 --- a/test/programs/pkg-hidden-main.flan +++ b/test/programs/pkg-hidden-main.flan @@ -1,11 +1,11 @@ ;;;; A name the import did not bring. ;;;; -;;;; sand.flan declares a main and this imports it, so sand/main is a name +;;;; sand.fln declares a main and this imports it, so sand/main is a name ;;;; somebody might reasonably write — and is not one. Left to the checker it ;;;; would be "unknown name", which is true and unhelpful; the refusal has to ;;;; say the name is missing on purpose. Never built: the refusal is the test. -(import sand "../../sand.flan") +(import sand "../../sand.fln") (defn main [] i32 (sand/main) diff --git a/test/programs/pkg-shared.flan b/test/programs/pkg-shared.flan index 4f52442a..31691b8f 100644 --- a/test/programs/pkg-shared.flan +++ b/test/programs/pkg-shared.flan @@ -1,11 +1,11 @@ ;;;; One package reached along two routes. ;;;; -;;;; raylib is imported here and again by sand.flan, which this also imports. +;;;; raylib is imported here and again by sand.fln, which this also imports. ;;;; Loading it twice would declare every binding twice and be refused as a ;;;; collision, so a directory is read once and keyed by its real path. Nothing ;;;; calls into raylib, so nothing links it either. -(import sand "../../sand.flan") +(import sand "../../sand.fln") (import rl "vendor:raylib") (defn main [] i32 diff --git a/test/programs/raylib-codepoints.flan b/test/programs/raylib-codepoints.flan index f76b44fb..57a33b7f 100644 --- a/test/programs/raylib-codepoints.flan +++ b/test/programs/raylib-codepoints.flan @@ -36,7 +36,7 @@ ;;;; ;;;; Nothing here draws, so nothing here needs the TTF the example looks for. -(import cp "../../examples/text-codepoints-loading.flan") +(import cp "../../examples/text-codepoints-loading.fln") (import rl "vendor:raylib") (defconst max-walk 128) diff --git a/test/programs/raylib-image-processing.flan b/test/programs/raylib-image-processing.flan index 4e8de18f..815ff862 100644 --- a/test/programs/raylib-image-processing.flan +++ b/test/programs/raylib-image-processing.flan @@ -37,7 +37,7 @@ ;;;; at all, so there is nothing in them for an implementation to have an ;;;; opinion about. -(import ip "../../examples/textures-image-processing.flan") +(import ip "../../examples/textures-image-processing.fln") (import rl "vendor:raylib") ;; Three probes, chosen so that between them every shape and the background diff --git a/test/programs/virtual-controls-headless.flan b/test/programs/virtual-controls-headless.flan index 80ace528..58fd906b 100644 --- a/test/programs/virtual-controls-headless.flan +++ b/test/programs/virtual-controls-headless.flan @@ -26,7 +26,7 @@ ;;;; the four directions move the player the four different ways. A crossed ;;;; axis anywhere in nearest-button or move-player changes the hash. -(import vc "../../examples/core-input-virtual-controls.flan") +(import vc "../../examples/core-input-virtual-controls.fln") (import rl "vendor:raylib") ;; A sixtieth of a second, fixed. The real program uses get-frame-time, which diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index eb42c7ab..2d608e3e 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -278,28 +278,21 @@ module Pool = struct done end -(* sand.flan is the workspace's own program, edited by hand and not by this - suite, and three cases here compile it. It still calls the randomness - functions by names the prelude does not have, so those three cannot check - until it is brought up to date — and the fixture, rather than a comment, is - what says so: the moment sand.flan calls (rand) every case below runs again - with nothing to undo. The one thing that is not automatic is the sand hash, - which is stale whatever happens because the generator now answers 64 bits - per draw; its row says so where the number is. *) +(* sand.fln is the workspace's own program, edited by hand and not by this + suite, and several cases here compile it. It once called randomness + functions by names the prelude did not have, and was skipped until it + called real ones; it now calls `rand`, which the prelude does have, so + these cases run unconditionally. The one thing that is not automatic is + the sand hash, which is stale whatever happens because the generator now + answers 64 bits per draw; its row says so where the number is. *) let sand_checks = - match In_channel.with_open_bin "../sand.flan" In_channel.input_all with - (* The open paren is the test and not the bare name: sand.flan explains - itself in a comment that says rand-f32 too, and a guard that matched that - would go on skipping after the calls were fixed — a guard that can never - release is worse than no guard. *) - | src -> not (contains src "(rand-f32") + match In_channel.with_open_bin "../sand.fln" In_channel.input_all with + | _ -> true | exception _ -> false let () = if not sand_checks then - print_endline - "acceptance: skipping the cases that compile sand.flan — it calls \ - rand-f32, which is not a name"; + print_endline "acceptance: skipping the cases that compile sand.fln — it is not there"; match Sys.command "command -v clang > /dev/null 2>&1" with | 0 -> let exe = compile "../calc-me.flan" in @@ -2778,9 +2771,9 @@ let () = This used to be skipped without FLAN_RAYLIB_H, because the generated bindings only existed when a header was read. They are committed now — - vendor/raylib/generated.flan — so it runs on the same terms as every + vendor/raylib/generated.fln — so it runs on the same terms as every other raylib case here: libraylib linkable, and no raylib-devel. That is - the change stated as a test rather than as a claim. If generated.flan + the change stated as a test rather than as a claim. If generated.fln were ever regenerated empty or stale, this is what would say so, and it would say so on an ordinary machine rather than only on one with a header exported. *) @@ -3126,7 +3119,7 @@ let () = Texture2D notes above say it: glyph-padding is read by nothing raylib computes on the CPU, offset-y only moves a glyph when it is drawn, and of each atlas rectangle only `width` is ever looked at. Those four - fields rest on the header agreeing with raylib's and on sand.flan + fields rest on the header agreeing with raylib's and on sand.fln looking right, and on nothing else. *) let raylib_font_out = "valid yes\n\ @@ -3150,7 +3143,7 @@ let () = (* Again at -O0. Everything above runs through mem2reg, which launders a sloppy alloca; -O0 tests the IR actually emitted, so a disagreement between the two points at undefined behaviour rather than a typo. *) - (* sand.flan's simulation, headless. This is the milestone-4 acceptance + (* sand.fln's simulation, headless. This is the milestone-4 acceptance case: N frames from a seeded PRNG, one hash. It imports the sim package and not raylib, deliberately — a program that imports raylib links libraylib on every target, and this one is the version meant to run on @@ -3686,7 +3679,7 @@ let () = outputs "an imported package nothing calls, -O0" ~opt:"-O0" "programs/pkg-unused.flan" "ok\n"; (* A package may import a package, and one reached along two routes is read - once: pkg-shared imports sand.flan, which imports raylib, and imports + once: pkg-shared imports sand.fln, which imports raylib, and imports raylib itself. Loading it twice would declare every binding twice. *) if sand_checks then outputs "a package reached along two routes" "programs/pkg-shared.flan" @@ -4022,7 +4015,7 @@ let () = "programs/generic-map-reject.flan" "at $t = f64"; (* This one is refused either way, so the guard is about *which* refusal: - with sand.flan out of date the file stops at the import and the needle + with sand.fln out of date the file stops at the import and the needle below would pass on the wrong error. *) if sand_checks then refuses "a package's main is not visible" "programs/pkg-hidden-main.flan" @@ -6291,7 +6284,7 @@ level "1" of the program's three cross-kind cast *sites*, the third being the (f32 int-box) after the loop. That count is the whole reason the runtime carries a table of sites at all: these casts live in frame - loops, sand.flan's at 120fps, and a flood is not a diagnostic. + loops, sand.fln's at 120fps, and a flood is not a diagnostic. [run] merges stderr into stdout, so the warnings and the numbers come back in one string and the count is a count over it. *) diff --git a/test/test_dev.ml b/test/test_dev.ml index e7940991..89ba8cb1 100644 --- a/test/test_dev.ml +++ b/test/test_dev.ml @@ -670,13 +670,13 @@ let () = either. The daemon derives the package from the path, so the file this is sent with is the one the import qualified. *) let agent_file = - let p = "../vendor/agent/agent.flan" in + let p = "../vendor/agent/agent.fln" in try Unix.realpath p with Unix.Unix_error _ -> p in let r = request c (Printf.sprintf - "(:op \"eval\" :code \"(defstruct Blob [id i32])\" :file %s)" + "(:op \"eval\" :code \"struct Blob(id: i32)\" :file %s)" (Wire.quote agent_file)) in if status r <> "ok" then @@ -8924,7 +8924,7 @@ let () = half of the same claim and lives where it always did. *) (* ── A program that starts its agent late ────────────────────────── - The shape a real one has: sand.flan opens a window and starts the + The shape a real one has: sand.fln opens a window and starts the agent afterwards, so the program's own [(agent/start ...)] is seconds into the run. The merged session used to wait up to ten seconds for the socket *before* running its accept loop, which charged those seconds to diff --git a/test/test_flan.ml b/test/test_flan.ml index 59b8221e..bfdd2a08 100644 --- a/test/test_flan.ml +++ b/test/test_flan.ml @@ -860,8 +860,9 @@ let () = Printf.printf "FAIL %s does not parse: %s: %s\n" path (Loc.to_string loc) msg) (* dune runs tests in _build/default/test/; the corpus is declared as a - dep in test/dune and lands at the build root. *) - [ "../calc-me.flan"; "../sand.flan" ]; + dep in test/dune and lands at the build root. sand is .fln now + (decision 130), so it is not here — this reads the paren syntax only. *) + [ "../calc-me.flan" ]; Test_support.report ~label:"parse" () diff --git a/test/test_session.ml b/test/test_session.ml index f7bbcc17..7924856b 100644 --- a/test/test_session.ml +++ b/test/test_session.ml @@ -16,19 +16,15 @@ let () = Watchdog.arm ~seconds:600 "test_session" let fail fmt = Test_support.fail fmt let has = Test_support.contains -(* sand.flan is the workspace's own program, edited by hand and not by this +(* sand.fln is the workspace's own program, edited by hand and not by this suite, and three cases below read it: it is the file with imports, and it is - the single-file package. While it calls the randomness functions by names - the prelude does not have it does not check at all, and those three would be - reporting that rather than anything about a session. The fixture decides, - so there is nothing to undo once sand.flan is brought up to date. *) + the single-file package. It once called randomness functions by names the + prelude did not have; it now calls `rand`, which the prelude does have, so + these cases run unconditionally — see test_acceptance.ml, which guards on + the same file for the same reason. *) let sand_checks = - match In_channel.with_open_bin "../sand.flan" In_channel.input_all with - (* The open paren and not the bare name — see test_acceptance.ml, which - guards on the same file for the same reason: sand.flan names rand-f32 in - a comment as well, and matching that would leave these skipped for ever. - *) - | src -> not (has src "(rand-f32") + match In_channel.with_open_bin "../sand.fln" In_channel.input_all with + | _ -> true | exception _ -> false (* Every rejection is asserted on its reason, not just on the failure: the @@ -760,23 +756,24 @@ let () = keeps the *expanded* declarations, so the package's names are replaced in place rather than appended a second time and rejected as duplicates. *) if not sand_checks then - print_endline - "session: skipping the cases that read sand.flan — it calls rand-f32, \ - which is not a name" + print_endline "session: skipping the cases that read sand.fln — it is not there" else begin - let t, _ = Session.create ~file:"../sand.flan" () in - let src = In_channel.with_open_bin "../sand.flan" In_channel.input_all in + let t, _ = Session.create ~file:"../sand.fln" () in + let src = In_channel.with_open_bin "../sand.fln" In_channel.input_all in (* [~origin] is the buffer's own path and both editor paths send it (flan.el's `:file (or buffer-file-name "")`). Omitting it here was testing a request the editor never sends. It used to matter to this - case for a second reason — sand.flan embedded brush.png, and an embedded + case for a second reason — sand.fln embedded brush.png, and an embedded path resolves relative to the file the form is written in, so the default - origin of "" found nothing. sand.flan has no embed any more; the + origin of "" found nothing. sand.fln has no embed any more; the first reason is the one that stands. *) - (match Session.eval ~origin:"../sand.flan" t src with + (match + Source.with_code ~syntax:Source.Indented ~at:None (fun () -> + Session.eval ~origin:"../sand.fln" t src) + with | c -> if not (List.mem "game-draw" c.Session.fns) then - fail "reloading sand.flan did not include its own functions" + fail "reloading sand.fln did not include its own functions" | exception Loc.Error { Loc.dmsg = m; _ } -> fail "reloading a file with imports failed: %s" m) end; @@ -1418,9 +1415,9 @@ let () = that can decide it — which is why it is derived here and not sent by the editor. *) if sand_checks then begin - let t, _ = Session.create ~file:"../sand.flan" () in + let t, _ = Session.create ~file:"../sand.fln" () in (match - Session.eval ~origin:"../vendor/agent/agent.flan" t + Session.eval ~origin:"../vendor/agent/agent.fln" t "(defn poll [] i32 (poll-raw))" with | c -> @@ -1428,13 +1425,13 @@ let () = fail "a form from a package file reported %s, wanted agent/poll" (String.concat " " c.Session.fns) | exception Loc.Error { Loc.dmsg = m; _ } -> fail "redefining agent/poll: %s" m); - (* A package that is a single file, which is what sand.flan is to the + (* A package that is a single file, which is what sand.fln is to the headless driver. The file being edited *is* the package rather than a member of a directory, so matching on the directory alone would answer "not a package" — and the failure is the silent one above: the form splices as a bare [step] and the running program keeps the one it had. *) let t2, _ = Session.create ~file:"programs/sand-headless.flan" () in - (match Session.eval ~origin:"../sand.flan" t2 "(defn step [] () (do))" with + (match Session.eval ~origin:"../sand.fln" t2 "(defn step [] () (do))" with | c -> if c.Session.fns <> [ "sand/step" ] then fail "a form from a single-file package reported %s, wanted sand/step" @@ -1442,7 +1439,7 @@ let () = | exception Loc.Error { Loc.dmsg = m; _ } -> fail "redefining sand/step: %s" m); (* And a file that is not a package keeps its names as written. *) - (match Session.eval ~origin:"../sand.flan" t "(defn game-draw [] () (do))" with + (match Session.eval ~origin:"../sand.fln" t "(defn game-draw [] () (do))" with | c -> if c.Session.fns <> [ "game-draw" ] then fail "a form from the program's own file reported %s" diff --git a/test/test_syntax.ml b/test/test_syntax.ml index d64e413d..78d363f7 100644 --- a/test/test_syntax.ml +++ b/test/test_syntax.ml @@ -252,7 +252,9 @@ let pair flan fln = let () = pair "syntax/algorithms.flan" "syntax/algorithms.fln"; - pair "../sand.flan" "syntax/sand.fln"; + (* sand itself is .fln now (decision 130), so there is no more paren + original to pair it against here; syntax/sand.fln is still checked + below. *) pair "syntax/infer/main.flan" "syntax/infer/main.fln"; (* Checked, never run: sand opens a window. *) List.iter diff --git a/test/test_web.ml b/test/test_web.ml index a4130555..19e577a7 100644 --- a/test/test_web.ml +++ b/test/test_web.ml @@ -174,7 +174,7 @@ let () = end; (* ── raylib in the browser ──────────────────────────────────────── - The claim docs/BUILT.md left open. core-basic-window.flan is built for the + The claim docs/BUILT.md left open. core-basic-window.fln is built for the web unchanged — no edit to its `until` loop, which is the whole point of choosing asyncify over emscripten_set_main_loop — and the module is then read for the two things that prove the claim rather than assert @@ -203,7 +203,7 @@ let () = fail "no GL imports in the module — raylib did not link"; cleanup out); - (* ── sand.flan, the flagship, for the browser ────────────────── + (* ── sand.fln, the flagship, for the browser ────────────────── The program the whole target was wanted for, and the last web build in this process on purpose — see [raylib_web] on why anything after it would pick the archive up silently. @@ -233,8 +233,8 @@ let () = paints. Only a human opening it can say that; docs/BUILT.md carries the commands. *) let out = Filename.concat scratch "flan-web-sand.html" in - (match web_build "../sand.flan" out with - | exception Failure m -> fail "sand.flan for the browser: %s" m + (match web_build "../sand.fln" out with + | exception Failure m -> fail "sand.fln for the browser: %s" m | () -> let html, js, wasm = parts out in List.iter diff --git a/vendor/agent/flan_agent.web.c b/vendor/agent/flan_agent.web.c index 6c8bd477..0ab375cf 100644 --- a/vendor/agent/flan_agent.web.c +++ b/vendor/agent/flan_agent.web.c @@ -29,7 +29,7 @@ * is no editor, no socket, and no session — `--dev` is refused by name on * every wasm target, so a web build has no cells to install a redefinition * into even if one arrived. There is nothing to lose because there was never - * anything there. sand.flan already says the same thing about a *native* + * anything there. sand.fln already says the same thing about a *native* * release build, at the call site: * * "Building without --dev is fine — nothing has cells to install into, so a @@ -44,9 +44,9 @@ * * It was the other candidate and it is ruled out by arithmetic, not taste. * Flan has no conditional compilation, so a program cannot say "skip this on - * web". sand.flan calls (agent/start ...) unconditionally, Reach cannot prune + * web". sand.fln calls (agent/start ...) unconditionally, Reach cannot prune * a package something reachable calls into, and a build-time refusal would - * therefore mean sand.flan does not build for the browser at all without being + * therefore mean sand.fln does not build for the browser at all without being * edited into a second program. Refusing is only honest when the caller has a * way to not ask; here it has none. * diff --git a/vendor/edn/edn.fln b/vendor/edn/edn.fln index eedfc4c5..394a1997 100644 --- a/vendor/edn/edn.fln +++ b/vendor/edn/edn.fln @@ -5,9 +5,9 @@ ;;;; anything: every token's text is a `slice` of the input buffer, not a copy ;;;; of it. ;;;; -;;;; Two layers sit above it. `read.flan`, in this package, is the one that -;;;; exists: `(edn/read bytes)` walks this cursor and answers a dynamic -;;;; `Value`. The other, `(read-edn Enemy bytes)` emitting a parser from a +;;;; Two layers sit above it. `read.fln`, in this package, is the one that +;;;; exists: `edn/read(bytes)` walks this cursor and answers a dynamic +;;;; `Value`. The other, `read-edn(Enemy, bytes)` emitting a parser from a ;;;; compile-time walk over a struct's fields, belongs to the compiler and is ;;;; not here; until it exists a caller writes the struct reader by hand ;;;; against this cursor, and test/programs/edn.flan is a worked example of @@ -29,19 +29,19 @@ ;;;; the kind of contract that otherwise gets discovered from a corrupted ;;;; string three frames later. ;;;; -;;;; **`read.flan` does not follow this rule, deliberately.** The two layers of +;;;; **`read.fln` does not follow this rule, deliberately.** The two layers of ;;;; this package diverge on exactly this point: a Token is a view, and a Value ;;;; owns copies of every string in it. The reason is that a view is a fine ;;;; thing for a cursor a caller is driving inside the function that holds the ;;;; buffer, and a trap for a document handed back out of one. Said the other ;;;; way: the contract above is a property of the *layer*, not of the package, -;;;; and a caller who mixes them — holding a Token out of an `(edn/read ...)` +;;;; and a caller who mixes them — holding a Token out of an `edn/read(...)` ;;;; that has returned — is on the tokenizer's terms and not the reader's. ;;;; ;;;; ── What is refused, and why ──────────────────────────────────────── ;;;; ;;;; Every refusal below is a *named* one with a reason attached, reachable as -;;;; (edn/error-message code). A tokenizer that quietly skipped what it did not +;;;; edn/error-message(code). A tokenizer that quietly skipped what it did not ;;;; understand would hand a caller a value that is not the one in the file. ;;;; ;;;; escaped strings "a\nb", "a\"b" — the important one. Unescaping needs @@ -81,9 +81,9 @@ ;;;; ;;;; On the cursor, not in the return type. `next` answers a Token whose kind ;;;; is tok-error, and the cursor carries the code and the byte offset it was -;;;; found at; (edn/error-message code) turns the code into the sentence. The +;;;; found at; edn/error-message(code) turns the code into the sentence. The ;;;; offset is the point: an editor underlines a byte range, and an Option with -;;;; no position could not tell it where. An (Option Token) was the alternative +;;;; no position could not tell it where. An Option(Token) was the alternative ;;;; and it loses exactly that — None says something went wrong, and a second ;;;; out-parameter for the position is the same two fields with a worse shape. ;;;; @@ -93,7 +93,7 @@ ;; ── Token kinds ───────────────────────────────────────────────────── ;; -;; Plain i32 constants and not a `defenum`, which is the shape that wants +;; Plain i32 constants and not an `enum`, which is the shape that wants ;; explaining. An enum here is FFI-only: `=` on an Enum value fails in emit, ;; and a keyword is not a pattern, so `match` cannot see one either. Both fixes ;; live in check.ml and emit.ml, which this lane does not touch. An i32 loses @@ -101,7 +101,7 @@ ;; actually branch on, which is the whole job. const tok-eof = 0 ; the input is exhausted; text is empty -const tok-error = 1 ; see (edn/error c) and (edn/error-message ...) +const tok-error = 1 ; see edn/error(c) and edn/error-message(...) const tok-nil = 2 ; nil const tok-bool = 3 ; true / false — text is the word const tok-int = 4 ; text parses as i64 @@ -379,7 +379,7 @@ fn- read-string(c: Ptr(Cursor), lo: i32) -> Token ;; The one call a caller makes. Advances the cursor past the token it returns. ;; ;; A cursor that has already failed keeps answering the same error token and -;; does not advance, so `(while (!= (.kind t) tok-eof) ...)` terminates on a +;; does not advance, so `while t.kind != tok-eof ...` terminates on a ;; malformed file instead of spinning. fn next(c: Ptr(Cursor)) -> Token if not is-ok(c) diff --git a/vendor/edn/provide.fln b/vendor/edn/provide.fln index 2ccc6d9b..d8c7bb83 100644 --- a/vendor/edn/provide.fln +++ b/vendor/edn/provide.fln @@ -1,13 +1,13 @@ ;;;; defedn: a struct derived from a data file, at compile time. ;;;; ;;;; F#'s type providers, with the part that makes them worth having and none -;;;; of the part that needs a plugin protocol. `(edn/defedn Tileset "t.edn")` +;;;; of the part that needs a plugin protocol. `edn/defedn(Tileset, "t.edn")` ;;;; reads t.edn while the program is being compiled, works out what shape it ;;;; is, and emits the struct that shape implies together with a reader for it. ;;;; From then on `(.texture-path data)` is a field load off a struct: no Value, ;;;; no match, no runtime tag, nothing to look up by name. ;;;; -;;;; read.flan is the other half of the same choice, and both belong here. A +;;;; read.fln is the other half of the same choice, and both belong here. A ;;;; dynamic Value is what you want when the shape is the program's *input* — ;;;; an editor opening a file it has never seen. A provider is what you want ;;;; when the shape is part of the program and only the numbers change, which @@ -20,25 +20,25 @@ ;;;; able to run arbitrary code at expansion time. Three things it could not do ;;;; are what this file rests on, and all three are general: ;;;; -;;;; - `(macro-slurp "t.edn")` reads a file at expansion time, resolved the -;;;; way `(embed "t.edn")` resolves a path — against the directory of the +;;;; - `macro-slurp("t.edn")` reads a file at expansion time, resolved the +;;;; way `embed("t.edn")` resolves a path — against the directory of the ;;;; source file the form is written in. ;;;; - a package's macro may call the package's own functions, which is why ;;;; the derivation below is ordinary Flan over the tokenizer next door ;;;; rather than a second scanner inlined into a macro body. -;;;; - a macro may answer several declarations, as a top-level `(do ...)`, -;;;; and may refuse with a sentence through `(compile-error "...")`. +;;;; - a macro may answer several declarations, as a top-level `do:`, +;;;; and may refuse with a sentence through `compile-error("...")`. ;;;; ;;;; ── The rules ──────────────────────────────────────────────────────── ;;;; ;;;; A map with keyword keys is a struct, one field per key, named for the ;;;; keyword. An integer is an i64, a float an f64, a boolean a bool, a string -;;;; a `string` — copied, which is read.flan's contract and not the tokenizer's: +;;;; a `string` — copied, which is read.fln's contract and not the tokenizer's: ;;;; a Token's text points into the buffer, and a struct that outlives the ;;;; buffer cannot hold one. ;;;; -;;;; A vector of one repeated shape is a `(Vec T)`. A set is this repo's own -;;;; spelling of one, `(Map T bool)` — check.ml says exactly that where it +;;;; A vector of one repeated shape is a `Vec(T)`. A set is this repo's own +;;;; spelling of one, `Map(T, bool)` — check.ml says exactly that where it ;;;; refuses a map with a `()` value — and its elements are therefore read as ;;;; map *keys*. That is why a vector inside a set derives to a fixed array ;;;; `[n T]` rather than to a Vec: a Vec is not a map key and `[2 i64]` is. @@ -65,7 +65,7 @@ fn- joined(a: str, b: str) -> str fn- joined3(a: str, b: str, c: str) -> str = joined(a, joined(b, c)) -;; Copied out, and not `(str (i64->bytes n))`. The prelude's note over +;; Copied out, and not `str(i64->bytes(n))`. The prelude's note over ;; append-i64 is the reason: i64->bytes renders into one shared static buffer ;; in the runtime, so two of its results cannot be held at once — and `where` ;; below holds a line and a column at the same time, which read as the same @@ -145,7 +145,7 @@ fn need-bool(c: Ptr(Cursor)) -> bool None -> false ;; Copied into the allocator, which is the whole difference between a field of -;; a struct and a Token's text. The lifetime contract at the top of edn.flan is +;; a struct and a Token's text. The lifetime contract at the top of edn.fln is ;; the reason: `text` is a slice of the buffer, and a struct read out of a ;; buffer that is later freed would hold a dangling one. fn need-string(c: Ptr(Cursor), a: Allocator) -> str @@ -210,7 +210,9 @@ struct ReadFailed(struct: str, code: i32, pos: i32) fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived let t = next(c) if not is-ok(c) - return derived-bad(joined3("the data file could not be read at ", where(src, error-pos(c)), joined(": ", error-message(c.err)))) + return derived-bad(joined3("the data file could not be read at ", + where(src, error-pos(c)), + joined(": ", error-message(c.err)))) if t.kind == tok-int ok-derived(quasiquote(i64), form-nil(), quasiquote(need-int(c))) elif t.kind == tok-float @@ -226,9 +228,11 @@ fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived elif t.kind == tok-set-open derive-set(c, name, t.pos, src) elif t.kind == tok-nil - derived-bad(joined3("the nil at ", where(src, t.pos), " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) + derived-bad(joined3("the nil at ", where(src, t.pos), + " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) else - derived-bad(joined3("the value at ", where(src, t.pos), " is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string")) + derived-bad(joined3("the value at ", where(src, t.pos), + " is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string")) ;; A vector, whose elements must all come to the same type. The first element ;; decides; every one after it is compared against that decision and both @@ -236,7 +240,8 @@ fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived ;; saying where sends someone to read the whole file. fn- derive-vec(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Derived if is-at-byte(c, \]) - return derived-bad(joined3("the empty vector at ", where(src, at-pos), " has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none")) + return derived-bad(joined3("the empty vector at ", where(src, at-pos), + " has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none")) let head = derive(c, joined(name, "-item"), src) if is-bad(head) return head @@ -255,29 +260,34 @@ fn- derive-vec(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Deriv cn = Form.Sym{.s joined(name, "-new")} ok-derived(ty, with-decl(head.decls, quasiquote(defn(~cn, [a Allocator], ~ty, vec-new(a)))), - quasiquote(let([xs ~cn(a)], expect(c, tok-vec-open), while(is-ok(c) and not is-at-byte(c, \]), push(xs, ~read1)), expect(c, tok-vec-close), xs))) + quasiquote(let([xs ~cn(a)], + expect(c, tok-vec-open), + while(is-ok(c) and not is-at-byte(c, \]), push(xs, ~read1)), + expect(c, tok-vec-close), + xs))) ;; Why every collection gets a one-line constructor of its own. ;; -;; `(vec-new)` and `(map-new)` each need to be told what they build, and the +;; `vec-new()` and `map-new()` each need to be told what they build, and the ;; way to tell them in argument position is to *name* a type: check.ml's ;; vec_new_elem and map_new_types take an `Ast.Var` and nothing else. A type -;; this derives may have no name — `(Vec i64)` has none, and `[2 i64]`, which +;; this derives may have no name — `Vec(i64)` has none, and `[2 i64]`, which ;; is the key of the set in the file this was built for, has none either. ;; ;; Both fall back to what the context wants, and a function's return type is a ;; type position where anything can be written. So the type is stated once, in ;; a signature, and the bare call in the body gets it from `want`. It is also -;; the more readable expansion: the reader says `(cells-new a)` where it would +;; the more readable expansion: the reader says `cells-new(a)` where it would ;; otherwise carry a type nobody wrote. fn- with-decl(decls: [Form], d: Form) -> [Form] form-append(decls, form-cons(d, form-nil())) -;; A set becomes `(Map T bool)`, so its elements are map keys. `derive-key` is +;; A set becomes `Map(T, bool)`, so its elements are map keys. `derive-key` is ;; where that constraint is enforced and said. fn- derive-set(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Derived if is-at-byte(c, \}) - return derived-bad(joined3("the empty set at ", where(src, at-pos), " has no element to derive an element type from")) + return derived-bad(joined3("the empty set at ", where(src, at-pos), + " has no element to derive an element type from")) let head = derive-key(c, joined(name, "-key"), src) if is-bad(head) return head @@ -296,11 +306,15 @@ fn- derive-set(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Deriv cn = Form.Sym{.s joined(name, "-new")} ok-derived(ty, with-decl(head.decls, quasiquote(defn(~cn, [a Allocator], ~ty, map-new(a)))), - quasiquote(let([tbl ~cn(a)], expect(c, tok-set-open), while(is-ok(c) and not is-at-byte(c, \}), put(tbl, ~read1, true)), expect(c, tok-map-close), tbl))) + quasiquote(let([tbl ~cn(a)], + expect(c, tok-set-open), + while(is-ok(c) and not is-at-byte(c, \}), put(tbl, ~read1, true)), + expect(c, tok-map-close), + tbl))) ;; One element of a set. The scalars that are map keys pass; a vector becomes a ;; fixed array, which is one where a Vec is not; anything else is refused here -;; rather than at the `(Map ...)` the caller would build out of it, because a +;; rather than at the `Map(...)` the caller would build out of it, because a ;; map-key refusal names a type nobody wrote. fn- derive-key(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived if is-at-byte(c, \[) @@ -309,7 +323,8 @@ fn- derive-key(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived if is-bad(d) return d if not is-key-type(d.ty) - return derived-bad(joined3("a set of ", render(d.ty), " is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are")) + return derived-bad(joined3("a set of ", render(d.ty), + " is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are")) d ;; A vector in key position. Its length is part of its type, so every element @@ -319,7 +334,8 @@ fn- derive-key(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived fn- derive-array(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived let open = next(c) if is-at-byte(c, \]) - return derived-bad(joined3("the empty vector at ", where(src, open.pos), " is inside a set, and an empty fixed array has no element type and no length")) + return derived-bad(joined3("the empty vector at ", where(src, open.pos), + " is inside a set, and an empty fixed array has no element type and no length")) let head = derive(c, joined(name, "-item"), src) if is-bad(head) return head @@ -333,16 +349,26 @@ fn- derive-array(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived n += 1 expect(c, tok-vec-close) if not is-key-type(head.ty) - return derived-bad(joined3("a set of vectors of ", render(head.ty), " is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise")) + return derived-bad(joined3("a set of vectors of ", render(head.ty), + " is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise")) let elem = head.ty read1 = head.reader count = Form.Int{.i n} ok-derived(quasiquote([~count ~elem]), head.decls, - quasiquote(let([arr array(~count, ~elem) i 0], expect(c, tok-vec-open), while(is-ok(c) and not is-at-byte(c, \]) and i < ~count, set(arr[i], ~read1), set(i, i + 1)), expect(c, tok-vec-close), arr))) + quasiquote(let([arr array(~count, ~elem) i 0], + expect(c, tok-vec-open), + while(is-ok(c) and not is-at-byte(c, \]) and i < ~count, + set(arr[i], ~read1), set(i, i + 1)), + expect(c, tok-vec-close), + arr))) fn- disagreement(what: str, src: [const u8], at-pos: i32, n: i64, first: Form, second: Form) -> str joined3(joined3("the ", what, " at "), where(src, at-pos), - joined3(joined3(" holds more than one shape: its first element is ", render(first), " and element "), i64->string(n), joined3(" is ", render(second), ". Every element has to be the same shape, because the type this becomes has one element type"))) + joined3(joined3(" holds more than one shape: its first element is ", render(first), + " and element "), + i64->string(n), + joined3(" is ", render(second), + ". Every element has to be the same shape, because the type this becomes has one element type"))) ;; ── A map, which is a struct ──────────────────────────────────────── ;; @@ -357,7 +383,8 @@ fn- disagreement(what: str, src: [const u8], at-pos: i32, n: i64, first: Form, s ;; Both signal SchemaDrift. See the note over that type. fn- derive-map(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Derived if is-at-byte(c, \}) - return derived-bad(joined3("the empty map at ", where(src, at-pos), " has no keys to derive fields from — a struct with no fields is not a shape anything can be read into")) + return derived-bad(joined3("the empty map at ", where(src, at-pos), + " has no keys to derive fields from — a struct with no fields is not a shape anything can be read into")) let fields = vec-new(Form) ; the defstruct's [name type ...] vector clauses = vec-new(Form) ; the reader's cond: test, body, test, body missing = vec-new(Form) ; one per field, checked when the map closes @@ -366,9 +393,13 @@ fn- derive-map(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Deriv while is-ok(c) and not is-at-byte(c, \}) let k = next(c) if not is-ok(c) - return derived-bad(joined3("the data file could not be read at ", where(src, error-pos(c)), joined(": ", error-message(c.err)))) + return derived-bad(joined3("the data file could not be read at ", + where(src, error-pos(c)), + joined(": ", error-message(c.err)))) if k.kind != tok-keyword - return derived-bad(joined3(joined3("the map at ", where(src, at-pos), " has a key at "), where(src, k.pos), " that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1")) + return derived-bad(joined3(joined3("the map at ", where(src, at-pos), " has a key at "), + where(src, k.pos), + " that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1")) let fname = copy-text(k.text) let d = derive(c, joined3(name, "-", fname), src) if is-bad(d) @@ -388,7 +419,9 @@ fn- derive-map(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Deriv ;; bit is decided here, where the field is, so the two cannot fall ;; out of step the way a parallel list of names would. push(missing, - quasiquote(when seen && ~bit == 0 then signal(SchemaDrift{.field ~lit .struct ~(Form.Str{.s name}) .is-extra false .pos k.pos}))) + quasiquote(when seen && ~bit == 0 then + signal(SchemaDrift{.field ~lit .struct ~(Form.Str{.s name}) + .is-extra false .pos k.pos}))) idx += 1 expect(c, tok-map-close) ;; An unknown key. The hand-written reader skips one, which is right when a @@ -398,7 +431,9 @@ fn- derive-map(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Deriv ;; handle the condition still reads the rest. push(clauses, quasiquote(:else)) push(clauses, - quasiquote(do(signal(SchemaDrift{.field copy-text(k.text) .struct ~(Form.Str{.s name}) .is-extra true .pos k.pos}), when not skip-value(c) then return out))) + quasiquote(do(signal(SchemaDrift{.field copy-text(k.text) .struct ~(Form.Str{.s name}) + .is-extra true .pos k.pos}), + when not skip-value(c) then return out))) let sname = Form.Sym{.s name} rname = Form.Sym{.s joined("read-", name)} let (struct) = quasiquote(defstruct(~sname, ~(Form.Vec{.xs slice(fields)}))) @@ -428,7 +463,7 @@ fn- is-same-type(a: Form, b: Form) -> bool is-bytes-equal(bytes-view(render(a)), bytes-view(render(b))) ;; A type form as text, for the refusals. Only the shapes this file builds — a -;; name, a number, `(Vec T)`, `(Map K V)` and `[n T]` — because nothing else +;; name, a number, `Vec(T)`, `Map(K, V)` and `[n T]` — because nothing else ;; ever reaches it. fn render(f: Form) -> str match f @@ -449,12 +484,13 @@ fn- render-items(xs: [Form]) -> str ;; itself, so there is no equality for a map to hash. fn- is-key-type(t: Form) -> bool let s = bytes-view(render(t)) - is-bytes-equal(s, bytes-view("i64")) or (is-bytes-equal(s, bytes-view("bool")) or is-bytes-equal(s, bytes-view("string"))) + is-bytes-equal(s, bytes-view("i64")) or + (is-bytes-equal(s, bytes-view("bool")) or is-bytes-equal(s, bytes-view("string"))) ;; ── The macro ─────────────────────────────────────────────────────── ;; -;; `(edn/defedn Tileset "assets/tileset.edn")`. The path is relative to the -;; file this is written in, exactly as `(embed "assets/tileset.edn")` is — see +;; `edn/defedn(Tileset, "assets/tileset.edn")`. The path is relative to the +;; file this is written in, exactly as `embed("assets/tileset.edn")` is — see ;; `macro-slurp` in the prelude, and check.ml's `embed_path`, which is the rule ;; it copies. ;; @@ -474,7 +510,8 @@ macro defedn(& args) match macro-slurp(path) Some(src) -> provide(name, path, src) None -> - refuse(joined3("there is no file at ", path, ", read relative to the file this defedn is written in — the same place (embed \"...\") would look")) + refuse(joined3("there is no file at ", path, + ", read relative to the file this defedn is written in — the same place (embed \"...\") would look")) _ -> refuse("defedn's first argument is the name of the struct to declare, written as a name") _ -> diff --git a/vendor/edn/read.fln b/vendor/edn/read.fln index b1d4678b..a5fb88c1 100644 --- a/vendor/edn/read.fln +++ b/vendor/edn/read.fln @@ -1,9 +1,9 @@ ;;;; The dynamic reader: an EDN document, and no type to read it into. ;;;; -;;;; `edn.flan` answers "what is the next token". This answers "what is in the +;;;; `edn.fln` answers "what is the next token". This answers "what is in the ;;;; file", for a caller that has no struct to hand — a config file whose keys -;;;; are not known until it is read, a tileset, a save. `(edn/defedn T path)` -;;;; in provide.flan is the other direction: the shape known at compile time, +;;;; are not known until it is read, a tileset, a save. `edn/defedn(T, path)` +;;;; in provide.fln is the other direction: the shape known at compile time, ;;;; read into a struct, at no run-time cost. Together they are the two sides ;;;; of one capability, and this is the dynamic one. ;;;; @@ -59,7 +59,7 @@ ;; ── Copying a token's text ────────────────────────────────────────── ;; Not the dyn reader's own — everything below boxes through the runtime, -;; which copies for itself — but provide.flan's generated readers build typed +;; which copies for itself — but provide.fln's generated readers build typed ;; strings out of token text and this is where that copy has always lived. ;; The (Vec u8) is the copy; the string is a view of it, and the Vec header is ;; dropped here on purpose. Nothing individually owns a block in a region — diff --git a/vendor/json/json.fln b/vendor/json/json.fln index d162e319..fc65fb52 100644 --- a/vendor/json/json.fln +++ b/vendor/json/json.fln @@ -3,7 +3,7 @@ ;;;; The shape is vendor/edn's, deliberately: a Cursor over a caller's buffer, ;;;; one `next` that answers a Token, errors accumulated on the cursor with the ;;;; byte offset they were found at, and every refusal named and given a reason -;;;; reachable as (json/error-message code). Read vendor/edn/edn.flan first if +;;;; reachable as json/error-message(code). Read vendor/edn/edn.fln first if ;;;; you have not; everything that file argues for is argued for there and only ;;;; the differences are argued for here. ;;;; @@ -26,7 +26,7 @@ ;;;; ;;;; * a Token's `text` is a slice INTO the buffer, exactly as edn's is, and ;;;; for a string token it is the RAW interior — backslashes and all; -;;;; * (json/string-of t) is the one call that allocates. It answers a +;;;; * json/string-of(t) is the one call that allocates. It answers a ;;;; string whose bytes are a fresh copy in the context's allocator, with ;;;; every escape resolved. ;;;; @@ -40,7 +40,7 @@ ;;;; survive the free-all in the cases that had no escapes and not in the ;;;; others, which is the kind of contract nobody can hold in their head. ;;;; -;;;; Note what that buys against vendor/edn/read.flan's dyn reader, which +;;;; Note what that buys against vendor/edn/read.fln's dyn reader, which ;;;; settled the same question a different way: it takes no allocator at all, ;;;; because every string it produces is boxed onto the collector's heap on ;;;; the spot — read-value's "a document owns its strings" rule. This @@ -53,8 +53,8 @@ ;;;; ── The allocator ─────────────────────────────────────────────────── ;;;; ;;;; string-of names no allocator and takes no parameter. spec-memory.md puts -;;;; the allocator in the calling convention, so the (vec-new u8) inside it -;;;; takes the context's, and (with-allocator frame (json/string-of t)) is the +;;;; the allocator in the calling convention, so the vec-new(u8) inside it +;;;; takes the context's, and with-allocator(frame, json/string-of(t)) is the ;;;; whole of "reading against an arena". An explicit allocator at the ;;;; construction site would override that, which is how this would take one if ;;;; the idiom could not express it. It can. @@ -75,7 +75,7 @@ ;;;; single quotes 'x' — legal in JSON5. ;;;; +1 — a leading plus is JSON5's. ;;;; .5 and 1. — JSON5 allows a bare leading or trailing -;;;; decimal point. Worth contrasting with edn.flan, which +;;;; decimal point. Worth contrasting with edn.fln, which ;;;; goes the other way and reads `.5` as a float on ;;;; purpose; here it is an error, and named. ;;;; 0x1f — hexadecimal is JSON5's. @@ -145,12 +145,12 @@ ;; ── Token kinds ───────────────────────────────────────────────────── ;; -;; Plain i32 constants and not a `defenum`, for the reason vendor/edn gives: +;; Plain i32 constants and not an `enum`, for the reason vendor/edn gives: ;; `=` on an Enum value fails in emit and a keyword is not a pattern, so an ;; enum here would be a token kind a caller could not branch on. const tok-eof = 0 ; the input is exhausted; text is empty -const tok-error = 1 ; see (json/error c) and (json/error-message ...) +const tok-error = 1 ; see json/error(c) and json/error-message(...) const tok-null = 2 ; null const tok-bool = 3 ; true / false — text is the word const tok-int = 4 ; a number with no fraction and no exponent @@ -555,7 +555,7 @@ fn- read-string(c: Ptr(Cursor), lo: i32) -> Token ;; The one call a caller makes. Advances the cursor past the token it returns. ;; ;; A cursor that has already failed keeps answering the same error token and -;; does not advance, so `(while (!= (.kind t) tok-eof) ...)` terminates on a +;; does not advance, so `while t.kind != tok-eof ...` terminates on a ;; malformed document instead of spinning. fn next(c: Ptr(Cursor)) -> Token if not is-ok(c) diff --git a/vendor/json/provide.fln b/vendor/json/provide.fln index 9aa4d692..8935392b 100644 --- a/vendor/json/provide.fln +++ b/vendor/json/provide.fln @@ -1,8 +1,8 @@ ;;;; defjson: a struct derived from a JSON file, at compile time. ;;;; -;;;; `(json/defjson Config "config.json")` reads config.json while the program +;;;; `json/defjson(Config, "config.json")` reads config.json while the program ;;;; is being compiled, derives the struct its shape implies, and emits that -;;;; struct with a reader over the tokenizer next door. `(.port cfg)` is then a +;;;; struct with a reader over the tokenizer next door. `cfg.port` is then a ;;;; field load: no Value, no match, no runtime tag, nothing looked up by name. ;;;; ;;;; It is the same idea as vendor/edn's defedn and deliberately not the same @@ -16,7 +16,7 @@ ;;;; ;;;; ── What is different, and why ─────────────────────────────────────── ;;;; -;;;; **Strings go through `string-of` and never through `.text`.** json.flan's +;;;; **Strings go through `string-of` and never through `.text`.** json.fln's ;;;; `.text` is the RAW interior of a string token, escapes undecoded, so a ;;;; field read off it would hold a literal backslash-n where the file meant a ;;;; newline. `string-of` is the one call in that package that allocates, and @@ -31,7 +31,7 @@ ;;;; field. ;;;; ;;;; **There are no sets**, so there is no map-key path and no fixed array: -;;;; every collection here is a `(Vec T)`. defjson is strictly the smaller of +;;;; every collection here is a `Vec(T)`. defjson is strictly the smaller of ;;;; the two. ;;;; ;;;; JSON has no integer type of its own — the tokenizer draws the line at @@ -50,7 +50,7 @@ fn- joined(a: str, b: str) -> str fn- joined3(a: str, b: str, c: str) -> str = joined(a, joined(b, c)) -;; Copied out, and not `(str (i64->bytes n))`: the prelude's note over +;; Copied out, and not `str(i64->bytes(n))`: the prelude's note over ;; append-i64 is the reason — i64->bytes renders into one shared static buffer ;; in the runtime, so two of its results cannot be held at once, and `where` ;; holds a line and a column at the same time. @@ -138,7 +138,7 @@ fn is-at-byte(c: Ptr(Cursor), b: u8) -> bool not is-at-end(c) and c.src[c.pos] == b ;; The comma between two members, taken when there is one. A trailing comma is -;; json.flan's err-trailing-comma and is the tokenizer's to refuse, not this +;; json.fln's err-trailing-comma and is the tokenizer's to refuse, not this ;; loop's: taking it here and then meeting the closer is exactly the shape that ;; refusal is written against. fn comma(c: Ptr(Cursor)) -> () @@ -173,7 +173,9 @@ struct ReadFailed(struct: str, code: i32, pos: i32) fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived let t = next(c) if not is-ok(c) - return derived-bad(joined3("the data file could not be read at ", where(src, error-pos(c)), joined(": ", error-message(c.err)))) + return derived-bad(joined3("the data file could not be read at ", + where(src, error-pos(c)), + joined(": ", error-message(c.err)))) if t.kind == tok-int ok-derived(quasiquote(i64), form-nil(), quasiquote(need-int(c))) elif t.kind == tok-float @@ -187,9 +189,11 @@ fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived elif t.kind == tok-array-open derive-array(c, name, t.pos, src) elif t.kind == tok-null - derived-bad(joined3("the null at ", where(src, t.pos), " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) + derived-bad(joined3("the null at ", where(src, t.pos), + " has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out")) else - derived-bad(joined3("the value at ", where(src, t.pos), " is not one defjson derives a type from — an object, an array, a number, a boolean or a string")) + derived-bad(joined3("the value at ", where(src, t.pos), + " is not one defjson derives a type from — an object, an array, a number, a boolean or a string")) ;; An array, whose elements must all come to the same type. The first decides; ;; every one after it is compared against that, and both positions are named @@ -197,7 +201,8 @@ fn- derive(c: Ptr(Cursor), name: str, src: [const u8]) -> Derived ;; whole file. fn- derive-array(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Derived if is-at-byte(c, \]) - return derived-bad(joined3("the empty array at ", where(src, at-pos), " has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none")) + return derived-bad(joined3("the empty array at ", where(src, at-pos), + " has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none")) let head = derive(c, joined(name, "-item"), src) if is-bad(head) return head @@ -208,7 +213,12 @@ fn- derive-array(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Der if is-bad(item) return item if not is-same-type(head.ty, item.ty) - return derived-bad(joined3(joined3("the array at ", where(src, at-pos), " holds more than one shape: element 0 is "), render(head.ty), joined3(joined3(" and element ", i64->string(n), " is "), render(item.ty), ". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type"))) + return derived-bad(joined3(joined3("the array at ", where(src, at-pos), + " holds more than one shape: element 0 is "), + render(head.ty), + joined3(joined3(" and element ", i64->string(n), " is "), + render(item.ty), + ". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type"))) comma(c) n += 1 expect(c, tok-array-close) @@ -216,20 +226,25 @@ fn- derive-array(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Der read1 = head.reader ty = quasiquote(Vec(~elem)) cn = Form.Sym{.s joined(name, "-new")} - ;; The constructor states the type so the bare (vec-new a) in its body - ;; can take it from `want`. (vec-new) has to be *told* what it builds by - ;; naming a type, and `(Vec i64)` has no name to be — but a signature is + ;; The constructor states the type so the bare vec-new(a) in its body + ;; can take it from `want`. vec-new() has to be *told* what it builds by + ;; naming a type, and `Vec(i64)` has no name to be — but a signature is ;; a type position where anything can be written. The reader reads ;; better for it too. ok-derived(ty, with-decl(head.decls, quasiquote(defn(~cn, [a Allocator], ~ty, vec-new(a)))), - quasiquote(let([xs ~cn(a)], expect(c, tok-array-open), while(is-ok(c) and not is-at-byte(c, \]), push(xs, ~read1), comma(c)), expect(c, tok-array-close), xs))) + quasiquote(let([xs ~cn(a)], + expect(c, tok-array-open), + while(is-ok(c) and not is-at-byte(c, \]), push(xs, ~read1), comma(c)), + expect(c, tok-array-close), + xs))) ;; ── An object, which is a struct ──────────────────────────────────── fn- derive-object(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> Derived if is-at-byte(c, \}) - return derived-bad(joined3("the empty object at ", where(src, at-pos), " has no members to derive fields from — a struct with no fields is not a shape anything can be read into")) + return derived-bad(joined3("the empty object at ", where(src, at-pos), + " has no members to derive fields from — a struct with no fields is not a shape anything can be read into")) let fields = vec-new(Form) ; the defstruct's [name type ...] vector clauses = vec-new(Form) ; the reader's cond: test, body, test, body missing = vec-new(Form) ; one per field, checked when the object closes @@ -238,9 +253,13 @@ fn- derive-object(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> De while is-ok(c) and not is-at-byte(c, \}) let k = next(c) if not is-ok(c) - return derived-bad(joined3("the data file could not be read at ", where(src, error-pos(c)), joined(": ", error-message(c.err)))) + return derived-bad(joined3("the data file could not be read at ", + where(src, error-pos(c)), + joined(": ", error-message(c.err)))) if k.kind != tok-string - return derived-bad(joined3("the object at ", joined3(where(src, at-pos), " has a member at ", where(src, k.pos)), " whose name is not a string, which JSON requires")) + return derived-bad(joined3("the object at ", + joined3(where(src, at-pos), " has a member at ", where(src, k.pos)), + " whose name is not a string, which JSON requires")) ;; The comparison in the generated reader is against the token's RAW ;; text, which costs no allocation per key. That is only the same ;; question as "is this the field" when the name has no escape in it — @@ -249,9 +268,11 @@ fn- derive-object(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> De ;; the file where it would have mattered. let raw = k.text if has-escape(raw) - return derived-bad(joined3("the member name at ", where(src, k.pos), " has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly")) + return derived-bad(joined3("the member name at ", where(src, k.pos), + " has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly")) if not is-name-like(raw) - return derived-bad(joined3("the member name at ", where(src, k.pos), " is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of")) + return derived-bad(joined3("the member name at ", where(src, k.pos), + " is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of")) expect(c, tok-colon) let fname = copy-of(raw) let d = derive(c, joined3(name, "-", fname), src) @@ -272,7 +293,9 @@ fn- derive-object(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> De ;; beside the field, so the two cannot fall out of step the way a ;; parallel list of names would. push(missing, - quasiquote(when seen && ~bit == 0 then signal(SchemaDrift{.field ~lit .struct ~(Form.Str{.s name}) .is-extra false .pos close.pos}))) + quasiquote(when seen && ~bit == 0 then + signal(SchemaDrift{.field ~lit .struct ~(Form.Str{.s name}) + .is-extra false .pos close.pos}))) comma(c) idx += 1 expect(c, tok-object-close) @@ -281,7 +304,9 @@ fn- derive-object(c: Ptr(Cursor), name: str, at-pos: i32, src: [const u8]) -> De ;; program that declines to handle the condition still reads the rest. push(clauses, quasiquote(:else)) push(clauses, - quasiquote(do(signal(SchemaDrift{.field match(string-of(k), Some(s), s, None, "") .struct ~(Form.Str{.s name}) .is-extra true .pos k.pos}), when not skip-value(c) then return out))) + quasiquote(do(signal(SchemaDrift{.field match(string-of(k), Some(s), s, None, "") + .struct ~(Form.Str{.s name}) .is-extra true .pos k.pos}), + when not skip-value(c) then return out))) let sname = Form.Sym{.s name} rname = Form.Sym{.s joined("read-", name)} let (struct) = quasiquote(defstruct(~sname, ~(Form.Vec{.xs slice(fields)}))) @@ -343,7 +368,7 @@ fn- is-same-type(a: Form, b: Form) -> bool is-bytes-equal(bytes-view(render(a)), bytes-view(render(b))) ;; A type form as text, for the refusals. Only the shapes this file builds — a -;; name and `(Vec T)` — because nothing else ever reaches it. +;; name and `Vec(T)` — because nothing else ever reaches it. fn render(f: Form) -> str match f Form.Sym(s) -> s @@ -360,8 +385,8 @@ fn- render-items(xs: [Form]) -> str ;; ── The macro ─────────────────────────────────────────────────────── ;; -;; `(json/defjson Config "config.json")`. The path is relative to the file this -;; is written in, exactly as `(embed "config.json")` is — see `macro-slurp` in +;; `json/defjson(Config, "config.json")`. The path is relative to the file this +;; is written in, exactly as `embed("config.json")` is — see `macro-slurp` in ;; the prelude, and check.ml's `embed_path`, which is the rule it copies. ;; ;; It answers a `do`, which the top level splices: the nested structs innermost @@ -378,7 +403,8 @@ macro defjson(& args) match macro-slurp(path) Some(src) -> provide(name, path, src) None -> - refuse(joined3("there is no file at ", path, ", read relative to the file this defjson is written in — the same place (embed \"...\") would look")) + refuse(joined3("there is no file at ", path, + ", read relative to the file this defjson is written in — the same place (embed \"...\") would look")) _ -> refuse("defjson's first argument is the name of the struct to declare, written as a name") _ -> diff --git a/vendor/raylib/bindings b/vendor/raylib/bindings index ddee763a..81b14c1b 100644 --- a/vendor/raylib/bindings +++ b/vendor/raylib/bindings @@ -17,7 +17,7 @@ # output the generator had already committed to. # # What does NOT belong here. Anything neither directive can express is a -# hand-written `declare-c` in raylib.flan, which wins over the generated file +# hand-written `declare-c` in raylib.fln, which wins over the generated file # and is left alone by the importer. That is the escape hatch for a signature # the importer gets wrong and for a Flan face the header cannot describe — # load-font-ex-raw and load-image-from-memory-raw are both that, each wrapped @@ -40,9 +40,9 @@ exclude MemFree # # A predicate keeps the kebab rule's name, `is-window-ready` for # `IsWindowReady`: a Flan name carries no `?`, and the hand-written bindings in -# raylib.flan follow the C name the same way. +# raylib.fln follow the C name the same way. -# Hand-written in raylib.flan, so excluded here: a second declare-c for one C +# Hand-written in raylib.fln, so excluded here: a second declare-c for one C # symbol is refused for the whole program. These three are on a game's # per-frame path (docs/PORTING.md), and a hand-written line is what the signature # check has to compare against -- generated output agrees with the header by @@ -69,7 +69,7 @@ exclude IsWindowReady # update-camera-pro is generated. (draw-cube-v was named here as the third # such pair and no longer is — see the DrawCubeV line further down, which is # what happens to a split of this kind when an example starts calling the -# other half.) Every other family in raylib.flan — the texture draws, the +# other half.) Every other family in raylib.fln — the texture draws, the # circle draws — sits together, so the split is worth naming: what is # hand-written is what the ported examples call, and hand-writing the variants # as well would widen the half that has to be maintained by hand for nothing @@ -99,7 +99,7 @@ exclude GetWorldToScreen # of a closed set of names in fact, so their Flan face is a defenum and # not the C signature — the same trade SetExitKey makes. # - DrawCubeV, DrawSphere, DrawSphereWires and DrawRay are inside a frame, -# in examples/models-box-collisions.flan and examples/core-3d-picking.flan. +# in examples/models-box-collisions.fln and examples/core-3d-picking.fln. # draw-cube-v moving here is the one place this batch *narrows* the split # the paragraph above names: it was generated because nothing called it, # and something calls it now. @@ -117,17 +117,17 @@ exclude GetScreenToWorldRay # is a PixelFormat in fact — twenty-four codes of which exactly one is what a # texture upload needs — so its Flan face is the defenum and not the C # signature, the same trade SetTextureFilter makes one block up. -# examples/textures-image-processing.flan is what wanted it: the C's +# examples/textures-image-processing.fln is what wanted it: the C's # `PIXELFORMAT_UNCOMPRESSED_R8G8B8A8` is a name there and would have been a 7 # here. exclude ImageFormat # ── The idiomatic layer, which is what these last two blocks are for ── # -# Three kinds of C signature get a Flan face in raylib.flan rather than the +# Three kinds of C signature get a Flan face in raylib.fln rather than the # generated one, and each kind is a directive here so that the generated file # does not also define the name. See the "An idiomatic layer" section of -# raylib.flan for what each wrapper buys at the call site. +# raylib.fln for what each wrapper buys at the call site. # # 1. An `int` parameter the package already has a defenum for. These are # excluded and hand-written with the enum type, exactly as SetExitKey and @@ -156,7 +156,7 @@ name GetKeyPressed get-key-pressed-raw # every raylib entry point that takes an array of vectors as pointer plus # count, and it is the whole family on purpose — a subset would put the # hole exactly where the next caller looks, which is the argument -# raylib.flan makes about ConfigFlags. +# raylib.fln makes about ConfigFlags. name DrawLineStrip draw-line-strip-raw name DrawTriangleFan draw-triangle-fan-raw name DrawTriangleStrip draw-triangle-strip-raw @@ -231,7 +231,7 @@ constant Gesture/gesture-double-tap GESTURE_DOUBLETAP constant PixelFormat/pixel-compressed-astc-4x4-rgba PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA constant PixelFormat/pixel-compressed-astc-8x8-rgba PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA -# The 16 ConfigFlags bits. These are the values sand.flan and the ported +# The 16 ConfigFlags bits. These are the values sand.fln and the ported # window-flags example pass to set-config-flags, set-window-state and # clear-window-state, and each is a single bit read off raylib.h by hand — # exactly the transcription this check exists to second-guess. diff --git a/vendor/raylib/generated.fln b/vendor/raylib/generated.fln index 4ac56a94..26f60b24 100644 --- a/vendor/raylib/generated.fln +++ b/vendor/raylib/generated.fln @@ -6,7 +6,7 @@ ;;;; beside it, which is read *while* these lines are made: `exclude` drops ;;;; a function, `name` gives one a Flan name the kebab rule would not. ;;;; Anything neither directive can express is a hand-written declare-c in -;;;; the package's own .flan, which wins over this file and is left alone. +;;;; the package's own source, which wins over this file and is left alone. ;;;; ;;;; Regenerating compares the package against the header first and ;;;; refuses to write when they disagree, so this file and the diff --git a/vendor/raylib/headers b/vendor/raylib/headers index ac089ad9..3368999b 100644 --- a/vendor/raylib/headers +++ b/vendor/raylib/headers @@ -15,7 +15,7 @@ # library they claim to bind. # # 2. every ordinary build. Every C symbol -# is bound already — by hand in raylib.flan or by generation in +# is bound already — by hand in raylib.fln or by generation in # generated.fln — so the importer generates nothing and the header read # is purely the check. It runs over every declaration in the package and # not only the hand-written ones, because the generated file is a package @@ -27,7 +27,7 @@ # the time anybody checked them — which is what a census written into a # comment beside a growing file always does. The generated half is # `grep -c '^(declare-c' generated.fln` and the hand-written half is the -# same over the other .flan files here; neither number goes stale.) +# same over the other .fln files here; neither number goes stale.) # # Why it is no longer optional. It used to be `?${FLAN_RAYLIB_H}`, and the # argument was that a build needs libraylib linkable and *not* raylib-devel @@ -56,7 +56,7 @@ # # To see what regeneration would produce without writing anything: # -# flan import-c vendor/raylib/raylib-5.5.h vendor/raylib/raylib.flan +# flan import-c vendor/raylib/raylib-5.5.h vendor/raylib/raylib.fln # # What shapes the generated half — which functions are skipped, and what they # are called — is `bindings` beside this file. See its comments for why a diff --git a/vendor/raylib/modes.fln b/vendor/raylib/modes.fln index 0c6c24e6..f8114e63 100644 --- a/vendor/raylib/modes.fln +++ b/vendor/raylib/modes.fln @@ -47,7 +47,7 @@ ;;;; one place anybody writes it, which is a worse thing to hand somebody than ;;;; a macro that is honest about its extent. ;;;; -;;;; So the discipline sand.flan already writes down stays the discipline: +;;;; So the discipline sand.fln already writes down stays the discipline: ;;;; keep the restart boundary OUTSIDE the pair, so choosing `continue` for a ;;;; frame abandons the update and still reaches the drawing. spec-conditions ;;;; §5 is the rule behind that — a transfer runs the intervening frames' @@ -55,17 +55,17 @@ ;;;; ;;;; ── Why this is a file of its own ─────────────────────────────────── ;;;; -;;;; vector.flan's reasoning, unchanged: the split is on `declare-c`. -;;;; raylib.flan is the package's statement about C, it is the file the header +;;;; vector.fln's reasoning, unchanged: the split is on `declare-c`. +;;;; raylib.fln is the package's statement about C, it is the file the header ;;;; check reads hand-written signatures out of, and a wrong line in it stops ;;;; the build. There is not one `declare-c` below — every macro here expands -;;;; into names raylib.flan already declares — so there is nothing for the +;;;; into names raylib.fln already declares — so there is nothing for the ;;;; header check to read and nothing raylib can make wrong. A package is a -;;;; directory, so this is another .flan beside the others and is qualified +;;;; directory, so this is another .fln beside the others and is qualified ;;;; `rl/` like the rest of it. ;;;; -;;;; The names come out qualified: the importer writes `(rl/with-drawing …)` -;;;; and a bare `(with-drawing …)` is an unknown name there, the rule every +;;;; The names come out qualified: the importer writes `rl/with-drawing:` +;;;; and a bare `with-drawing:` is an unknown name there, the rule every ;;;; declaration in this package follows. The expansions name this package's ;;;; own functions unqualified and the expander qualifies them on the way out ;;;; — see test/programs/pkgs/mac/mac.flan, which is that rule's worked @@ -105,7 +105,7 @@ macro with-drawing(& args) ;; The 2D camera. The argument is a Camera2D value, evaluated once where it ;; always was. Remember that a fresh (Camera2D {}) has zoom 0.0 and is not -;; usable as an identity — raylib.flan says so beside the struct. +;; usable as an identity — raylib.fln says so beside the struct. macro with-mode-2d(& args) if length(args) < 2 or (length(args) == 2 and is-form-empty-list(args[1])) quote diff --git a/vendor/raylib/raylib.fln b/vendor/raylib/raylib.fln index 509c15ab..7787c645 100644 --- a/vendor/raylib/raylib.fln +++ b/vendor/raylib/raylib.fln @@ -71,7 +71,7 @@ struct Texture2D(id: u32, width: i32, height: i32, mipmaps: i32, format: i32) struct Rectangle(x: f32, y: f32, width: f32, height: f32) -;; KeyboardKey, the subset sand.flan uses. A keyword at a call site resolves +;; KeyboardKey, the subset sand.fln uses. A keyword at a call site resolves ;; against these members at compile time and a typo is an error there. ;; ;; Every member carries the `key-` prefix, as every member of every other @@ -185,7 +185,7 @@ declare-c(set-trace-log-level, [level TraceLogLevel], "SetTraceLogLevel") ;; A bitfield, like the gestures below and for the same reason: raylib wants ;; the OR of several and a keyword can only ever name one member, so the -;; parameter is a u32 and the members are defconsts rather than a defenum. +;; parameter is a u32 and the members are consts rather than a enum. ;; ;; The part that is NOT obvious from the signature: set-config-flags has to ;; be called BEFORE init-window. raylib stores the flags and reads them while @@ -193,7 +193,7 @@ declare-c(set-trace-log-level, [level TraceLogLevel], "SetTraceLogLevel") ;; INFO, and does nothing to the window that already exists — which looks ;; exactly like a binding that did not work. Afterwards is what the generated ;; set-window-state, clear-window-state and is-window-state are for, and they -;; take these same bits, which is why the four sand.flan sets grew into the +;; take these same bits, which is why the four sand.fln sets grew into the ;; whole of ConfigFlags: a subset has its hole exactly where the next caller ;; looks. Every value below was read off raylib.h 5.5. ;; @@ -236,7 +236,7 @@ declare-c(is-key-released, [key Key], bool, "IsKeyReleased") ;; The other two halves of that family, hand-written for exactly the reason ;; above and added late: they were generated, so they took an i32, so -;; `(rl/is-key-up :key-space)` did not compile while `(rl/is-key-down :key-space)` did. +;; `rl/is-key-up(:key-space)` did not compile while `rl/is-key-down(:key-space)` did. ;; That is a hole in a family rather than a missing convenience — a caller ;; who has used is-key-down has no reason to expect the sibling to be spelled ;; differently, and what they get instead of a keyword is a number nobody @@ -263,8 +263,8 @@ declare-c(is-mouse-button-up, [button MouseButton], bool, "IsMouseButtonUp") ;; caller could otherwise have to think about — KEY_NULL for one, the NUL ;; byte for the other. An Option says which of the two it is in the type, so ;; the loop that drains the queue cannot read the sentinel as a key or as a -;; character: `while (> key 0)` is a comparison a reader has to know the -;; convention to trust, and `(while-some ...)` — or the `if-let` shape the +;; character: `while key > 0` is a comparison a reader has to know the +;; convention to trust, and `while-some(...)` — or the `if-let` shape the ;; examples use — is one a reader can check. ;; ;; The generated declarations are still what call C; only their names moved @@ -303,7 +303,7 @@ declare-c(get-mouse-wheel-move, [], f32, "GetMouseWheelMove") ;; EnableCursor — are in the generated half rather than here: they take no ;; arguments at all, so there is no Flan face for a hand-written line to ;; improve, which is the same rule that leaves GetMouseX there. -;; examples/core-3d-picking.flan toggles them from the right mouse button. +;; examples/core-3d-picking.fln toggles them from the right mouse button. declare-c(show-cursor, [], "ShowCursor") declare-c(hide-cursor, [], "HideCursor") @@ -313,7 +313,7 @@ declare-c(is-cursor-hidden, [], bool, "IsCursorHidden") ;; The shape the pointer takes. raylib's SetMouseCursor says `int` and means ;; one of these eleven, so the Flan face is the enum for the same reason ;; set-exit-key takes a Key: the call is made every frame from a hover test, -;; and `(rl/set-mouse-cursor :cursor-ibeam)` is checked against the members +;; and `rl/set-mouse-cursor(:cursor-ibeam)` is checked against the members ;; where an i32 would take any number at all — including the one off-by-one ;; that picks the arrow instead of the I-beam and looks like nothing at all ;; went wrong. @@ -482,7 +482,7 @@ declare-c(get-world-to-screen-2d, [position Vector2 camera Camera2D], Vector2, ;; not a number. ;; ;; `projection` is `int` in the header and `CameraProjection` here, which is -;; the same four bytes with a face on it: a Flan defenum lowers to int32_t in +;; the same four bytes with a face on it: a Flan enum lowers to int32_t in ;; a struct field exactly as it does in a parameter, and the layout check ;; knows that, so it accepts an enum where the header says `int` and still ;; refuses an `f64` where the header says `float`. What it buys is at the @@ -773,7 +773,7 @@ struct Image(data: Ptr(u8), width: i32, height: i32, mipmaps: i32, format: i32) ;; everywhere one is passed, and there is nothing in an `int` to say that 7 is ;; the one a texture upload requires — which is exactly the trade ;; TextureFilter and MouseCursor already made, and the reason this is a -;; defenum rather than a row of defconsts. +;; enum rather than a row of consts. ;; ;; The set is closed and is here whole, compressed members included, because a ;; subset would put the hole where the next caller looks: `format` is a field @@ -889,7 +889,7 @@ declare-c(image-crop, [image Ptr(Image) crop Rectangle], "ImageCrop") ;; duplicates it, which is what this was originally reached for — though ;; image-copy in the generated half says that in one argument and is the ;; better call for it. (An earlier comment here said 5.5 had no ImageCopy. It -;; does — raylib-5.5.h line 1348 — and generated.flan has bound it all along.) +;; does — raylib-5.5.h line 1348 — and generated.fln has bound it all along.) ;; ;; The result owns its own buffer: unload-image it, like anything else that ;; allocated. @@ -917,7 +917,7 @@ declare-c(load-texture-from-image, [image Image], Texture2D, ;; ;; Immediate-mode drawing: each of these needs a GL context, so a window has ;; to be open and none of them can be in the acceptance table. They are -;; exercised by running sand.flan and looking at it, which is the honest +;; exercised by running sand.fln and looking at it, which is the honest ;; description — "it links" is not "it draws the right thing". ;; ;; raylib's own naming is kept: a plain name fills, `-lines` outlines, and a @@ -954,7 +954,7 @@ declare-c(draw-circle-lines-v, [center Vector2 radius f32 color Color], ;; Two radii, horizontal then vertical. Equal radii is a circle, so a binding ;; that exchanged them would be invisible unless they differ — which is why -;; sand.flan's ellipse is deliberately wider than it is tall. +;; sand.fln's ellipse is deliberately wider than it is tall. declare-c(draw-ellipse, [x i32 y i32 radius-h f32 radius-v f32 color Color], "DrawEllipse") @@ -1014,14 +1014,14 @@ declare-c(draw-rectangle-rounded-lines-ex, ;; ;; Eleven entry points take an array of vectors as a pointer plus an `int` ;; count. A Flan slice already carries both, so every call site that does not -;; go through a wrapper has to take the slice apart itself — `(addr (at pts -;; 0))` and `(length pts)`, twice, in the right order — and the compiler cannot +;; go through a wrapper has to take the slice apart itself — `addr(pts[0])` +;; and `length(pts)`, twice, in the right order — and the compiler cannot ;; check that the two halves came from the same slice. The wrapper is where ;; that idiom lives, which is the rule check-collision-point-poly set. ;; ;; It also guards the empty case, which is the part a hand-written call site ;; gets wrong rather than merely writes out. raylib takes a count of 0 and -;; draws nothing, but `(at pts 0)` on an empty slice is out of bounds before +;; draws nothing, but `pts[0]` on an empty slice is out of bounds before ;; raylib is ever reached: the safe call is "do not call at all", and it is ;; written once here instead of at every use. ;; @@ -1146,7 +1146,7 @@ declare-c(get-screen-height, [], i32, "GetScreenHeight") ;; *at all* without a pad plugged in: with no gamepad, is-gamepad-available is ;; false, every button predicate is false and every axis reads 0.0, which is ;; also exactly what a wrapper with its two int arguments exchanged would -;; report. So these are bound, wired into sand.flan's HUD, and honestly +;; report. So these are bound, wired into sand.fln's HUD, and honestly ;; described as untested — the only check they get is that a pad moves the ;; read-out. ;; @@ -1234,7 +1234,7 @@ declare-c(get-gamepad-axis-movement, [pad i32 axis GamepadAxis], f32, ;; silently accepted integers would give up what makes a keyword argument ;; checkable. The consequence is simply that an enum parameter cannot be ;; indexed, and the caller spells the loop as a cond over the members it -;; knows — which is what examples/core-input-gamepad.flan does. +;; knows — which is what examples/core-input-gamepad.fln does. ;; SetGamepadVibration is NOT bound, and the reason is not the usual one. Two ;; things are wrong with it at once. Its arity changed — 5.1-dev takes three @@ -1249,7 +1249,7 @@ declare-c(get-gamepad-axis-movement, [pad i32 axis GamepadAxis], f32, ;; ;; Touch is a superset of the mouse on a desktop: with no touchscreen, ;; get-touch-point-count is 0 but get-touch-position 0 still tracks the mouse, -;; which is what makes it visible in sand.flan at all. +;; which is what makes it visible in sand.fln at all. ;; ;; The gesture system is fed by raylib's own event polling, so a gesture is ;; only ever detected inside a window's frame loop — nothing here is headless @@ -1259,7 +1259,7 @@ declare-c(get-gamepad-axis-movement, [pad i32 axis GamepadAxis], f32, ;; several and is-gesture-detected tests against one. That is why the enabling ;; call below takes a u32 and not a Gesture — a keyword can only ever name one ;; member, and `gesture-all` is spelled out below so the common case still -;; reads. The defconst and the members now share the `gesture-` stem, which +;; reads. The const and the members now share the `gesture-` stem, which ;; is the prefix reading its way out of the enum and into the constant beside ;; it. enum Gesture @@ -1319,7 +1319,7 @@ declare-c(get-gesture-hold-duration, [], f32, "GetGestureHoldDuration") ;; The one thing the layout gets for free: RenderTexture2D is a u32 and two ;; Texture2Ds, and Texture2D is already pinned as far as anything headless can ;; pin it, so the only new claim here is the order of the three members. -;; sand.flan draws through one, which is where a wrong order shows up. +;; sand.fln draws through one, which is where a wrong order shows up. struct RenderTexture2D(id: u32, texture: Texture2D, depth: Texture2D) @@ -1337,7 +1337,7 @@ declare-c(unload-render-texture, [target RenderTexture2D], ;; Everything drawn between these two lands in the target instead of the ;; screen, and the target's texture comes out of the GPU upside down — raylib ;; renders it bottom-up — so drawing it back with a NEGATIVE source height is -;; not a flourish, it is the correction. sand.flan does exactly that. +;; not a flourish, it is the correction. sand.fln does exactly that. declare-c(begin-texture-mode, [target RenderTexture2D], "BeginTextureMode") declare-c(end-texture-mode, [], "EndTextureMode") @@ -1353,7 +1353,7 @@ declare-c(end-texture-mode, [], "EndTextureMode") ;; That makes Wave the audio equivalent of the Image family — raylib ;; *computes* with it, headlessly — and it is the only part of this section ;; the acceptance table asserts. Everything from Sound down is exercised by -;; running sand.flan with a working sound server, and a machine without one +;; running sand.fln with a working sound server, and a machine without one ;; gets silence rather than a crash: init-audio-device logs a warning, every ;; load answers a zeroed struct and every play is a no-op. @@ -1594,7 +1594,7 @@ declare-c(load-font, [path str], Font, "LoadFont") ;; raylib's own convention is that a NULL pointer with a count of 0 means the ;; default ASCII set, and the wrapper keeps it — but Flan has no null pointer ;; literal, so the null comes from the one place the language does hand out -;; zeroed bytes: a `defonce` with no initialiser is BSS (plan.org, zero +;; zeroed bytes: a `once` with no initialiser is BSS (plan.org, zero ;; values), and a zeroed (Ptr i32) is exactly a null one. It is never written ;; to and never read through; raylib only ever compares it against NULL. once default-codepoints: Ptr(i32) @@ -1685,7 +1685,7 @@ declare-c(draw-text-codepoint, ;; which is also its answer for genuinely malformed UTF-8. Nothing in the ;; result tells the two apart. docs/PORTING.md §A.1 is the whole story. ;; -;; So the declaration says `(Ptr u8)` and means it. That is a hand-written line +;; So the declaration says `Ptr(u8)` and means it. That is a hand-written line ;; over a `const char *` the importer would have rendered as `string`, which is ;; exactly the case lib/cimport.ml's [ptr_agrees] exists for, and the generated ;; half no longer carries the string-faced version at all — a binding that is @@ -1713,7 +1713,7 @@ fn get-codepoint-previous(text: [const u8], offset: i32, codepoint-size: Ptr(i32 ;; ;; Layouts only, read off raylib.h 5.5 and checked against it on every build. ;; Describing them is what lets the importer bind the Load/Gen/Draw/Unload -;; families over them in generated.flan; none of those calls is written here. +;; families over them in generated.fln; none of those calls is written here. ;; ;; The field names are the header's through the kebab rule, which is how the ;; layout check pairs them, so Matrix's are m-0 to m-15 in raylib's order — a diff --git a/vendor/raylib/vector.fln b/vendor/raylib/vector.fln index 43280286..baf61cb6 100644 --- a/vendor/raylib/vector.fln +++ b/vendor/raylib/vector.fln @@ -10,7 +10,7 @@ ;;;; the arithmetic in Flan, or a small C file re-exporting them as symbols. ;;;; ;;;; It is written in Flan, and the measurement that decided it was already -;;;; taken: examples/shapes-following-eyes.flan is an example whose every +;;;; taken: examples/shapes-following-eyes.fln is an example whose every ;;;; line is vector maths, ported without a vector library, and its own ;;;; header reports that this cost nothing — the C does not use raymath there ;;;; either. A C shim would buy identical arithmetic at the price of a @@ -25,7 +25,7 @@ ;;;; ;;;; ── Why this is a file of its own ─────────────────────────────────── ;;;; -;;;; The split is on `declare-c`, not on "idiomatic". raylib.flan is the +;;;; The split is on `declare-c`, not on "idiomatic". raylib.fln is the ;;;; package's statement about C: every line in it is a declaration or a thin ;;;; wrapper over one, it is the file the header check reads hand-written ;;;; signatures out of, and a wrong line in it stops the build. There is not @@ -34,15 +34,15 @@ ;;;; nothing here can be made wrong by raylib changing. A reader who wants to ;;;; know what the package claims about C should not have to walk past four ;;;; hundred lines of float arithmetic to find out, and 1300 lines of -;;;; raylib.flan is already the argument against adding to it. +;;;; raylib.fln is already the argument against adding to it. ;;;; -;;;; A package is a directory, so this is simply another .flan beside the +;;;; A package is a directory, so this is simply another .fln beside the ;;;; others and is qualified `rl/` like the rest of it. ;;;; ;;;; ── Names ─────────────────────────────────────────────────────────── ;;;; ;;;; `v2-` and `v3-`, not `vector2-`. These appear nested inside each other — -;;;; `(rl/v2-add p (rl/v2-scale d t))` is the ordinary shape — and the longer +;;;; `rl/v2-add(p, rl/v2-scale(d, t))` is the ordinary shape — and the longer ;;;; spelling puts more characters between the reader and the arithmetic than ;;;; it puts meaning. The prefix still says the type, which is the part a ;;;; language without generics needs it to say. @@ -52,7 +52,7 @@ ;;;; `clamp` and `lerp`. Both are already in the prelude — clamp as a macro ;;;; (prelude.ml, "clamp is a macro and not a function"), lerp as a function ;;;; — and both are unqualified names every program already has; -;;;; examples/textures-fog-of-war.flan calls the prelude's clamp today. A +;;;; examples/textures-fog-of-war.fln calls the prelude's clamp today. A ;;;; second `rl/lerp` would not even be the same function: the prelude writes ;;;; the weighted sum `(1-t)a + tb`, which returns b exactly at t = 1.0, ;;;; where raymath writes `a + t*(b - a)`, which does not once rounding is @@ -77,8 +77,8 @@ fn inverse-lerp(value: f32, start: f32, end: f32) -> f32 ;; for extrapolation — a caller who wants it bounded writes the prelude's ;; clamp around it and can see that they did. ;; -;; Written as one expression rather than as (lerp out-start out-end -;; (inverse-lerp ...)) because the prelude's lerp is the weighted-sum form +;; Written as one expression rather than as lerp(out-start, out-end, +;; inverse-lerp(...)) because the prelude's lerp is the weighted-sum form ;; and raymath's Remap is the a + t*(b - a) form; composing them would be a ;; different function in the last bit. fn remap(value: f32, in-start: f32, in-end: f32, out-start: f32, out-end: f32) -> f32 diff --git a/web/examples/quotes.sh b/web/examples/quotes.sh index 631bf749..4bd5902d 100644 --- a/web/examples/quotes.sh +++ b/web/examples/quotes.sh @@ -107,8 +107,8 @@ want "xfer channel" "$(printf '%s\n' "$ir" | grep 'define {} @"flan.main"')" want "shim wrapper" "$("$FLAN" shim "$here/shimdemo.flan" | grep 'GetMousePosition();')" # Lines quoted verbatim from repository files. -want "raylib binding" "$(grep -F 'unload-texture' "$root/vendor/raylib/raylib.flan")" -want "agent declare" "$(grep -F 'flan_agent_poll' "$root/vendor/agent/agent.flan" | head -1)" +want "raylib binding" "$(grep -F 'unload-texture' "$root/vendor/raylib/raylib.fln")" +want "agent declare" "$(grep -F 'flan_agent_poll' "$root/vendor/agent/agent.fln" | head -1)" want "conditions.org" "$(grep -F 'Innermost frame offering the name wins' "$root/conditions.org")" # The value renderer, anchored in the test corpus rather than in NEXT.md (the # rolling scratch document TODO.org replaced). It used to grep NEXT.md for this diff --git a/web/index.html b/web/index.html index ab340edd..a7198fab 100644 --- a/web/index.html +++ b/web/index.html @@ -1858,10 +1858,10 @@ directory may carry a headers file naming the library's own C heade flan generate-c <package-dir> reads it with clang -Xclang -ast-dump=json, turns every function it can represent into the same declare-c line a person would have written, and writes them to -generated.flan in the package — which is committed.

+generated.fln in the package — which is committed.

$ flan generate-c vendor/raylib
-wrote vendor/raylib/generated.flan: 268 declarations, 117 refused, of 581 functions
+wrote vendor/raylib/generated.fln: 318 declarations, 61 refused, of 581 functions
 in vendor/raylib/raylib-5.5.h.
 Every defstruct, every hand-written declare-c and every mapped
 constant agrees with it.