def report(state): init_tran = trans_dict[state.sig][e.Initial] msg = None get_state = lambda sig: l.get_state_by_sig(sig, flat_state_list) is_child = lambda sg: state in l.get_path_from_root(get_state(sg))[:-1] if isinstance(init_tran, e._Local): msg = 'cannot use LocalTransition for initial' elif isinstance(init_tran, e._Internal): msg = 'cannot use InternalTransition for initial' elif isinstance(init_tran, e._Choice): if init_tran.default is None: msg = ('must declare default when using Choice as initial') elif get_state(init_tran.default) is None: msg = 'default points to nonexistent state' elif not is_child(init_tran.default): msg = 'default target must be a child state' elif any(get_state(s) is None for s in init_tran.switch.values()): msg = 'switch dict references nonexistent state' elif not all(is_child(sig) for sig in init_tran.switch.values()): msg = 'switch dict value not a child state' # at this point we know it is instance of regular Transition elif init_tran.target == st.sig: msg = 'initial transition cannot be a loop' elif get_state(init_tran.target) is None: msg = 'transition target points to nonexistent state' elif not is_child(init_tran.target): msg = 'target state must be a child state' elif init_tran.guard is not e.always_true: msg = 'initial transition cannot have a guard' return (state, msg) if msg else None
def visit(state, visited=set()): # instantiating should be ok in this case if state in visited: return set() visited.add(state) # if orthogonal is reachable, its states are automatically reachable if state.kind == 'orthogonal': [visit(st, visited) for st in state.states] # all state's parents are reachable # visit transition targets going out of every parent state for parent in l.get_path_from_root(state): visit(parent, visited) # visit transition targets going out of current state for tran in trans_dict.get(state.sig, {}).values(): if isinstance(tran, e._Choice): to_visit = [l.get_state_by_sig(sig, flat_state_list) for sig in tran.switch.values() + [tran.default]] else: to_visit = [l.get_state_by_sig(tran.target, flat_state_list)] # nonexistent states (None values in list) are checked elsewhere [visit(st, visited) for st in to_visit if st is not None] return visited