diff --git a/web/examples/quotes.sh b/web/examples/quotes.sh index d7d26a5..44f6465 100644 --- a/web/examples/quotes.sh +++ b/web/examples/quotes.sh @@ -29,6 +29,13 @@ want "flan usage" "$("$FLAN" 2>&1 | sed -n 2p)" # calc-me, the first acceptance program, still answers what the page says. want "calc-me" "$("$FLAN" run "$root/calc-me.flan" '1 + 2 * (3 - 0.5) / 2')" +# The sand hash. The page shows it twice — native and wasm32 — and the claim is +# that the two agree; only the native half is cheap enough to check here. +want "sand hash" "$("$FLAN" run "$root/test/programs/sand-headless.flan")" + +# The two cross-target refusals, in the compiler's own words. +want "run --target" "$("$FLAN" run "$here/hello.flan" --target=wasm32-wasi 2>&1)" + # The refusal and diagnostic messages quoted in the prose and in the # "Not implemented yet" table. for pair in \ diff --git a/web/index.html b/web/index.html index 5a2682c..55889f1 100644 --- a/web/index.html +++ b/web/index.html @@ -905,6 +905,8 @@ is generated; a Flan string crosses as ptr+len, exactly as it is stored.

1
+

That is 1.0, printed by the same rule as before.

+

declare-c names the C library's own function in the C library's own signature, and the compiler writes the wrapper. This is what raylib's package is made of — one line per binding:

@@ -927,7 +929,8 @@ full of garbage rather than as a link error.

So the boundary has one wrapper per binding, each flattening the aggregates: a struct returns through an out-pointer, a struct argument is passed by pointer, and clang classifies all of it, per target, for free. flan shim <file> prints -the whole generated file:

+the whole generated file, of which this is the end — the rest is the typedefs +and a comment saying not to edit it:

(defstruct Vector2 [x f32  y f32])
 
@@ -1170,8 +1173,19 @@ uses; it is program-scoped, so in sand you write sim/settle and not
 
 

Native x86-64 is the development target. --target=wasm32-wasi produces a module, and the headless sand acceptance program prints the same 64-bit hash under it as -natively, byte for byte, at -O2 and at -O0. That is the -milestone the RNG is written in Flan for.

+it does natively:

+ +
$ flan run test/programs/sand-headless.flan
+2256461126764447066
+$ flan build test/programs/sand-headless.flan --target=wasm32-wasi -o sand.wasm
+$ node --no-warnings test/wasm-run.mjs sand.wasm
+2256461126764447066
+ +

That number is the whole point of writing the RNG in Flan rather than calling libc's: +a grid hash is only a regression test if the sequence is byte-identical on both targets. +It holds at -O2 and at -O0. The wasm side needs a +wasm32 builtins archive — from wasi-sdk, or emscripten's substituting for +it — and the compiler names every path it looked in when it cannot find one.

Dev and release builds are deliberately different. --dev means indirection cells and -rdynamic, which is what exports the cells for a loaded @@ -1179,9 +1193,16 @@ module to bind to; release builds call directly, emit constants as constants, an the folding back. Dev builds are not pruned by reachability, because what a REPL may redefine next is not a function of what has been called so far.

-

Some things are refused by name rather than half-supported: ---dev with a wasm target and flan run --target=, both because a -cross-built module is not something this host can dlopen or exec.

+

Some things are refused by name rather than half-supported, and both cross-target +refusals say why:

+ +
$ flan run hello.flan --target=wasm32-wasi
+flan run: --target is refused — a cross-built module is not something this host
+can exec. Use flan build --target=... and a wasm runtime.
+
+$ flan build hello.flan --dev --target=wasm32-wasi
+wasm32: --dev is native only — the reload path is dlopen, which wasm32 has no
+equivalent of

Build time for calc-me.flan is about 110ms, of which the frontend — read, parse, load, check, emit — is under 10ms. Every C translation unit goes through an object