| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2014 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are |
| 4 # met: |
| 5 # |
| 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided |
| 11 # with the distribution. |
| 12 # * Neither the name of Google Inc. nor the names of its |
| 13 # contributors may be used to endorse or promote products derived |
| 14 # from this software without specific prior written permission. |
| 15 # |
| 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 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. |
| 27 |
| 28 from types import IntType, StringType |
| 29 from encoding import KeyEncoding |
| 30 from action import Term |
| 31 from transition_keys import TransitionKey |
| 32 |
| 33 def escape_for_dot(v): |
| 34 v = str(v) |
| 35 v = v.replace('\r', '\\\\r').replace('\t', '\\\\t').replace('\n', '\\\\n') |
| 36 v = v.replace('\\', '\\\\').replace('\"', '\\\"') |
| 37 return v |
| 38 |
| 39 def map_characters(encoding, term): |
| 40 if term.name() == 'LITERAL': |
| 41 f = lambda x : KeyEncoding.to_str(encoding, x) |
| 42 term = Term('LITERAL', "'%s'" % ''.join(map(f, term.args()))) |
| 43 elif term.name() == 'RANGE': |
| 44 f = lambda x : "'%s'" % KeyEncoding.to_str(encoding, x) |
| 45 term = Term('RANGE', *map(f, term.args())) |
| 46 return term |
| 47 |
| 48 def term_to_dot(term, term_mapper = None): |
| 49 node_ix = [0] |
| 50 node_template = 'node [label="%s"]; N_%d;' |
| 51 edge_template = 'N_%d -> N_%d' |
| 52 nodes = [] |
| 53 edges = [] |
| 54 |
| 55 def process(term): |
| 56 if type(term) == StringType or type(term) == IntType: |
| 57 node_ix[0] += 1 |
| 58 nodes.append(node_template % (escape_for_dot(str(term)), node_ix[0])) |
| 59 return node_ix[0] |
| 60 elif isinstance(term, Term): |
| 61 term = term if not term_mapper else term_mapper(term) |
| 62 child_ixs = map(process, term.args()) |
| 63 node_ix[0] += 1 |
| 64 nodes.append(node_template % (escape_for_dot(term.name()), node_ix[0])) |
| 65 for child_ix in child_ixs: |
| 66 edges.append(edge_template % (node_ix[0], child_ix)) |
| 67 return node_ix[0] |
| 68 raise Exception |
| 69 |
| 70 process(term) |
| 71 return 'digraph { %s %s }' % ('\n'.join(nodes), '\n'.join(edges)) |
| 72 |
| 73 def automaton_to_dot(automaton): |
| 74 |
| 75 def f(node, (node_content, edge_content)): |
| 76 if node.action(): |
| 77 action_text = escape_for_dot(node.action()) |
| 78 node_content.append(' S_l%s[shape = box, label="%s"];' % |
| 79 (node.node_number(), action_text)) |
| 80 node_content.append(' S_%s -> S_l%s [arrowhead = none];' % |
| 81 (node.node_number(), node.node_number())) |
| 82 for key, state in node.key_state_iter(): |
| 83 if key == TransitionKey.epsilon(): |
| 84 key = "ε" |
| 85 else: |
| 86 key = key.to_string(automaton.encoding()) |
| 87 edge_content.append(" S_%s -> S_%s [ label = \"%s\" ];" % ( |
| 88 node.node_number(), state.node_number(), escape_for_dot(key))) |
| 89 return (node_content, edge_content) |
| 90 |
| 91 (node_content, edge_content) = automaton.visit_all_states(f, ([], [])) |
| 92 |
| 93 start_set = automaton.start_set() |
| 94 assert len(start_set) == 1 |
| 95 start_node = iter(start_set).next() |
| 96 terminal_set = automaton.terminal_set() |
| 97 |
| 98 terminals = ["S_%d;" % x.node_number() for x in terminal_set] |
| 99 start_number = start_node.node_number() |
| 100 start_shape = "circle" |
| 101 if start_node in terminal_set: |
| 102 start_shape = "doublecircle" |
| 103 |
| 104 return ''' |
| 105 digraph finite_state_machine { |
| 106 rankdir=LR; |
| 107 node [shape = %s, style=filled, bgcolor=lightgrey]; S_%s |
| 108 node [shape = doublecircle, style=unfilled]; %s |
| 109 node [shape = circle]; |
| 110 %s |
| 111 %s |
| 112 } |
| 113 ''' % (start_shape, |
| 114 start_number, |
| 115 " ".join(terminals), |
| 116 "\n".join(edge_content), |
| 117 "\n".join(node_content)) |
| OLD | NEW |