flan/test/syntax/handwritten/inventory.fln

82 lines
2.4 KiB
Plaintext

; An inventory report: items from the stock package, reorder rules held as
; function values, and the report's text built in an arena that is reset
; between runs.
import stock "stock"
struct Rule
label: string
applies: CFn(stock/Item) -> bool
def report-width: i32 = 28
once runs: i32
const reorder-below = 5
; Run the body n times, counting passes in the name given.
defmacro(repeat, [i n & body]):
quote
for ~i in range(~n)
~@body
; Say what went wrong when a check does not hold.
defmacro(expect, [test message]):
quote
if not ~test
println("expected:", ~message)
fn gcd(a: i32, b: i32) -> i32
loop([x a y b]):
if y == 0 then x else recur(y, x % y)
fn line(it: stock/Item) -> ()
let price = stock/money(stock/value(it))
defer
free(price)
let dots = report-width - i32(length(it.name)) - i32(length(price))
print(it.name)
for i in range(max(dots, 1))
print(".")
println(string(slice(price)))
fn low?(it: stock/Item) -> bool = it.count < reorder-below
fn count-if(items: [stock/Item], keep?: Fn(stock/Item) -> bool) -> i32
let n = 0
for i in range(length(items))
if keep?(items[i])
++(n)
n
fn main() -> i32
let items = [stock/item("bolts", 12, 400), stock/item("nuts", 5, 3),
stock/item("gears", 1250, 7), stock/item("belts", 899, 0)]
let rules = [Rule{.label "reorder", .applies low?},
Rule{.label "valuable", .applies fn(it) => stock/value(it) > 5000}]
let frame = arena-new(4096)
repeat(pass, 2):
runs += 1
with-allocator(frame):
println("report", runs)
for i in range(length(items))
line(items[i])
for r in range(length(rules))
let names = vec-new(string)
for i in range(length(items))
if rules[r].applies(items[i])
push(names, items[i].name)
println(rules[r].label, slice(names))
free-all(frame)
arena-destroy(frame)
let total = 0
for i in range(0, length(items), 2)
total += items[i].count
println("even rows hold", total, "and share a factor of",
gcd(items[0].count, items[2].count + 1))
println("sign bits", stock/sign-bit(-2.5), stock/sign-bit(2.5),
"masked", bit-and(-total, 0xFF))
let big = 1000
println("worth over", big, count-if(slice(items), fn(it) => stock/value(it) > big))
expect(total == 407, "407 on even rows")
expect(runs == 2, "two runs")
0