Debug/release: conditional compilation
This chapter builds on the toy project discussed in the previous chapter. It might be useful to be familiar with it, especially if this is your first time reading this.
Matla's conditional compilation is tied to the Matla
module discussed in the previous
chapter. If you remember, Matla.tla
is generated by
matla init
among your project's sources.
Just like we did back then, let's pretend this module only defines assert
and none of its
variants, all of which are handled the same by matla's conditional compilation anyway.
> cat Matla.tla
---- MODULE Matla ----
\* Matla helpers, mostly for assertions and debug/release conditional compilation.
\* TLC!Assertions are built on top of the standard `TLC' module.
LOCAL TLC == INSTANCE TLC
---- MODULE dbg ----
\* All functions in this module do nothing in `release' mode.
\* Checks some predicate.
assert(
\* Predicate that must be true.
pred,
\* Message issued when the predicate is false.
message
) ==
TLC!Assert(pred, message)
====
\* End of module `dbg'.
\* Contains debug-only functions.
dbg == INSTANCE dbg
\* Checks some predicate.
\*
\* Active in debug and release.
assert(
\* Predicate that must be true.
pred,
\* Message issued when the predicate is false.
message
) ==
TLC!Assert(pred, message)
====
\* End of module `Matla'.
The two versions, Matla!assert
and Matla!dbg!assert
, behave exactly the same in debug
mode,
which is matla run
's default mode. They differ in release
mode however, activated by matla run --release
, in that Matla!dbg!assert
s will be compiled away (replaced by TRUE
) while
Matla!assert
s will still cause TLC to check them, and fail if they do not hold.
Let's illustrate this on our running stopwatch project, sources available here.
> exa
Matla.tla Matla.toml sw_0.cfg sw_0.tla target
> bat sw_0.cfg
───────┬────────────────────────────────────────────────────────────────────────
│ File: sw_0.cfg
───────┼────────────────────────────────────────────────────────────────────────
1 │ INIT init
2 │ NEXT next
3 │
4 │ INVARIANTS
5 │ inv_cnt_pos
6 │ inv_reset
───────┴────────────────────────────────────────────────────────────────────────
Module sw_0
defines a next
action:
> bat -r 17:27 sw_0.tla
───────┬────────────────────────────────────────────────────────────────────────
│ File: sw_0.tla
───────┼────────────────────────────────────────────────────────────────────────
17 │ next ==
18 │ bool(reset')
19 │ /\ bool(start_stop')
20 │ /\ (
21 │ IF start_stop' THEN counting' = ~counting
22 │ ELSE UNCHANGED counting
23 │ ) /\ (
24 │ IF reset' THEN cnt' = 0
25 │ ELSE IF counting' /\ cnt < 59 THEN cnt' = cnt + 1
26 │ ELSE UNCHANGED cnt
27 │ )
───────┴────────────────────────────────────────────────────────────────────────
Let's add a non-debug check that we expect to fail:
> bat -r 17:29 sw_0.tla
───────┬────────────────────────────────────────────────────────────────────────
│ File: sw_0.tla
───────┼────────────────────────────────────────────────────────────────────────
17 ~ │ LOCAL Matla == INSTANCE Matla
18 │ next ==
19 │ bool(reset')
20 │ /\ bool(start_stop')
21 + │ /\ Matla!assert(reset')
22 │ /\ (
23 │ IF start_stop' THEN counting' = ~counting
24 │ ELSE UNCHANGED counting
25 │ ) /\ (
26 │ IF reset' THEN cnt' = 0
27 │ ELSE IF counting' /\ cnt < 59 THEN cnt' = cnt + 1
28 │ ELSE UNCHANGED cnt
29 │ )
───────┴────────────────────────────────────────────────────────────────────────
Running matla again, we get
Error: an assertion failed with "that's probably going to fail"
- triggered at
module sw_0, 20:8 → 20:60
| vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
20 | /\ Matla!assert(reset', "that's probably going to fail")
|
- while exploring this trace
┌───┐
│ 0 │ initial state
└─┬─┘
│ cnt : 0
│ counting : false
│ reset : false
│ start_stop: false
┴
specification is unsafe
Let's make sure debug
/release
modes work for Matla!dbg!assert
. Project sources available
here.
> bat -r 17:29 sw_0.tla
───────┬────────────────────────────────────────────────────────────────────────
│ File: sw_0.tla
───────┼────────────────────────────────────────────────────────────────────────
17 │ LOCAL Matla == INSTANCE Matla
18 │ next ==
19 │ bool(reset')
20 │ /\ bool(start_stop')
21 ~ │ /\ Matla!dbg!assert(reset')
22 │ /\ (
23 │ IF start_stop' THEN counting' = ~counting
24 │ ELSE UNCHANGED counting
25 │ ) /\ (
26 │ IF reset' THEN cnt' = 0
27 │ ELSE IF counting' /\ cnt < 59 THEN cnt' = cnt + 1
28 │ ELSE UNCHANGED cnt
29 │ )
───────┴────────────────────────────────────────────────────────────────────────
Running in debug
mode (without --release
) should still fail:
> matla run -w 1
Error: an assertion failed with "that's probably going to fail"
- triggered at
module sw_0, 20:8 → 20:64
| vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
20 | /\ Matla!dbg!assert(reset', "that's probably going to fail")
|
- while exploring this trace
┌───┐
│ 0 │ initial state
└─┬─┘
│ cnt : 0
│ counting : false
│ reset : false
│ start_stop: false
┴
specification is unsafe
Running in release
mode should succeed however, since besides the assertion line 21
the
specification is safe:
> matla run -w 1 --release
specification is safe