90 lines
2.3 KiB
Python
90 lines
2.3 KiB
Python
|
|
MODEL = """
|
|
MODULE {name}
|
|
VAR
|
|
state : {{ {states} }};
|
|
ASSIGN
|
|
init(state) := {initial};
|
|
next(state) :=
|
|
case
|
|
{transitions}
|
|
esac;
|
|
DEFINE
|
|
{properties}
|
|
"""
|
|
|
|
TRAN = " state = {n} : {{{ms}}};"
|
|
PROP = """ -- Property "{prop}"
|
|
{alias} := {logic};
|
|
"""
|
|
PROP_LOGIC = "state = {state}"
|
|
|
|
LTL_FORM = """LTLSPEC
|
|
{ltl};
|
|
"""
|
|
|
|
A_UPPERCASE = ord('a')
|
|
ALPHABET_SIZE = 26
|
|
|
|
|
|
def _decompose(number):
|
|
"""Generate digits from `number` in base alphabet, least significants
|
|
bits first.
|
|
|
|
Since A is 1 rather than 0 in base alphabet, we are dealing with
|
|
`number - 1` at each iteration to be able to extract the proper digits.
|
|
"""
|
|
|
|
while number:
|
|
number, remainder = divmod(number - 1, ALPHABET_SIZE)
|
|
yield remainder
|
|
|
|
|
|
def base_10_to_alphabet(number):
|
|
"""Convert a decimal number to its base alphabet representation"""
|
|
|
|
return ''.join(
|
|
chr(A_UPPERCASE + part)
|
|
for part in _decompose(number)
|
|
)[::-1]
|
|
|
|
class ModelBuilder:
|
|
def __init__(self, states, initial, transitions, properties, ltls=[], name="main"):
|
|
self._name = name
|
|
self._states = states
|
|
self._initial = initial
|
|
self._tran = transitions
|
|
self._props = properties
|
|
self._ltls = ltls
|
|
|
|
self._propalias = {}
|
|
for no,prop in enumerate(properties.keys()):
|
|
self._propalias[prop] = base_10_to_alphabet(no + 1)
|
|
|
|
def generate(self):
|
|
# build model
|
|
states_decl = ",".join(self._states)
|
|
transitions = []
|
|
|
|
for n,ms in self._tran.items():
|
|
transition = TRAN.format(n=n, ms=",".join(ms))
|
|
transitions.append(transition)
|
|
|
|
properties = []
|
|
for prop,states in self._props.items():
|
|
alias = self._propalias[prop]
|
|
logic = " | ".join([PROP_LOGIC.format(state=x) for x in states])
|
|
prop_str = PROP.format(prop=prop, alias=alias, logic=logic)
|
|
properties.append(prop_str)
|
|
|
|
out = MODEL.format(name=self._name,
|
|
states=states_decl,
|
|
initial=self._initial,
|
|
transitions="\n".join(transitions),
|
|
properties="\n".join(properties))
|
|
|
|
# add LTL formulas
|
|
for ltl in self._ltls:
|
|
out += LTL_FORM.format(ltl=ltl)
|
|
return out
|