1 # Pure generators: each takes a Rand.Rng and returns a value beside the next state. 2 import Base 3 import bend-kit-random@0.1.0.1/random.bend as Rand 4 import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes 5 6 # A generator is `Rand.Rng -> T & Rand.Rng`. The same seed replays the same value: 7 # (xs, r) = Gen.list(~U32, ~Gen.u32, 8, Rand.seed(42)) 8 # Sizes are capped at 1024 so lengths and Nats stay small enough to build and shrink. 9 10 # n, capped at 1024. 11 def cap(+n: U32) -> U32: 12 U32.min(n, 1024) 13 14 # A uniform U32. 15 def u32(r: Rand.Rng) -> U32 & Rand.Rng: 16 Rand.next(r) 17 18 # A uniform U32 in [lo, hi); lo when hi <= lo + 1. 19 def u32.range(+lo: U32, hi: U32, r: Rand.Rng) -> U32 & Rand.Rng: 20 Rand.range(lo, hi, r) 21 22 # A uniform size in [0, min(max, 1024)]. 23 def size(+max: U32, r: Rand.Rng) -> U32 & Rand.Rng: 24 Rand.below((cap(max) + 1 : U32), r) 25 26 def nat.fin(xr: U32 & Rand.Rng) -> Nat & Rand.Rng: 27 (x, r) = xr 28 (U32.to_nat(x), r) 29 30 # A uniform Nat in [0, min(max, 1024)]. 31 def nat(+max: U32, r: Rand.Rng) -> Nat & Rand.Rng: 32 nat.fin(size(max, r)) 33 34 def char.fin(xr: U32 & Rand.Rng) -> Char & Rand.Rng: 35 (x, r) = xr 36 (Chr{x}, r) 37 38 # A printable ASCII char, ' ' (32) through '~' (126). 39 def char(r: Rand.Rng) -> Char & Rand.Rng: 40 char.fin(Rand.range(32, 127, r)) 41 42 # n + 1 chars prepended to acc; cr holds the next char. 43 def string.go(n: Nat, acc: String, cr: Char & Rand.Rng) -> String & Rand.Rng: 44 match n: 45 case 0n: 46 (c, r) = cr 47 (SCon{c, acc}, r) 48 case 1n+p: 49 (c, r) = cr 50 string.go(p, SCon{c, acc}, char(r)) 51 52 # Exactly n printable ASCII chars. 53 def string.of(n: Nat, r: Rand.Rng) -> String & Rand.Rng: 54 match n: 55 case 0n: 56 (SNil{}, r) 57 case 1n+p: 58 string.go(p, SNil{}, char(r)) 59 60 def string.fin(nr: Nat & Rand.Rng) -> String & Rand.Rng: 61 (n, r) = nr 62 string.of(n, r) 63 64 # Printable ASCII of length in [0, min(max, 1024)]. 65 def string(+max: U32, r: Rand.Rng) -> String & Rand.Rng: 66 string.fin(nat(max, r)) 67 68 # Byte i and the n bytes after it; xr holds byte i (Bytes.set keeps its low 8 bits). 69 def bytes.go(n: Nat, b: Bytes.Bytes, +i: U32, xr: U32 & Rand.Rng) -> Bytes.Bytes & Rand.Rng: 70 match n: 71 case 0n: 72 (x, r) = xr 73 (Bytes.set(b, i, x), r) 74 case 1n+p: 75 (x, r) = xr 76 bytes.go(p, Bytes.set(b, i, x), (i + 1 : U32), Rand.next(r)) 77 78 def bytes.start(n: Nat, +len: U32, r: Rand.Rng) -> Bytes.Bytes & Rand.Rng: 79 match n: 80 case 0n: 81 (Bytes.new(0), r) 82 case 1n+p: 83 bytes.go(p, Bytes.new(len), 0, Rand.next(r)) 84 85 # Exactly min(len, 1024) uniform octets, one draw each. 86 def bytes.of(+len: U32, r: Rand.Rng) -> Bytes.Bytes & Rand.Rng: 87 +n = cap(len) 88 bytes.start(U32.to_nat(n), n, r) 89 90 def bytes.fin(nr: U32 & Rand.Rng) -> Bytes.Bytes & Rand.Rng: 91 (n, r) = nr 92 bytes.of(n, r) 93 94 # Uniform octets, length in [0, min(max, 1024)]. 95 def bytes(+max: U32, r: Rand.Rng) -> Bytes.Bytes & Rand.Rng: 96 bytes.fin(size(max, r)) 97 98 # n + 1 items prepended to acc; hr holds the next item. 99 def list.go(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, n: Nat, acc: List<&2, T>, hr: T & Rand.Rng) -> List<&2, T> & Rand.Rng: 100 match n: 101 case 0n: 102 (h, r) = hr 103 (h <> acc, r) 104 case 1n+p: 105 (h, r) = hr 106 list.go(~T, ~gen, p, h <> acc, gen(r)) 107 108 # Exactly n items from gen. The first draw ends up last; replay is unaffected. 109 def list.of(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, n: Nat, r: Rand.Rng) -> List<&2, T> & Rand.Rng: 110 match n: 111 case 0n: 112 (Nil{}, r) 113 case 1n+p: 114 list.go(~T, ~gen, p, Nil{}, gen(r)) 115 116 def list.fin(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, nr: Nat & Rand.Rng) -> List<&2, T> & Rand.Rng: 117 (n, r) = nr 118 list.of(~T, ~gen, n, r) 119 120 # Items from gen, length in [0, min(max, 1024)]. 121 def list(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, +max: U32, r: Rand.Rng) -> List<&2, T> & Rand.Rng: 122 list.fin(~T, ~gen, nat(max, r)) 123 124 def maybe.some(~T: Data, hr: T & Rand.Rng) -> Maybe<&2, T> & Rand.Rng: 125 (h, r) = hr 126 (Some{h}, r) 127 128 def maybe.if(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, none: Bool, r: Rand.Rng) -> Maybe<&2, T> & Rand.Rng: 129 match none: 130 case True{}: 131 (None{}, r) 132 case False{}: 133 maybe.some(~T, gen(r)) 134 135 def maybe.pick(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, xr: U32 & Rand.Rng) -> Maybe<&2, T> & Rand.Rng: 136 (+x, r) = xr 137 maybe.if(~T, ~gen, U32.is_eq(x, 0), r) 138 139 # None one time in four, else Some from gen. 140 def maybe(~T: Data, ~gen: Rand.Rng -> T & Rand.Rng, r: Rand.Rng) -> Maybe<&2, T> & Rand.Rng: 141 maybe.pick(~T, ~gen, Rand.below(4, r)) 142 143 def map.fin(~A: Type, ~B: Type, ~f: A -> B, ar: A & Rand.Rng) -> B & Rand.Rng: 144 (a, r) = ar 145 (f(a), r) 146 147 # gen's value through f. 148 def map(~A: Type, ~B: Type, ~f: A -> B, ~gen: Rand.Rng -> A & Rand.Rng, r: Rand.Rng) -> B & Rand.Rng: 149 map.fin(~A, ~B, ~f, gen(r)) 150 151 def bind.fin(~A: Type, ~B: Type, ~k: A -> Rand.Rng -> B & Rand.Rng, ar: A & Rand.Rng) -> B & Rand.Rng: 152 (a, r) = ar 153 k(a, r) 154 155 # gen's value picks the next generator: bind(~Nat, ~List<&2, U32>, ~(r => Gen.nat(8, r)), ~(n => r => Gen.list.of(~U32, ~Gen.u32, n, r)), r). 156 def bind(~A: Type, ~B: Type, ~gen: Rand.Rng -> A & Rand.Rng, ~k: A -> Rand.Rng -> B & Rand.Rng, r: Rand.Rng) -> B & Rand.Rng: 157 bind.fin(~A, ~B, ~k, gen(r)) 158 159 def pair.snd(~A: Type, ~B: Type, a: A, br: B & Rand.Rng) -> (A & B) & Rand.Rng: 160 (b, r) = br 161 ((a, b), r) 162 163 def pair.fst(~A: Type, ~B: Type, ~gb: Rand.Rng -> B & Rand.Rng, ar: A & Rand.Rng) -> (A & B) & Rand.Rng: 164 (a, r) = ar 165 pair.snd(~A, ~B, a, gb(r)) 166 167 # ga's value then gb's, drawn in that order. 168 def pair(~A: Type, ~B: Type, ~ga: Rand.Rng -> A & Rand.Rng, ~gb: Rand.Rng -> B & Rand.Rng, r: Rand.Rng) -> (A & B) & Rand.Rng: 169 pair.fst(~A, ~B, ~gb, ga(r))