| OLD | NEW |
| 1 # Copyright 2014 the V8 project authors. All rights reserved. | 1 # Copyright 2014 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without | 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are | 3 # modification, are permitted provided that the following conditions are |
| 4 # met: | 4 # met: |
| 5 # | 5 # |
| 6 # * Redistributions of source code must retain the above copyright | 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above | 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following | 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided | 10 # disclaimer in the documentation and/or other materials provided |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 from types import IntType, StringType | 28 from types import IntType, StringType |
| 29 from key_encoding import KeyEncoding | 29 from key_encoding import KeyEncoding |
| 30 from term import Term | 30 from term import Term |
| 31 from transition_key import TransitionKey | 31 from transition_key import TransitionKey |
| 32 from automaton import Action |
| 32 | 33 |
| 33 def escape_for_dot(v): | 34 def escape_for_dot(v): |
| 34 v = str(v) | 35 v = str(v) |
| 35 v = v.replace('\r', '\\\\r').replace('\t', '\\\\t').replace('\n', '\\\\n') | 36 v = v.replace('\r', '\\\\r').replace('\t', '\\\\t').replace('\n', '\\\\n') |
| 36 v = v.replace('\\', '\\\\').replace('\"', '\\\"') | 37 v = v.replace('\\', '\\\\').replace('\"', '\\\"') |
| 37 return v | 38 return v |
| 38 | 39 |
| 39 def map_characters(encoding, term): | 40 def map_characters(encoding, term): |
| 40 if term.name() == 'LITERAL': | 41 if term.name() == 'LITERAL': |
| 41 f = lambda x : KeyEncoding.to_str(encoding, x) | 42 f = lambda x : KeyEncoding.to_str(encoding, x) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 63 node_ix[0] += 1 | 64 node_ix[0] += 1 |
| 64 nodes.append(node_template % (escape_for_dot(term.name()), node_ix[0])) | 65 nodes.append(node_template % (escape_for_dot(term.name()), node_ix[0])) |
| 65 for child_ix in child_ixs: | 66 for child_ix in child_ixs: |
| 66 edges.append(edge_template % (node_ix[0], child_ix)) | 67 edges.append(edge_template % (node_ix[0], child_ix)) |
| 67 return node_ix[0] | 68 return node_ix[0] |
| 68 raise Exception | 69 raise Exception |
| 69 | 70 |
| 70 process(term) | 71 process(term) |
| 71 return 'digraph { %s %s }' % ('\n'.join(nodes), '\n'.join(edges)) | 72 return 'digraph { %s %s }' % ('\n'.join(nodes), '\n'.join(edges)) |
| 72 | 73 |
| 73 def automaton_to_dot(automaton): | 74 def automaton_to_dot(automaton, merge = False): |
| 74 | 75 terminal_set = automaton.terminal_set() |
| 75 def f(node, (node_content, edge_content)): | 76 to_skip = set([]) |
| 76 if node.action(): | 77 # get a replacement action for a state's omega transition |
| 77 action_text = escape_for_dot(node.action()) | 78 def analyse_omega_chain(state): |
| 79 omega_chain = list(state.omega_chain_iter()) |
| 80 if len(omega_chain) == 1: |
| 81 omega_state = omega_chain[0][0] |
| 82 # Handle match nodes |
| 83 if omega_chain[0][1] == 0: |
| 84 if omega_state in terminal_set: |
| 85 to_skip.add(omega_state) # don't draw omega transition state |
| 86 terminal_set.add(state) |
| 87 return omega_state.action() |
| 88 elif len(omega_chain) == 2: |
| 89 first_action = omega_chain[0][0].action().name() |
| 90 if ((first_action == 'store_token' or |
| 91 first_action == 'store_harmony_token') and |
| 92 omega_chain[1][0].action().name() == 'no_op'): |
| 93 if (omega_chain[0][0].action().term().args() == |
| 94 omega_chain[1][0].action().term().args()): |
| 95 return Action(Term('goto', omega_chain[0][0].node_number()), 0) |
| 96 else: |
| 97 to_skip.add(omega_chain[0][0]) # don't draw first transition |
| 98 return Action(Term('chain', |
| 99 omega_chain[0][0].action().term(), |
| 100 Term('goto', omega_chain[1][0].node_number())), 0) |
| 101 return Action.empty_action() |
| 102 # draw state |
| 103 skipped = set([]) |
| 104 drawn = set([]) |
| 105 def draw(node, (node_content, edge_content)): |
| 106 if node in to_skip: # skip match nodes |
| 107 skipped.add(node) |
| 108 return (node_content, edge_content) |
| 109 drawn.add(node) |
| 110 omega_action = analyse_omega_chain(node) if merge else Action.empty_action() |
| 111 node_action = node.action() |
| 112 if node_action.name() == 'no_op': |
| 113 node_action = Action.empty_action() |
| 114 if node_action or omega_action: |
| 115 action_text = str(node.action()) |
| 116 if omega_action: |
| 117 action_text += ' | ' + str(omega_action) |
| 118 action_text = '< %s >' % escape_for_dot(action_text) |
| 78 node_content.append(' S_l%s[shape = box, label="%s"];' % | 119 node_content.append(' S_l%s[shape = box, label="%s"];' % |
| 79 (node.node_number(), action_text)) | 120 (node.node_number(), action_text)) |
| 80 node_content.append(' S_%s -> S_l%s [arrowhead = none];' % | 121 node_content.append(' S_%s -> S_l%s [arrowhead = none];' % |
| 81 (node.node_number(), node.node_number())) | 122 (node.node_number(), node.node_number())) |
| 82 for key, state in node.key_state_iter(): | 123 for key, state in node.key_state_iter(): |
| 83 if key == TransitionKey.epsilon(): | 124 if key == TransitionKey.epsilon(): |
| 84 key = "ε" | 125 key = "ε" |
| 85 elif key == TransitionKey.omega(): | 126 elif key == TransitionKey.omega(): |
| 127 if omega_action: # don't draw omega transition |
| 128 continue |
| 86 key = "ω" | 129 key = "ω" |
| 87 else: | 130 else: |
| 88 key = key.to_string(automaton.encoding()) | 131 key = key.to_string(automaton.encoding()) |
| 89 edge_content.append(" S_%s -> S_%s [ label = \"%s\" ];" % ( | 132 edge_content.append(" S_%s -> S_%s [ label = \"%s\" ];" % ( |
| 90 node.node_number(), state.node_number(), escape_for_dot(key))) | 133 node.node_number(), state.node_number(), escape_for_dot(key))) |
| 91 return (node_content, edge_content) | 134 return (node_content, edge_content) |
| 92 | 135 |
| 93 (node_content, edge_content) = automaton.visit_all_states(f, ([], [])) | 136 (node_content, edge_content) = automaton.visit_all_states(draw, ([], [])) |
| 137 |
| 138 assert skipped == to_skip |
| 139 terminal_set -= to_skip |
| 140 assert automaton.node_count() == len(skipped) + len(drawn) |
| 94 | 141 |
| 95 start_set = automaton.start_set() | 142 start_set = automaton.start_set() |
| 96 assert len(start_set) == 1 | 143 assert len(start_set) == 1 |
| 97 start_node = iter(start_set).next() | 144 start_node = iter(start_set).next() |
| 98 terminal_set = automaton.terminal_set() | |
| 99 | 145 |
| 100 terminals = ["S_%d;" % x.node_number() for x in terminal_set] | 146 terminals = ["S_%d;" % x.node_number() for x in terminal_set] |
| 101 start_number = start_node.node_number() | 147 start_number = start_node.node_number() |
| 102 start_shape = "circle" | 148 start_shape = "circle" |
| 103 if start_node in terminal_set: | 149 if start_node in terminal_set: |
| 104 start_shape = "doublecircle" | 150 start_shape = "doublecircle" |
| 105 | 151 |
| 106 return ''' | 152 return ''' |
| 107 digraph finite_state_machine { | 153 digraph finite_state_machine { |
| 108 rankdir=LR; | 154 rankdir=LR; |
| 109 node [shape = %s, style=filled, bgcolor=lightgrey]; S_%s | 155 node [shape = %s, style=filled, bgcolor=lightgrey]; S_%s |
| 110 node [shape = doublecircle, style=unfilled]; %s | 156 node [shape = doublecircle, style=unfilled]; %s |
| 111 node [shape = circle]; | 157 node [shape = circle]; |
| 112 %s | 158 %s |
| 113 %s | 159 %s |
| 114 } | 160 } |
| 115 ''' % (start_shape, | 161 ''' % (start_shape, |
| 116 start_number, | 162 start_number, |
| 117 " ".join(terminals), | 163 " ".join(terminals), |
| 118 "\n".join(edge_content), | 164 "\n".join(edge_content), |
| 119 "\n".join(node_content)) | 165 "\n".join(node_content)) |
| OLD | NEW |