82 lines
2.4 KiB
Plaintext
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
|