78 lines
1.9 KiB
Plaintext
78 lines
1.9 KiB
Plaintext
; A ledger that applies transfers between accounts. A transfer that would
|
|
; overdraw signals, and the caller picks a restart: skip it, cap it at what
|
|
; the account holds, or allow an overdraft up to a limit it supplies.
|
|
|
|
struct Overdraft :parent Error
|
|
account: i32
|
|
short: i64
|
|
|
|
struct Audit
|
|
account: i32
|
|
amount: i64
|
|
|
|
once balances: [4 i64]
|
|
once audits: i32
|
|
once log: i64
|
|
|
|
; Every transfer leaves a digit in the log when it is done with, however it
|
|
; ended: 1 applied, 2 left through a restart.
|
|
fn note(d: i64) -> ()
|
|
log = log * 10 + d
|
|
|
|
fn withdraw(account: i32, amount: i64) -> i64
|
|
let have = balances[account]
|
|
if amount > have
|
|
let short = amount - have
|
|
restart-case
|
|
error(Overdraft{.account account, .short short})
|
|
restart skip()
|
|
return 0
|
|
restart cap()
|
|
return withdraw(account, have)
|
|
restart allow(limit: i64)
|
|
if short > limit
|
|
return 0
|
|
if amount >= 100
|
|
signal(Audit{.account account, .amount amount})
|
|
balances[account] -= amount
|
|
amount
|
|
|
|
fn transfer(from: i32, to: i32, amount: i64) -> i64
|
|
let applied: i64 = 0
|
|
defer note(if applied == amount then 1 else 2)
|
|
applied = withdraw(from, amount)
|
|
balances[to] += applied
|
|
applied
|
|
|
|
fn run(policy) -> ()
|
|
balances = [100 50 0 10]
|
|
log = 0
|
|
handler-bind
|
|
transfer(0, 2, 30)
|
|
transfer(1, 2, 80)
|
|
transfer(3, 0, 25)
|
|
transfer(0, 1, 100)
|
|
on Overdraft(o)
|
|
match policy
|
|
:skip -> invoke-restart('skip)
|
|
:cap -> invoke-restart('cap)
|
|
_ -> invoke-restart('allow, i64(20))
|
|
on Audit(a)
|
|
audits += 1
|
|
println(policy, slice(balances), "log", log)
|
|
|
|
fn main() -> i32
|
|
run(:skip)
|
|
run(:cap)
|
|
run(:allow)
|
|
println("audited", audits)
|
|
let caught =
|
|
handler-case
|
|
balances = [0 0 0 0]
|
|
withdraw(2, 5)
|
|
on Overdraft(o)
|
|
println("unhandled overdraft on", o.account, "short by", o.short)
|
|
-1
|
|
println("caught", caught)
|
|
0
|