I just wrote a smol PRNG in Garnet and it looks like this:
--- A test implementation of the PCG PRNG from https://sr.ht/~icefox/oorandom
--- Fails to give perfect results after the first 3 numbers due to signed/unsigned
--- arithmetic nonsense, but it's a start.
type Rand32 = struct
state: I64,
inc: I64,
end
const RAND32_DEFAULT_INC I64 = 1442695040888963407
const RAND32_MULTIPLIER I64 = 6364136223846793005
fn rand32_new_inc(seed I64, inc I64) Rand32 =
let rng = Rand32({
.state = 0,
.inc = __bor_i64(__lshift_i64(inc, 1), 1),
})
let mut rng2 = rand32_u32(rng).0
rng2$.state = rng2$.state + seed
let rng3 = rand32_u32(rng2).0
rng3
end
fn rand32_new(seed I64) Rand32 =
rand32_new_inc(seed, RAND32_DEFAULT_INC)
end
fn rand32_u32(rand Rand32) {Rand32, I32} =
let oldstate = rand$.state
let mut newrng = rand
newrng$.state = oldstate * RAND32_MULTIPLIER + rand$.inc
-- ok maybe binary op operators are an ok idea
let xorshifted = __i64_to_i32( __rshift_i64( __bxor_i64( __rshift_i64(oldstate, 18), oldstate), 27))
let rot = __i64_to_i32(__rshift_i64(oldstate, 59))
{newrng, __ror_i32(xorshifted, rot)}
end
fn main() {} =
let mut rng = rand32_new(54321);
let mut i I32 = 0
loop
if i == 3 then break end
i = i + 1
let res = rand32_u32(rng)
rng = res.0
let out I32 = res.1
__println(out)
end
end
Now let me take a moment to ponder what I want it to look like.
- Unsigned integers
- Bit operators
- borrows/unique borrows for function calls
+=
-=
*=
etc assignment operators- Imports of some kind of stdlib
- While loops
Things I'm not so sure about yet:
- Type unwrap operator
- Wrapping vs checked operators
- Associated consts?
- Some kind of method decl shortcut syntax?
So I guess it becomes something like this:
type Rand32 = struct state: U64, inc: U64, end const RAND32_DEFAULT_INC U64 = 1442695040888963407 const RAND32_MULTIPLIER U64 = 6364136223846793005 const RAND32 = { .new = fn(seed U64) Rand32 = RAND32.new_inc(seed, RAND32_DEFAULT_INC) end .new_inc = fn(seed U64, inc U64) Rand32 = let mut rng = Rand32 { .state = 0, .inc = inc << 1 | 1, } RAND32.next(rng &uniq) rng$.state = rng$.state + seed RAND32.next(rng &uniq) rng end .next = fn(rand &uniq Rand32) U32 = let oldstate = rand^$.state rand^$.state = oldstate * RAND32_MULTIPLIER + rand^$.inc let xorshifted = cast(|U32| ((oldstate >> 18) ^ oldstate) >> 27) let rot = cast(|U32| oldstate >> 59) U32.ror(xorshifted, rot) end } fn main() = let mut rng = RAND32.new(54321) let mut i U32 = 0 while i != 0 do let res = RAND32.next(rng) println(res) i += 1 end end
Not so sure if the code atually needs to be in a module yet, but it feels a little odd to have methods flapping around in the breeze. A UFCS would help but again that's kinda tricksy rn. Maybe
.foo = fn(...)
can be sugar'd intofn foo(...)
in a struct decl? Still, overall it isn't the worst thing ever.
Oh right, still need to get rid of
@
for generic types, sigh.