flan/test/syntax/handwritten/traffic.fln

88 lines
2.2 KiB
Plaintext

; A traffic light at a crossing, driven by a clock and a pedestrian button.
; Each state carries how long it has left; a fault drops the light to
; flashing, and a supervisor decides whether to reset it.
data Light
Green(left: i32)
Yellow(left: i32, walk: bool)
Red(left: i32, walk: bool)
Flashing()
struct Fault
tick: i32
const green-time = 4
const yellow-time = 1
const red-time = 3
fn next(l: Light, pressed: bool) -> Light
match l
Green(left) ->
if left > 1 and not pressed then Light.Green{.left left - 1}
else Light.Yellow{.left yellow-time, .walk pressed}
Yellow(left, walk) ->
if left > 1
Light.Yellow{.left left - 1, .walk walk}
else
Light.Red{.left red-time, .walk walk}
Red(left, walk) ->
if left > 1 then Light.Red{.left left - 1, .walk walk} else Light.Green{.left green-time}
Flashing -> Light.Flashing{}
fn show(l: Light) -> str
match l
Green(_) -> "G"
Yellow(_, _) -> "Y"
Red(_, walk) -> if walk then "W" else "R"
Flashing -> "*"
; Runs the light for ticks steps; a fault at fault-at is signalled, and
; whoever handles it may reset the light to red.
fn run(ticks: i32, presses: [const i32], fault-at: i32) -> ()
let l = Light.Red{.left 1, .walk false}
p = 0
t = 0
until :clock t >= ticks
let pressed = p < length(presses)
and presses[p] == t
if pressed
++(p)
if t == fault-at
l = restart-case
error(Fault{.tick t})
l
restart reset() "Put the light back to red and carry on"
Light.Red{.left red-time, .walk false}
restart flash()
Light.Flashing{}
match l
Flashing ->
print(show(l))
break :clock
_ -> print(show(l))
l = next(l, pressed)
t += 1
println("")
fn main() -> i32
let none = [-1]
let two = [1 9]
run(12, slice(none), -1)
run(12, slice(two), -1)
handler-bind
run(12, slice(none), 5)
on Fault(f)
invoke-restart('reset)
handler-bind
run(12, slice(none), 5)
on Fault(f)
invoke-restart('flash)
println:
handler-case
run(12, slice(none), 2)
"no fault"
on Fault(f)
println("")
"fault at tick"
0