| 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 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 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 inspect import getmembers | 29 from inspect import getmembers |
| 30 from nfa import * | 30 from nfa import * |
| 31 | 31 |
| 32 class NfaBuilder(object): | 32 class NfaBuilder(object): |
| 33 | 33 |
| 34 def __init__(self): | 34 def __init__(self, encoding, character_classes = {}): |
| 35 self.__node_number = 0 | 35 self.__node_number = 0 |
| 36 self.__operation_map = {} | 36 self.__operation_map = {} |
| 37 self.__members = getmembers(self) | 37 self.__members = getmembers(self) |
| 38 self.__character_classes = {} | 38 self.__encoding = encoding |
| 39 self.__character_classes = character_classes |
| 39 self.__states = [] | 40 self.__states = [] |
| 40 | 41 |
| 41 def set_character_classes(self, classes): | |
| 42 self.__character_classes = classes | |
| 43 | |
| 44 def __new_state(self): | 42 def __new_state(self): |
| 45 self.__node_number += 1 | 43 self.__node_number += 1 |
| 46 return NfaState() | 44 return NfaState() |
| 47 | 45 |
| 48 def __or(self, graph): | 46 def __or(self, graph): |
| 49 start = self.__new_state() | 47 start = self.__new_state() |
| 50 ends = [] | 48 ends = [] |
| 51 for x in [self.__process(graph[1]), self.__process(graph[2])]: | 49 for x in [self.__process(graph[1]), self.__process(graph[2])]: |
| 52 start.add_epsilon_transition(x[0]) | 50 start.add_epsilon_transition(x[0]) |
| 53 ends += x[1] | 51 ends += x[1] |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 (left, right) = (self.__process(graph[1]), self.__process(graph[2])) | 98 (left, right) = (self.__process(graph[1]), self.__process(graph[2])) |
| 101 self.__patch_ends(left[1], right[0]) | 99 self.__patch_ends(left[1], right[0]) |
| 102 return (left[0], right[1]) | 100 return (left[0], right[1]) |
| 103 | 101 |
| 104 def __key_state(self, key): | 102 def __key_state(self, key): |
| 105 state = self.__new_state() | 103 state = self.__new_state() |
| 106 state.add_unclosed_transition(key) | 104 state.add_unclosed_transition(key) |
| 107 return (state, [state]) | 105 return (state, [state]) |
| 108 | 106 |
| 109 def __literal(self, graph): | 107 def __literal(self, graph): |
| 110 return self.__key_state(TransitionKey.single_char(graph[1])) | 108 return self.__key_state( |
| 109 TransitionKey.single_char(self.__encoding, graph[1])) |
| 111 | 110 |
| 112 def __class(self, graph): | 111 def __class(self, graph): |
| 113 return self.__key_state( | 112 return self.__key_state(TransitionKey.character_class( |
| 114 TransitionKey.character_class(graph, self.__character_classes)) | 113 self.__encoding, graph, self.__character_classes)) |
| 115 | 114 |
| 116 def __not_class(self, graph): | 115 def __not_class(self, graph): |
| 117 return self.__key_state( | 116 return self.__key_state(TransitionKey.character_class( |
| 118 TransitionKey.character_class(graph, self.__character_classes)) | 117 self.__encoding, graph, self.__character_classes)) |
| 119 | 118 |
| 120 def __any(self, graph): | 119 def __any(self, graph): |
| 121 return self.__key_state(TransitionKey.any()) | 120 return self.__key_state(TransitionKey.any(self.__encoding)) |
| 122 | 121 |
| 123 def __epsilon(self, graph): | 122 def __epsilon(self, graph): |
| 124 start = self.__new_state() | 123 start = self.__new_state() |
| 125 end = self.__new_state() | 124 end = self.__new_state() |
| 126 start.close(end) | 125 start.close(end) |
| 127 return (start, [end]) | 126 return (start, [end]) |
| 128 | 127 |
| 129 def __action(self, graph): | 128 def __action(self, graph): |
| 130 (start, ends) = self.__process(graph[1]) | 129 (start, ends) = self.__process(graph[1]) |
| 131 action = graph[2] | 130 action = graph[2] |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 return closure | 208 return closure |
| 210 is_epsilon = lambda k: k == TransitionKey.epsilon() | 209 is_epsilon = lambda k: k == TransitionKey.epsilon() |
| 211 state_iter = lambda node : node.state_iter(key_filter = is_epsilon) | 210 state_iter = lambda node : node.state_iter(key_filter = is_epsilon) |
| 212 edge = set(state_iter(node)) | 211 edge = set(state_iter(node)) |
| 213 closure = Automaton.visit_states( | 212 closure = Automaton.visit_states( |
| 214 edge, inner, state_iter=state_iter, visit_state=set()) | 213 edge, inner, state_iter=state_iter, visit_state=set()) |
| 215 node.set_epsilon_closure(closure) | 214 node.set_epsilon_closure(closure) |
| 216 Automaton.visit_states(set([start_state]), outer) | 215 Automaton.visit_states(set([start_state]), outer) |
| 217 | 216 |
| 218 @staticmethod | 217 @staticmethod |
| 219 def __replace_catch_all(state): | 218 def __replace_catch_all(encoding, state): |
| 220 catch_all = TransitionKey.unique('catch_all') | 219 catch_all = TransitionKey.unique('catch_all') |
| 221 transitions = state.transitions() | 220 transitions = state.transitions() |
| 222 if not catch_all in transitions: | 221 if not catch_all in transitions: |
| 223 return | 222 return |
| 224 f = lambda acc, state: acc | set(state.epsilon_closure_iter()) | 223 f = lambda acc, state: acc | set(state.epsilon_closure_iter()) |
| 225 reachable_states = reduce(f, transitions[catch_all], set()) | 224 reachable_states = reduce(f, transitions[catch_all], set()) |
| 226 f = lambda acc, state: acc | set(state.transitions().keys()) | 225 f = lambda acc, state: acc | set(state.transitions().keys()) |
| 227 keys = reduce(f, reachable_states, set()) | 226 keys = reduce(f, reachable_states, set()) |
| 228 keys.discard(TransitionKey.epsilon()) | 227 keys.discard(TransitionKey.epsilon()) |
| 229 keys.discard(catch_all) | 228 keys.discard(catch_all) |
| 230 inverse_key = TransitionKey.inverse_key(keys) | 229 inverse_key = TransitionKey.inverse_key(encoding, keys) |
| 231 if inverse_key: | 230 if inverse_key: |
| 232 transitions[inverse_key] = transitions[catch_all] | 231 transitions[inverse_key] = transitions[catch_all] |
| 233 del transitions[catch_all] | 232 del transitions[catch_all] |
| 234 | 233 |
| 235 def nfa(self, graph): | 234 def nfa(self, graph): |
| 236 (start, end, nodes_created) = self.__nfa(graph) | 235 (start, end, nodes_created) = self.__nfa(graph) |
| 237 end.close(None) | 236 end.close(None) |
| 238 self.__compute_epsilon_closures(start) | 237 self.__compute_epsilon_closures(start) |
| 239 f = lambda node, state: self.__replace_catch_all(node) | 238 f = lambda node, state: self.__replace_catch_all(self.__encoding, node) |
| 240 Automaton.visit_states(set([start]), f) | 239 Automaton.visit_states(set([start]), f) |
| 241 return Nfa(start, end, nodes_created) | 240 return Nfa(self.__encoding, start, end, nodes_created) |
| 242 | 241 |
| 243 @staticmethod | 242 @staticmethod |
| 244 def add_action(graph, action): | 243 def add_action(graph, action): |
| 245 return ('ACTION', graph, action) | 244 return ('ACTION', graph, action) |
| 246 | 245 |
| 247 @staticmethod | 246 @staticmethod |
| 248 def add_continue(graph): | 247 def add_continue(graph): |
| 249 return ('CONTINUE', graph) | 248 return ('CONTINUE', graph) |
| 250 | 249 |
| 251 @staticmethod | 250 @staticmethod |
| (...skipping 18 matching lines...) Expand all Loading... |
| 270 | 269 |
| 271 __modifer_map = { | 270 __modifer_map = { |
| 272 '+': 'ONE_OR_MORE', | 271 '+': 'ONE_OR_MORE', |
| 273 '?': 'ZERO_OR_ONE', | 272 '?': 'ZERO_OR_ONE', |
| 274 '*': 'ZERO_OR_MORE', | 273 '*': 'ZERO_OR_MORE', |
| 275 } | 274 } |
| 276 | 275 |
| 277 @staticmethod | 276 @staticmethod |
| 278 def apply_modifier(modifier, graph): | 277 def apply_modifier(modifier, graph): |
| 279 return (NfaBuilder.__modifer_map[modifier], graph) | 278 return (NfaBuilder.__modifer_map[modifier], graph) |
| OLD | NEW |