def test_any_repetition(self): edge_a = Edge('a', 'state_a') edge_b = Edge('b', 'state_b') state_a = State('state_a') state_b = State('state_b') edge_out_a = Edge('a', 'state_a') edge_out_a_e = Edge('', 'state_a') edge_out_b = Edge('b', 'state_b') edge_out_b_e = Edge('', 'state_b') state_out_a = State('state_a', [edge_out_a, edge_out_b]) state_out_b = State('state_b', [edge_out_a, edge_out_b]) in_edges = [edge_a, edge_b] new_end_states = [state_a, state_b] new_states = [state_a, state_b] repetition = (0, float('inf')) is_optional = False in_edges_out = [edge_out_a, edge_out_b, edge_out_a_e, edge_out_b_e] new_end_states_out = [state_out_a, state_out_b] new_states_out = [state_out_a, state_out_b] expected = [in_edges_out, new_end_states_out, new_states_out] actual = repetition_applicator.apply_repetition( in_edges, new_end_states, new_states, repetition, is_optional) logger.debug( f'Actual result:\nin_edges: {actual[0]}\nnew_end_states: {actual[1]}\nnew_states: {actual[2]}' ) logger.debug(f'start_edges') self.assertTrue(edges_equal(actual[0], expected[0])) logger.debug(f'end_states') assert_states_equal(actual[1], expected[1]) logger.debug(f'states') assert_states_equal(actual[2], expected[2])
def test_N_repetition(self): edge = Edge('a', 'state_a') state = State('state_a') edge_out = Edge('a', 'state_a') edge_2_out = Edge('a', 'state_a_2') state_out = State('state_a', [edge_2_out]) state_2_out = State('state_a_2') in_edges = [edge] new_end_states = [state] new_states = [state] repetition = (2, 2) is_optional = False in_edges_out = [edge_out] new_end_states_out = [state_2_out] new_states_out = [state_out, state_2_out] expected = [in_edges_out, new_end_states_out, new_states_out] actual = repetition_applicator.apply_repetition( in_edges, new_end_states, new_states, repetition, is_optional) logger.debug( f'Actual result:\nin_edges: {actual[0]}\nnew_end_states: {actual[1]}\nnew_states: {actual[2]}' ) logger.debug(f'start_edges') self.assertTrue(edges_equal(actual[0], expected[0])) logger.debug(f'end_states') assert_states_equal(actual[1], expected[1]) logger.debug(f'states') assert_states_equal(actual[2], expected[2])
def test_N_plus_repetition(self): in_edge = Edge('a', 'state_a') in_state = State('state_a') edge = Edge('a', 'state_a') edge2 = Edge('a', 'state_a_2') edge3 = Edge('a', 'state_a_3') edge3e = Edge('', 'state_a_3') state = State('state_a', [edge2]) state2 = State('state_a_2', [edge3]) state3 = State('state_a_3', [edge3]) in_edges = [in_edge] new_end_states = [in_state] new_states = [in_state] repetition = (3, float('inf')) is_optional = False in_edges_out = [edge] new_end_states_out = [state3] new_states_out = [state, state2, state3] expected = [in_edges_out, new_end_states_out, new_states_out] actual = repetition_applicator.apply_repetition( in_edges, new_end_states, new_states, repetition, is_optional) logger.debug( f'Actual result:\nin_edges: {actual[0]}\nnew_end_states: {actual[1]}\nnew_states: {actual[2]}' ) logger.debug(f'start_edges') self.assertTrue(edges_equal(actual[0], expected[0])) logger.debug(f'end_states') assert_states_equal(actual[1], expected[1]) logger.debug(f'states') assert_states_equal(actual[2], expected[2])
def test_N_plus_repetition(self): edge_a = Edge('a', 'state_a') edge_b = Edge('b', 'state_b') state_a = State('state_a', edge_b) state_b = State('state_b') edge_out_a = Edge('a', 'state_a') edge_out_b = Edge('b', 'state_b') edge_out_a_2 = Edge('a', 'state_a_2') edge_out_b_2 = Edge('b', 'state_b_2') edge_out_a_3 = Edge('a', 'state_a_3') edge_out_a_3_i = Edge('a', 'state_a_3') edge_out_b_3 = Edge('b', 'state_b_3') state_out_a = State('state_a', edge_out_b) state_out_b = State('state_b', edge_out_a_2) state_out_a_2 = State('state_a_2', edge_out_b_2) state_out_b_2 = State('state_b_2', edge_out_a_3) state_out_a_3 = State('state_a_3', edge_out_b_3) state_out_b_3 = State('state_b_3', edge_out_a_3_i) in_edges = [edge_a] new_end_states = [state_b] new_states = [state_a, state_b] repetition = (3, float('inf')) is_optional = False in_edges_out = [edge_out_a] new_end_states_out = [state_out_b_3] new_states_out = [ state_out_a, state_out_b, state_out_a_2, state_out_b_2, state_out_a_3, state_out_b_3 ] expected = [in_edges_out, new_end_states_out, new_states_out] actual = repetition_applicator.apply_repetition( in_edges, new_end_states, new_states, repetition, is_optional) logger.debug( f'Actual result:\nin_edges: {actual[0]}\nnew_end_states: {actual[1]}\nnew_states: {actual[2]}' ) logger.debug(f'start_edges') self.assertTrue(edges_equal(actual[0], expected[0])) logger.debug(f'end_states') assert_states_equal(actual[1], expected[1]) logger.debug(f'states') assert_states_equal(actual[2], expected[2])
def recursive_parse_elements(elements, used_state_ids=None): logger.debug('Parsing elements {elements}') current_states = [] next_states = [] start_edges = [] end_states = [] states = [] current_end_states = [] new_end_states = [] new_token_end_states = [] new_states = [] current_in_edges = [] if used_state_ids == None: used_state_ids = {} # {state_id:string: times_used:int} first_iteration = True i = 0 while i < len(elements): logger.debug(f'i: {i} | {elements[i:]}') tokens, i = get_concurrent_tokens(elements, i) logger.debug(f'Tokens: {tokens}') for token in tokens: logger.debug(f'Processing token "{token}"') token, repetition = get_repetition(token) logger.debug(f'Got repetition. token: "{token}", repetition: {repetition}') token, is_optional = get_optionality(token) logger.debug(f'Got optionality. token: "{token}", is_optional: {is_optional}') # If we have a group, we have to recurse down into it, because the internal # structure of these states could be anything. if isinstance(token, list): logger.debug(f'Token "{token}" is list, recursing.') in_edges, new_token_end_states, new_states = recursive_parse_elements(token, used_state_ids) else: token, is_automata = is_automata_token(token) logger.debug(f'is_automata: {is_automata}') # Make sure the token hasn't been used before. If it has, then we # need to add a suffix onto it. # TODO: Make sure state machines know to ignore this suffix, or find # a better way to register which state machine goes with which token. if token in used_state_ids: unique_token = token + f'_#{used_state_ids[token]+1}' logger.debug(f'Token "{token}" is already in use. Changing to {unique_token}.') used_state_ids[token] += 1 else: unique_token = token used_state_ids[token] = 1 new_state = State(unique_token, is_automata = is_automata) new_token_end_states = [new_state] new_states = [new_state] in_edge = Edge(token, new_state.id) in_edges = [in_edge] in_edges, new_token_end_states, new_states = repetition_applicator.apply_repetition(in_edges, new_token_end_states, new_states, repetition, is_optional) logger.debug(f'Got apply_repetition result of:\n in_edges: {in_edges}\n new_token_end_states: {new_token_end_states}\n new_states: {new_states}') if first_iteration: logger.debug(f'Appending edge(s) {in_edges} to start_edges.') start_edges += in_edges else: for current_state in current_end_states: for edge in in_edges: logger.debug(f'Appending edge(s) {edge} to current_end_states {current_end_states}.') current_state.add_edge(edge) logger.debug(f'Dumping new states {[state.id for state in new_states]} into states.') states += new_states logger.debug(f'Dumping new end_states for token {token} ({new_token_end_states}) into new_end_states ({new_end_states}).') new_end_states += new_token_end_states new_token_end_states = [] # End for token in tokens loop first_iteration = False logger.debug(f'Reached end of concurrent tokens, setting current_end_states to new_end_states ({[state.id for state in new_end_states]}).') current_end_states = new_end_states new_end_states = [] # End i < len(elements) loop end_states = current_end_states logger.debug(f'Returning:\n start_edges: {start_edges}\n end_states: {end_states}\n states:{states}') return start_edges, end_states, states