Custom operators¶
FuzzTLA can generate calls to operators from your own TLA+ modules, alongside the standard operators. A library campaign therefore tests both checkers on the operators that your specifications use. The Community Modules and recursive-operator campaigns are prepared libraries of this kind.
Adding a module¶
Put the module in the corpus, for example in my-corpus/tla/MyOperators.tla:
---- MODULE MyOperators ----
Singleton(value) == {value}
Contains(values, value) == value \in values
====
Then list it in the [generator] table of config.toml:
classpath = ["./tla"]
custom_operators = [
{ module = "MyOperators", operators = ["Singleton", "Contains"] },
]
weights = { name = 8, enum_set = 16, "MyOperators!Contains" = 8 }
classpathlists directories and JARs, in search order, relative toconfig.toml. A JAR may holdModule.tlaat its root or undertla2sany/StandardModules/.operatorsnames the operators that become expression forms. The helpers they use are included automatically.- Each operator has weight one unless
weightsnames it as"Module!Operator".
Before generating, FuzzTLA runs Apalache's type checker on each module once to infer
the operators' types. @type annotations are respected, and polymorphic operators get
new type instances at each call.
What an operator may use¶
An operator must be first-order and state-free. It cannot use:
- operator parameters or operator results;
CONSTANTs,VARIABLEs orASSUME;- recursion, except with
link = "diff"(below); - actions or temporal operators.
Its types must be ones the generator can produce. Reals, old-style records, sparse tuples, and empty records, variants or tuples are not supported. Overriding a standard module is not supported.
How the checkers see the operators¶
By default, every checker receives the operator definitions inlined into the generated
module. A module entry can change this with link:
link |
Parser and TLC | Apalache |
|---|---|---|
| none | inlined definitions | inlined definitions |
"instance" |
the module, through INSTANCE, including its Java overrides |
inlined definitions, or its own built-in version of the module |
"diff", with tlc_module = "M" |
module M, which defines the same operators |
the entry's own module |
"instance" tests TLC's Java overrides against Apalache. "diff" compares two
implementations of the same operators. Only the Apalache side is validated, so the
TLC side may be recursive.
Starting from a library file¶
A library file is a TOML file with a [generator] table that holds classpath and
custom_operators:
fuzztla init --corpus my-corpus --library libraries/community-modules.toml
init --library copies the classpath into my-corpus/tla/ and writes both keys into
config.toml. The repository ships libraries/community-modules.toml and
libraries/recursion.toml.
The library is fixed per corpus¶
The first run records the library's sources, the selected operators and the Apalache
version in .operator-library. Later runs, and print --corpus, refuse to work with
a changed library, because the old entries would no longer replay. To change the
library, initialize a new corpus.