diff --git a/projects/aether-lang-c3d8/JOURNAL.md b/projects/aether-lang-c3d8/JOURNAL.md index 7b32a557..b50dc0e3 100644 --- a/projects/aether-lang-c3d8/JOURNAL.md +++ b/projects/aether-lang-c3d8/JOURNAL.md @@ -63,6 +63,34 @@ compile the same optimized core — and the equivalence checks prove it preserve ## Ideas / backlog +### Aether 30.2 — a standard library worth the name (planned + shipped this session) + +30.0 and 30.1 made Aether *pleasant to write* (comprehensions, ranges, sections); this makes it +*productive* to write, by giving it the list vocabulary every functional programmer expects. All +fifteen functions are written **in Aether itself** on top of the existing primitives — so they cost +the type checker and the three backends nothing new, and the differential suite covers them exactly +like user code. They pair directly with what just shipped: `sort (concatMap (fn x -> [x, 0 - x]) [1 .. n])`, +`partition (> 0)`, `takeWhile (< limit)`, `zipWith (+)`. + +- [x] **Transformers:** `zipWith f xs ys`, `concatMap f xs` (the list-monad bind), `scanl f z xs` + (foldl keeping every running accumulator), `iterate n f x` (a bounded orbit `[x, f x, f (f x), …]`). +- [x] **Splitters:** `takeWhile p`, `dropWhile p`, `span p` (their pair), `partition p` (order + preserved in both halves). +- [x] **Ordering:** `insert x xs` (into a sorted list) and `sort` (ascending insertion sort) — both + polymorphic on the structural `≤`, so `sort ["pear", "apple"]` works as readily as on ints. +- [x] **Reducers:** `product`, `maximum`, `minimum` (partial on `[]`, like `head`), `last`, `init`. +- [x] **Verification:** a new 200-program **stdlib fuzzer** (`stdlibFuzz.ts`) generating random calls + across all eleven order-sensitive combinators, each checked against an **independent TypeScript + reference** *and* the JS backend (300/300 across four seeds); a 15-case in-app `stdlib` battery + (suite 182 → 197, WASM ≡ VM 166 → 181); a gallery example; About/stdlib updates. Every existing + suite (property suite, optimizer/SpecConstr/SROA/comprehension/section fuzzers) stays green. +- [ ] **A `Maybe`/`Option` in the prelude** would unlock the total reducers (`headOpt`, `find`, + `lookup`, `mapMaybe`) — it needs a prelude *type* declaration, not just `let` defs, so it's a small + extension to how `PRELUDE_DEFS` are wired. +- [ ] **`sortBy` / `groupBy` / `nub`** once a comparator/eq-callback convention is settled, and a + merge sort behind `sort` for the log-linear guarantee on long lists. +- [ ] **`foldr1`/`foldl1`/`scanr`** to round out the fold family. + ### Aether 30.1 — operator sections, point-free style (+ a real JS-backend bug this caught) (planned + shipped this session) With comprehensions and ranges in (30.0), the next everyday convenience the language lacked was @@ -2243,6 +2271,7 @@ finds `sum x`, `abs x`, `max x 0` (clamp), `reverse x`, `map (fn h -> h + h) x`, - list: `map filter foldl foldr length append reverse sum range enumFromTo enumFromThenTo take drop elem all any concat zip replicate` (`enumFromTo`/`enumFromThenTo` back the `[a .. b]` / `[a, s .. b]` range literals) +- list (30.2): `zipWith concatMap takeWhile dropWhile span partition scanl insert sort product maximum minimum last init iterate` - combinators: `subtract flip` (companions to operator sections — `(subtract n)` is the section `-` can't give) - string: `strlen toUpper toLower chars join parseInt` (+ `show`, `^`) - primitives: `head tail empty print sqrt sin cos floor toFloat pi abs min max` @@ -2250,6 +2279,21 @@ finds `sum x`, `abs x`, `max x 0` (clamp), `reverse x`, `map (fn h -> h + h) x`, ## Session log +- 2026-07-24 (claude): **Aether 30.2 — a standard library worth the name.** After making Aether + pleasant to write (30.0 comprehensions/ranges, 30.1 sections), this makes it productive by adding + the list vocabulary every functional programmer expects — **fifteen** combinators, all written **in + Aether itself** so they cost the type checker and the three backends nothing new: transformers + (`zipWith`, `concatMap`, `scanl`, `iterate`), splitters (`takeWhile`, `dropWhile`, `span`, + `partition`), ordering (`insert`, `sort` — polymorphic on structural `≤`, so `sort ["pear","apple"]` + works), and reducers (`product`, `maximum`, `minimum`, `last`, `init`). They compose directly with + the new syntax: `sort (concatMap (fn x -> [x, 0 - x]) [1 .. n])`, `partition (> 0)`, + `zipWith (+)`. **Verification:** a new 200-program **stdlib fuzzer** (`stdlibFuzz.ts`) generating + random calls across all eleven order-sensitive combinators, each checked against an **independent + TypeScript reference** *and* the JS backend (300/300 across four seeds); a 15-case in-app `stdlib` + battery (suite **182 → 197**, WASM ≡ VM **166 → 181**); a gallery example; About/stdlib updates. No + regression — the property suite (12/12), the optimizer/SpecConstr/SROA fuzzers, and the + comprehension/section fuzzers all stay green. Full CI gate green. + - 2026-07-24 (claude): **Aether 30.1 — operator sections (+ a real JS-backend bug the differential suite caught).** After 30.0's comprehensions, the next everyday convenience missing was **operator sections**. Shipped, again as pure parser sugar desugared in `parseParen` to a lambda (nothing diff --git a/projects/aether-lang-c3d8/src/examples.ts b/projects/aether-lang-c3d8/src/examples.ts index 9ae772a1..6277ef97 100644 --- a/projects/aether-lang-c3d8/src/examples.ts +++ b/projects/aether-lang-c3d8/src/examples.ts @@ -1682,6 +1682,31 @@ let people = [ { name = "Ada", age = 36 }, { name = "Alan", age = 41 }, { name = , names people , map (subtract 1) [10, 20, 30] )`, + }, + { + id: 'stdlib-tour', + title: 'Standard-library tour', + blurb: 'sort, partition, span, scanl, zipWith, takeWhile — the 30.2 list toolkit, point-free.', + visual: false, + code: `// Aether 30.2 — a real list library, all written in Aether itself, and all +// happy to be driven by sections and comprehensions. + +let xs = [ 5, 3, 8, 1, 9, 2, 7, 4, 6 ] in + +// running sums, the sorted list, and a split into evens / odds +let sums = scanl (+) 0 xs in +let sorted = sort xs in +let evens = partition (fn x -> x % 2 == 0) xs in + +// combine two lists element-wise; keep a prefix; grab the extremes +let dots = zipWith ( * ) [1, 2, 3] [10, 20, 30] in +let small = takeWhile (< 9) sorted in +let bounds = (minimum xs, maximum xs) in + +// it all composes: reflect [1..4] through zero, then sort the 8 points +let mirror = sort (concatMap (fn x -> [x, 0 - x]) [1 .. 4]) in + +(sums, sorted, evens, dots, small, bounds, mirror)`, }, { id: 'comprehension-garden', diff --git a/projects/aether-lang-c3d8/src/lang/prelude.ts b/projects/aether-lang-c3d8/src/lang/prelude.ts index 53ef6c71..956cd5d8 100644 --- a/projects/aether-lang-c3d8/src/lang/prelude.ts +++ b/projects/aether-lang-c3d8/src/lang/prelude.ts @@ -331,4 +331,96 @@ export const PRELUDE_DEFS: PreludeDef[] = [ doc: 'replicate n x — a list of n copies of x', src: 'fn n x -> if n <= 0 then [] else x :: replicate (n - 1) x', }, + + // ---- Aether 30.2 — a richer list toolkit (all written in Aether itself) ---- + { + name: 'zipWith', + recursive: true, + doc: 'zipWith f xs ys — combine two lists element-wise with f', + src: 'fn f xs ys -> if empty xs then [] else if empty ys then [] else f (head xs) (head ys) :: zipWith f (tail xs) (tail ys)', + }, + { + name: 'concatMap', + recursive: true, + doc: 'concatMap f xs — map f then flatten (the list-monad bind)', + src: 'fn f xs -> if empty xs then [] else append (f (head xs)) (concatMap f (tail xs))', + }, + { + name: 'takeWhile', + recursive: true, + doc: 'takeWhile p xs — the longest prefix whose elements all satisfy p', + src: 'fn p xs -> if empty xs then [] else if p (head xs) then head xs :: takeWhile p (tail xs) else []', + }, + { + name: 'dropWhile', + recursive: true, + doc: 'dropWhile p xs — drop the longest prefix satisfying p, keep the rest', + src: 'fn p xs -> if empty xs then [] else if p (head xs) then dropWhile p (tail xs) else xs', + }, + { + name: 'span', + recursive: false, + doc: 'span p xs — (takeWhile p xs, dropWhile p xs)', + src: 'fn p xs -> (takeWhile p xs, dropWhile p xs)', + }, + { + name: 'partition', + recursive: true, + doc: 'partition p xs — (elements where p holds, elements where it doesn’t), order preserved', + src: 'fn p xs -> if empty xs then ([], []) else match partition p (tail xs) with (yes, no) -> if p (head xs) then (head xs :: yes, no) else (yes, head xs :: no)', + }, + { + name: 'scanl', + recursive: true, + doc: 'scanl f z xs — like foldl, but keeping every intermediate accumulator (starts with z)', + src: 'fn f z xs -> z :: (if empty xs then [] else scanl f (f z (head xs)) (tail xs))', + }, + { + name: 'insert', + recursive: true, + doc: 'insert x xs — insert x into an already-sorted list, keeping it sorted', + src: 'fn x xs -> if empty xs then [x] else if x <= head xs then x :: xs else head xs :: insert x (tail xs)', + }, + { + name: 'sort', + recursive: false, + doc: 'sort xs — ascending insertion sort (works on any comparable element)', + src: 'foldr insert []', + }, + { + name: 'product', + recursive: false, + doc: 'product xs — the product of an Int list', + src: 'foldl (fn a x -> a * x) 1', + }, + { + name: 'maximum', + recursive: false, + doc: 'maximum xs — the largest element (partial: undefined on [])', + src: 'fn xs -> foldl max (head xs) (tail xs)', + }, + { + name: 'minimum', + recursive: false, + doc: 'minimum xs — the smallest element (partial: undefined on [])', + src: 'fn xs -> foldl min (head xs) (tail xs)', + }, + { + name: 'last', + recursive: true, + doc: 'last xs — the final element (partial: undefined on [])', + src: 'fn xs -> if empty (tail xs) then head xs else last (tail xs)', + }, + { + name: 'init', + recursive: true, + doc: 'init xs — every element but the last (partial: undefined on [])', + src: 'fn xs -> if empty (tail xs) then [] else head xs :: init (tail xs)', + }, + { + name: 'iterate', + recursive: true, + doc: 'iterate n f x — the n-element list [x, f x, f (f x), …]', + src: 'fn n f x -> if n <= 0 then [] else x :: iterate (n - 1) f (f x)', + }, ] diff --git a/projects/aether-lang-c3d8/src/lang/stdlibFuzz.ts b/projects/aether-lang-c3d8/src/lang/stdlibFuzz.ts new file mode 100644 index 00000000..c918c766 --- /dev/null +++ b/projects/aether-lang-c3d8/src/lang/stdlibFuzz.ts @@ -0,0 +1,176 @@ +// Aether — an in-browser DIFFERENTIAL FUZZER for the 30.2 list standard library. +// +// The new combinators (`sort`, `partition`, `span`, `takeWhile`/`dropWhile`, +// `scanl`, `zipWith`, `insert`, `product`, `maximum`/`minimum`, …) are written in +// Aether itself and compiled into every program. This harness generates hundreds +// of random calls to them and proves, for each: +// +// • the compiled program's VM result equals an INDEPENDENT reference (the same +// operation computed directly here in TypeScript), and +// • that value re-appears from the JavaScript backend (VM ≡ JS). +// +// So the library isn't merely "tested" — every call is checked against a second, +// separate implementation of what it should mean, on two backends. Deterministic +// given the seed; pure logic, so it also runs head-less under Node. + +import { runPipeline } from './pipeline.ts' +import { compileToJs, runJsModule } from './jsBackend.ts' +import { valueToString } from './values.ts' + +export interface StdlibFuzzResult { + total: number + passed: number + /** distinct combinators exercised across the batch */ + covered: number + failures: { code: string; detail: string }[] +} + +type Rng = () => number +function makeRng(seed: number): Rng { + let s = seed >>> 0 + return () => { + s = (s * 1664525 + 1013904223) >>> 0 + return s / 4294967296 + } +} +const int = (rng: Rng, lo: number, hi: number): number => lo + (Math.floor(rng() * (hi - lo + 1)) | 0) +const randList = (rng: Rng, maxLen: number, hi: number): number[] => { + const n = int(rng, 0, maxLen) + const xs: number[] = [] + for (let i = 0; i < n; i++) xs.push(int(rng, 0, hi)) + return xs +} + +const fmtList = (xs: number[]): string => `[${xs.join(', ')}]` +const fmtLit = (xs: number[]): string => `[${xs.join(', ')}]` +const pairLL = (a: number[], b: number[]): string => `(${fmtList(a)}, ${fmtList(b)})` + +// each op: build the Aether source and the reference string, from fresh randoms +const OPS: readonly ((rng: Rng) => { code: string; expected: string })[] = [ + // sort + (rng) => { + const xs = randList(rng, 8, 9) + return { code: `sort ${fmtLit(xs)}`, expected: fmtList([...xs].sort((a, b) => a - b)) } + }, + // insert into a sorted list + (rng) => { + const xs = randList(rng, 7, 9).sort((a, b) => a - b) + const k = int(rng, 0, 9) + const out = [...xs] + let i = 0 + while (i < out.length && out[i] < k) i++ + out.splice(i, 0, k) + return { code: `insert ${k} ${fmtLit(xs)}`, expected: fmtList(out) } + }, + // partition on parity + (rng) => { + const xs = randList(rng, 8, 9) + return { + code: `partition (fn x -> x % 2 == 0) ${fmtLit(xs)}`, + expected: pairLL(xs.filter((x) => x % 2 === 0), xs.filter((x) => x % 2 !== 0)), + } + }, + // span (< k) + (rng) => { + const xs = randList(rng, 8, 9) + const k = int(rng, 0, 9) + let i = 0 + while (i < xs.length && xs[i] < k) i++ + return { code: `span (< ${k}) ${fmtLit(xs)}`, expected: pairLL(xs.slice(0, i), xs.slice(i)) } + }, + // takeWhile (< k) + (rng) => { + const xs = randList(rng, 8, 9) + const k = int(rng, 0, 9) + let i = 0 + while (i < xs.length && xs[i] < k) i++ + return { code: `takeWhile (< ${k}) ${fmtLit(xs)}`, expected: fmtList(xs.slice(0, i)) } + }, + // dropWhile (< k) + (rng) => { + const xs = randList(rng, 8, 9) + const k = int(rng, 0, 9) + let i = 0 + while (i < xs.length && xs[i] < k) i++ + return { code: `dropWhile (< ${k}) ${fmtLit(xs)}`, expected: fmtList(xs.slice(i)) } + }, + // scanl (+) z + (rng) => { + const xs = randList(rng, 7, 6) + const z = int(rng, 0, 5) + const acc: number[] = [z] + let s = z + for (const x of xs) { + s += x + acc.push(s) + } + return { code: `scanl (+) ${z} ${fmtLit(xs)}`, expected: fmtList(acc) } + }, + // zipWith (+) + (rng) => { + const xs = randList(rng, 8, 9) + const ys = randList(rng, 8, 9) + const n = Math.min(xs.length, ys.length) + const out: number[] = [] + for (let i = 0; i < n; i++) out.push(xs[i] + ys[i]) + return { code: `zipWith (+) ${fmtLit(xs)} ${fmtLit(ys)}`, expected: fmtList(out) } + }, + // product + (rng) => { + const xs = randList(rng, 6, 5) + return { code: `product ${fmtLit(xs)}`, expected: String(xs.reduce((a, b) => a * b, 1)) } + }, + // maximum of a guaranteed-non-empty list + (rng) => { + const xs = randList(rng, 7, 20) + xs.push(int(rng, 0, 20)) + return { code: `maximum ${fmtLit(xs)}`, expected: String(Math.max(...xs)) } + }, + // minimum of a guaranteed-non-empty list + (rng) => { + const xs = randList(rng, 7, 20) + xs.push(int(rng, 0, 20)) + return { code: `minimum ${fmtLit(xs)}`, expected: String(Math.min(...xs)) } + }, +] + +export function runStdlibFuzz(runs = 200, seed = 0x57d11b): StdlibFuzzResult { + const rng = makeRng(seed) + let passed = 0 + const usedOps = new Set() + const failures: { code: string; detail: string }[] = [] + + for (let i = 0; i < runs; i++) { + const opIdx = int(rng, 0, OPS.length - 1) + usedOps.add(opIdx) + const { code, expected } = OPS[opIdx](rng) + + let vm: string + let coreAst + try { + const r = runPipeline(code, { execute: true }) + if (r.error) { + if (failures.length < 8) failures.push({ code, detail: `${r.error.stage}: ${r.error.message}` }) + continue + } + coreAst = r.coreAst + vm = r.run?.result ? valueToString(r.run.result) : '()' + } catch (e) { + if (failures.length < 8) failures.push({ code, detail: `threw: ${String(e)}` }) + continue + } + if (vm !== expected) { + if (failures.length < 8) failures.push({ code, detail: `VM ${vm} ≠ reference ${expected}` }) + continue + } + try { + const js = runJsModule(compileToJs(coreAst!).full) + if (js.error === null && js.result === vm) passed++ + else if (failures.length < 8) failures.push({ code, detail: `JS ${js.error ?? js.result} ≠ VM ${vm}` }) + } catch (e) { + if (failures.length < 8) failures.push({ code, detail: `JS threw: ${String(e)}` }) + } + } + + return { total: runs, passed, covered: usedOps.size, failures } +} diff --git a/projects/aether-lang-c3d8/src/lang/testSuite.ts b/projects/aether-lang-c3d8/src/lang/testSuite.ts index 5a807ba4..e22de196 100644 --- a/projects/aether-lang-c3d8/src/lang/testSuite.ts +++ b/projects/aether-lang-c3d8/src/lang/testSuite.ts @@ -1481,6 +1481,98 @@ in qsort [3, 1, 4, 1, 5, 9, 2, 6]`, code: 'flip (fn a b -> a - b) 3 10', expected: '7', }, + + // ---- standard library (Aether 30.2) ---- + { + group: 'stdlib', + name: 'zipWith combines two lists', + code: 'zipWith (+) [1, 2, 3] [10, 20, 30]', + expected: '[11, 22, 33]', + }, + { + group: 'stdlib', + name: 'zipWith stops at the shorter list', + code: 'zipWith ( * ) [1, 2, 3, 4] [10, 20]', + expected: '[10, 40]', + }, + { + group: 'stdlib', + name: 'concatMap maps then flattens', + code: 'concatMap (fn x -> [x, x * 10]) [1, 2, 3]', + expected: '[1, 10, 2, 20, 3, 30]', + }, + { + group: 'stdlib', + name: 'takeWhile / dropWhile split at the first failure', + code: '(takeWhile (< 3) [1, 2, 3, 4, 1], dropWhile (< 3) [1, 2, 3, 4, 1])', + expected: '([1, 2], [3, 4, 1])', + }, + { + group: 'stdlib', + name: 'span is takeWhile paired with dropWhile', + code: 'span (fn x -> x != 0) [3, 2, 0, 4, 5]', + expected: '([3, 2], [0, 4, 5])', + }, + { + group: 'stdlib', + name: 'partition keeps order in both halves', + code: 'partition (fn x -> x % 2 == 0) [1, 2, 3, 4, 5, 6]', + expected: '([2, 4, 6], [1, 3, 5])', + }, + { + group: 'stdlib', + name: 'scanl keeps every running accumulator', + code: 'scanl (+) 0 [1, 2, 3, 4]', + expected: '[0, 1, 3, 6, 10]', + }, + { + group: 'stdlib', + name: 'sort orders an Int list', + code: 'sort [3, 1, 4, 1, 5, 9, 2, 6]', + expected: '[1, 1, 2, 3, 4, 5, 6, 9]', + }, + { + group: 'stdlib', + name: 'sort is polymorphic (strings, structural ≤)', + code: 'sort ["pear", "apple", "fig", "date"]', + expected: '["apple", "date", "fig", "pear"]', + }, + { + group: 'stdlib', + name: 'insert keeps a sorted list sorted', + code: 'insert 4 [1, 3, 5, 7]', + expected: '[1, 3, 4, 5, 7]', + }, + { + group: 'stdlib', + name: 'product multiplies an Int list', + code: 'product [1, 2, 3, 4, 5]', + expected: '120', + }, + { + group: 'stdlib', + name: 'maximum / minimum', + code: '(maximum [3, 7, 2, 9, 4], minimum [3, 7, 2, 9, 4])', + expected: '(9, 2)', + }, + { + group: 'stdlib', + name: 'last / init decompose from the right', + code: '(last [1, 2, 3, 4], init [1, 2, 3, 4])', + expected: '(4, [1, 2, 3])', + }, + { + group: 'stdlib', + name: 'iterate builds a bounded orbit', + code: 'iterate 6 ( * 2) 1', + expected: '[1, 2, 4, 8, 16, 32]', + }, + { + group: 'stdlib', + name: 'the toolkit composes with sections & comprehensions', + code: 'sort (concatMap (fn x -> [x, 0 - x]) [ n | n <- [1 .. 3] ])', + expected: '[-3, -2, -1, 1, 2, 3]', + }, ] export function runCase(tc: TestCase): TestResult { diff --git a/projects/aether-lang-c3d8/src/pages/About.tsx b/projects/aether-lang-c3d8/src/pages/About.tsx index a08b9c25..6cf943d1 100644 --- a/projects/aether-lang-c3d8/src/pages/About.tsx +++ b/projects/aether-lang-c3d8/src/pages/About.tsx @@ -198,6 +198,15 @@ export default function About() { usefulness algorithm — non-exhaustive matches are reported with a concrete witness pattern, and unreachable clauses are flagged. +
  • + A real list library. Beyond map/filter/ + fold, the prelude carries zipWith, concatMap,{' '} + scanl, takeWhile/dropWhile, span,{' '} + partition, insert, a polymorphic sort,{' '} + product/maximum/minimum, last/ + init and iterate — all written in Aether itself, so they type-check + and run on all three backends like any other code. +
  • Operator sections. Point-free style: (+ 1) and{' '} (> 0) are right sections, (+) / (::) the bare diff --git a/projects/aether-lang-c3d8/src/pages/Tests.tsx b/projects/aether-lang-c3d8/src/pages/Tests.tsx index 3d6138b2..bb1132cc 100644 --- a/projects/aether-lang-c3d8/src/pages/Tests.tsx +++ b/projects/aether-lang-c3d8/src/pages/Tests.tsx @@ -9,6 +9,8 @@ import { runComprehensionFuzz } from '../lang/comprehensionFuzz.ts' import type { ComprehensionFuzzResult } from '../lang/comprehensionFuzz.ts' import { runSectionFuzz } from '../lang/sectionFuzz.ts' import type { SectionFuzzResult } from '../lang/sectionFuzz.ts' +import { runStdlibFuzz } from '../lang/stdlibFuzz.ts' +import type { StdlibFuzzResult } from '../lang/stdlibFuzz.ts' import { runSemanticsSelfCheck } from '../lang/semanticsSelfCheck.ts' import type { SemSelfResult } from '../lang/semanticsSelfCheck.ts' @@ -20,6 +22,7 @@ export default function Tests() { const [sroaFuzz, setSroaFuzz] = useState(null) const [compFuzz, setCompFuzz] = useState(null) const [secFuzz, setSecFuzz] = useState(null) + const [libFuzz, setLibFuzz] = useState(null) const [semResults, setSemResults] = useState(null) const [running, setRunning] = useState(false) @@ -34,6 +37,7 @@ export default function Tests() { setSroaFuzz(runSroaFuzz()) setCompFuzz(runComprehensionFuzz()) setSecFuzz(runSectionFuzz()) + setLibFuzz(runStdlibFuzz()) setSemResults(runSemanticsSelfCheck()) setRunning(false) }, 10) @@ -375,6 +379,45 @@ export default function Tests() { )} + {libFuzz && ( +
    +
    +

    + Stdlib fuzz — 30.2 list-combinator soundness{' '} + + {libFuzz.passed}/{libFuzz.total} + +

    +

    + {libFuzz.total} randomly generated calls across {libFuzz.covered} new + combinators — sort, insert, partition,{' '} + span, takeWhile/dropWhile, scanl,{' '} + zipWith, product, maximum/minimum — + each proved sound two ways: the compiled program's{' '} + VM result equals an independent reference (a second implementation of + the operation, in TypeScript) and that value{' '} + re-appears on the JavaScript backend (VM ≡ JS). Deterministic, so this + badge is stable. +

    + {libFuzz.failures.length > 0 && ( + + + {libFuzz.failures.map((f, i) => ( + + + + + ))} + +
    + {f.detail} +
    {f.code}
    +
    + )} +
    +
    + )} + {!results && (

    Press “Run all tests” to execute the suite live.

    )}