64 lines
2.2 KiB
OCaml
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
|