| OLD | NEW |
| 1 # Copyright 2013 the V8 project authors. All rights reserved. | 1 # Copyright 2013 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 |
| 11 # with the distribution. | 11 # with the distribution. |
| 12 # * Neither the name of Google Inc. nor the names of its | 12 # * Neither the name of Google Inc. nor the names of its |
| 13 # contributors may be used to endorse or promote products derived | 13 # contributors may be used to endorse or promote products derived |
| 14 # from this software without specific prior written permission. | 14 # from this software without specific prior written permission. |
| 15 # | 15 # |
| 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 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 TupleType | 28 from types import TupleType |
| 29 from transition_keys import TransitionKey | 29 from transition_keys import TransitionKey |
| 30 from automaton import * |
| 30 from inspect import getmembers | 31 from inspect import getmembers |
| 31 | 32 |
| 32 class NfaState: | 33 class NfaState(AutomatonState): |
| 33 | 34 |
| 34 def __init__(self, node_number): | 35 def __init__(self, node_number): |
| 36 super(NfaState, self).__init__(node_number) |
| 35 self.__transitions = {} | 37 self.__transitions = {} |
| 36 self.__unclosed = set() | 38 self.__unclosed = set() |
| 37 self.__node_number = node_number | |
| 38 self.__epsilon_closure = None | 39 self.__epsilon_closure = None |
| 39 self.__transition_action = None | 40 self.__transition_action = None |
| 40 | 41 |
| 41 def node_number(self): | |
| 42 return self.__node_number | |
| 43 | |
| 44 def epsilon_closure(self): | 42 def epsilon_closure(self): |
| 45 return self.__epsilon_closure | 43 return self.__epsilon_closure |
| 46 | 44 |
| 47 def set_epsilon_closure(self, closure): | 45 def set_epsilon_closure(self, closure): |
| 48 assert self.is_closed() | 46 assert self.is_closed() |
| 49 assert self.__epsilon_closure == None | 47 assert self.__epsilon_closure == None |
| 50 self.__epsilon_closure = frozenset(closure) | 48 self.__epsilon_closure = frozenset(closure) |
| 51 | 49 |
| 52 def set_transition_action(self, action): | 50 def set_transition_action(self, action): |
| 53 assert not self.is_closed() | 51 assert not self.is_closed() |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 f = lambda acc, (k, vs): acc | vs if match_func(k, value) else acc | 100 f = lambda acc, (k, vs): acc | vs if match_func(k, value) else acc |
| 103 return reduce(f, self.__transitions.items(), set()) | 101 return reduce(f, self.__transitions.items(), set()) |
| 104 | 102 |
| 105 def char_matches(self, value): | 103 def char_matches(self, value): |
| 106 return self.__matches(lambda k, v : k.matches_char(v), value) | 104 return self.__matches(lambda k, v : k.matches_char(v), value) |
| 107 | 105 |
| 108 def key_matches(self, value): | 106 def key_matches(self, value): |
| 109 return self.__matches(lambda k, v : k.matches_key(v), value) | 107 return self.__matches(lambda k, v : k.matches_key(v), value) |
| 110 | 108 |
| 111 def __str__(self): | 109 def __str__(self): |
| 112 return "NfaState(" + str(self.__node_number) + ")" | 110 return "NfaState(" + str(self.node_number()) + ")" |
| 113 | 111 |
| 114 @staticmethod | 112 @staticmethod |
| 115 def gather_transition_keys(state_set): | 113 def gather_transition_keys(state_set): |
| 116 f = lambda acc, state: acc | set(state.__transitions.keys()) | 114 f = lambda acc, state: acc | set(state.__transitions.keys()) |
| 117 return TransitionKey.disjoint_keys(reduce(f, state_set, set())) | 115 return TransitionKey.disjoint_keys(reduce(f, state_set, set())) |
| 118 | 116 |
| 119 class NfaBuilder: | 117 class NfaBuilder: |
| 120 | 118 |
| 121 def __init__(self): | 119 def __init__(self): |
| 122 self.__node_number = 0 | 120 self.__node_number = 0 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 __modifer_map = { | 246 __modifer_map = { |
| 249 '+': 'ONE_OR_MORE', | 247 '+': 'ONE_OR_MORE', |
| 250 '?': 'ZERO_OR_ONE', | 248 '?': 'ZERO_OR_ONE', |
| 251 '*': 'ZERO_OR_MORE', | 249 '*': 'ZERO_OR_MORE', |
| 252 } | 250 } |
| 253 | 251 |
| 254 @staticmethod | 252 @staticmethod |
| 255 def apply_modifier(modifier, graph): | 253 def apply_modifier(modifier, graph): |
| 256 return (NfaBuilder.__modifer_map[modifier], graph) | 254 return (NfaBuilder.__modifer_map[modifier], graph) |
| 257 | 255 |
| 258 class Nfa: | 256 class Nfa(Automaton): |
| 259 | 257 |
| 260 def __init__(self, start, end, nodes_created): | 258 def __init__(self, start, end, nodes_created): |
| 259 super(Nfa, self).__init__() |
| 261 self.__start = start | 260 self.__start = start |
| 262 self.__end = end | 261 self.__end = end |
| 263 self.__epsilon_closure_computed = False | 262 self.__epsilon_closure_computed = False |
| 264 self.__verify(nodes_created) | 263 self.__verify(nodes_created) |
| 265 | 264 |
| 266 @staticmethod | |
| 267 def __visit_edges(edge, compute_next_edge, visitor, state): | |
| 268 visited = set() | |
| 269 while edge: | |
| 270 f = lambda (next_edge, state), node: ( | |
| 271 next_edge | compute_next_edge(node), | |
| 272 visitor(node, state)) | |
| 273 (next_edge, state) = reduce(f, edge, (set(), state)) | |
| 274 visited |= edge | |
| 275 edge = next_edge - visited | |
| 276 return state | |
| 277 | |
| 278 def __visit_all_edges(self, visitor, state): | 265 def __visit_all_edges(self, visitor, state): |
| 279 edge = set([self.__start]) | 266 edge = set([self.__start]) |
| 280 next_edge = lambda node: node.next_states(lambda x : True) | 267 next_edge = lambda node: node.next_states(lambda x : True) |
| 281 return Nfa.__visit_edges(edge, next_edge, visitor, state) | 268 return self.visit_edges(edge, next_edge, visitor, state) |
| 282 | 269 |
| 283 def __verify(self, nodes_created): | 270 def __verify(self, nodes_created): |
| 284 def f(node, node_list): | 271 def f(node, node_list): |
| 285 assert node.is_closed() | 272 assert node.is_closed() |
| 286 node_list.append(node) | 273 node_list.append(node) |
| 287 return node_list | 274 return node_list |
| 288 node_list = self.__visit_all_edges(f, []) | 275 node_list = self.__visit_all_edges(f, []) |
| 289 assert len(node_list) == nodes_created | 276 assert len(node_list) == nodes_created |
| 290 | 277 |
| 291 def __compute_epsilon_closures(self): | 278 def __compute_epsilon_closures(self): |
| 292 if self.__epsilon_closure_computed: | 279 if self.__epsilon_closure_computed: |
| 293 return | 280 return |
| 294 self.__epsilon_closure_computed = True | 281 self.__epsilon_closure_computed = True |
| 295 def outer(node, state): | 282 def outer(node, state): |
| 296 def inner(node, closure): | 283 def inner(node, closure): |
| 297 closure.add(node) | 284 closure.add(node) |
| 298 return closure | 285 return closure |
| 299 is_epsilon = lambda k: k == TransitionKey.epsilon() | 286 is_epsilon = lambda k: k == TransitionKey.epsilon() |
| 300 next_edge = lambda node : node.next_states(is_epsilon) | 287 next_edge = lambda node : node.next_states(is_epsilon) |
| 301 edge = next_edge(node) | 288 edge = next_edge(node) |
| 302 closure = Nfa.__visit_edges(edge, next_edge, inner, set()) | 289 closure = self.visit_edges(edge, next_edge, inner, set()) |
| 303 node.set_epsilon_closure(closure) | 290 node.set_epsilon_closure(closure) |
| 304 self.__visit_all_edges(outer, None) | 291 self.__visit_all_edges(outer, None) |
| 305 | 292 |
| 306 @staticmethod | 293 @staticmethod |
| 307 def __close(states): | 294 def __close(states): |
| 308 f = lambda acc, node: acc | node.epsilon_closure() | 295 f = lambda acc, node: acc | node.epsilon_closure() |
| 309 return reduce(f, states, set(states)) | 296 return reduce(f, states, set(states)) |
| 310 | 297 |
| 311 def matches(self, string): | 298 def matches(self, string): |
| 312 self.__compute_epsilon_closures() | 299 self.__compute_epsilon_closures() |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 dfa_nodes[name]['transitions'][key] = (transition_state, action) | 342 dfa_nodes[name]['transitions'][key] = (transition_state, action) |
| 356 return name | 343 return name |
| 357 | 344 |
| 358 def compute_dfa(self): | 345 def compute_dfa(self): |
| 359 self.__compute_epsilon_closures() | 346 self.__compute_epsilon_closures() |
| 360 dfa_nodes = {} | 347 dfa_nodes = {} |
| 361 start_name = self.__to_dfa(set([self.__start]), dfa_nodes, self.__end) | 348 start_name = self.__to_dfa(set([self.__start]), dfa_nodes, self.__end) |
| 362 return (start_name, dfa_nodes) | 349 return (start_name, dfa_nodes) |
| 363 | 350 |
| 364 def to_dot(self): | 351 def to_dot(self): |
| 365 | 352 iterator = lambda visitor, state: self.__visit_all_edges(visitor, state) |
| 366 def f(node, node_content): | 353 return self.generate_dot(self.__start, set([self.__end]), iterator) |
| 367 for key, values in node.transitions().items(): | |
| 368 if key == TransitionKey.epsilon(): | |
| 369 key = "ε" | |
| 370 key = str(key).replace('\\', '\\\\') | |
| 371 for value in values: | |
| 372 if value[1]: | |
| 373 node_content.append( | |
| 374 " S_%d -> S_%d [ label = \"%s {%s} -> %s\" ];" % | |
| 375 (node.node_number(), value[0].node_number(), key, value[1][1], | |
| 376 value[1][2])) | |
| 377 else: | |
| 378 node_content.append( | |
| 379 " S_%d -> S_%d [ label = \"%s\" ];" % | |
| 380 (node.node_number(), value[0].node_number(), key)) | |
| 381 return node_content | |
| 382 | |
| 383 node_content = self.__visit_all_edges(f, []) | |
| 384 | |
| 385 return ''' | |
| 386 digraph finite_state_machine { | |
| 387 rankdir=LR; | |
| 388 node [shape = circle, style=filled, bgcolor=lightgrey]; S_%s | |
| 389 node [shape = doublecircle, style=unfilled]; S_%s | |
| 390 node [shape = circle]; | |
| 391 %s | |
| 392 } | |
| 393 ''' % (self.__start.node_number(), | |
| 394 self.__end.node_number(), | |
| 395 "\n".join(node_content)) | |
| OLD | NEW |