92 lines
2.2 KiB
Plaintext
92 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
|
|
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) -> string
|
|
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}
|
|
let p = 0
|
|
let 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()
|
|
:report
|
|
"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
|