flan/lib/prelude.ml

64 lines
2.2 KiB
OCaml

(** The milestone-2 prelude, written in Flan.
Printing is deliberately *not* a primitive (plan.org, Milestone-2
primitives): [write-stdout] is the one output primitive and everything
above it is Flan. That is what keeps a second backend cheap — a primitive
is the only thing implemented twice.
It lives here as a string rather than as a file because there is no package
loader yet; at milestone 3 it becomes an ordinary [core:] package and this
module goes away. The acceptance programs may call anything defined here.
No overloading: [print-f64] and [print-str] name the type, because
compile-time overloading before the checker is stable is how a small
language stops being one. A single [println] is milestone 5. *)
let source = {flan|
(defn print-bytes [b [u8]]
(write-stdout b))
(defn print-str [s string]
(write-stdout (bytes s)))
(defn print-f64 [x f64]
(write-stdout (f64->bytes x)))
(defn print-i64 [x i64]
(write-stdout (i64->bytes x)))
(defn newline []
(write-stdout (bytes "\n")))
;; A seeded PRNG in Flan rather than libc's, because a grid hash is only a
;; regression test if the sequence is byte-identical on native and wasm32
;; (plan.org, RNG is ours). PCG-XSH-RR 32: one u64 LCG step per draw, folded
;; down to 32 bits by an xorshift and rotated by the state's top five bits.
(defvar rand-state u64 6364136223846793005)
(defn rand-seed [seed u64]
(set rand-state (+ (* seed 6364136223846793005) 1442695040888963407)))
(defn rand-u32 [] u32
(let [s rand-state]
(set rand-state (+ (* s 6364136223846793005) 1442695040888963407))
;; The rotate is masked to 5 bits: a 32-bit shift by 32 is poison in LLVM,
;; and r = 0 is the case that would ask for it.
(let [x (u32 (>> (bit-xor (>> s 18) s) 27))
r (u32 (>> s 59))]
(bit-or (>> x r) (<< x (bit-and (- 32 r) 31))))))
;; In [0, 1). The divisor is 2^32 exactly, so the result never reaches 1.0.
(defn rand-f32 [] f32
(/ (f32 (rand-u32)) 4294967296.0))
;; Prints s and then a newline. Takes a string, not an Option or an any —
;; there is nothing to dispatch on yet.
(defn print-line [s string]
(print-str s)
(newline))
|flan}
let file = "<prelude>"
let forms () = Reader.read_all ~file source