| 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 from string import printable |
| 27 | 28 |
| 28 class TransitionKey: | 29 class TransitionKey: |
| 29 | 30 |
| 30 __lower_bound = 0 | 31 __lower_bound = 0 |
| 31 __latin_1_upper_bound = 255 | 32 __latin_1_upper_bound = 255 |
| 32 __unicode_whitespace_bounds = (256, 256) | 33 __unicode_whitespace_bounds = (256, 256) |
| 33 __unicode_literal_bounds = (257, 257) | 34 __unicode_literal_bounds = (257, 257) |
| 34 __upper_bound = 257 | 35 __upper_bound = 257 |
| 35 | 36 |
| 36 @staticmethod | 37 @staticmethod |
| 37 def __verify_ranges(ranges): | 38 def __verify_ranges(ranges): |
| 38 last = (TransitionKey.__lower_bound - 1, TransitionKey.__lower_bound - 1) | 39 last = (TransitionKey.__lower_bound - 1, TransitionKey.__lower_bound - 1) |
| 39 for r in ranges: | 40 for r in ranges: |
| 40 assert TransitionKey.__lower_bound <= r[0] | 41 assert TransitionKey.__lower_bound <= r[0] |
| 41 assert r[1] <= TransitionKey.__upper_bound | 42 assert r[1] <= TransitionKey.__upper_bound |
| 42 assert r[0] <= r[1] | 43 assert r[0] <= r[1] |
| 43 assert last[1] < r[0] | 44 assert last[1] < r[0] |
| 44 # TODO check classes are always disjoint points | 45 # TODO check classes are always disjoint points |
| 45 last = r | 46 last = r |
| 46 | 47 |
| 47 @staticmethod | 48 @staticmethod |
| 48 def __create(ranges): | 49 def __create(ranges): |
| 49 TransitionKey.__verify_ranges(ranges) | 50 TransitionKey.__verify_ranges(ranges) |
| 50 key = TransitionKey() | 51 key = TransitionKey() |
| 51 key.__ranges = ranges | 52 key.__ranges = tuple(ranges) # immutable |
| 52 key.__cached_hash = None | 53 key.__cached_hash = None |
| 53 return key | 54 return key |
| 54 | 55 |
| 55 __cached_epsilon = None | 56 __cached_epsilon = None |
| 56 @staticmethod | 57 @staticmethod |
| 57 def epsilon(): | 58 def epsilon(): |
| 58 if (TransitionKey.__cached_epsilon == None): | 59 if (TransitionKey.__cached_epsilon == None): |
| 59 TransitionKey.__cached_epsilon = TransitionKey.__create([]) | 60 TransitionKey.__cached_epsilon = TransitionKey.__create([]) |
| 60 return TransitionKey.__cached_epsilon | 61 return TransitionKey.__cached_epsilon |
| 61 | 62 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 90 if r[0] <= char and char <= r[1]: return True | 91 if r[0] <= char and char <= r[1]: return True |
| 91 return False | 92 return False |
| 92 | 93 |
| 93 def matches_key(self, key): | 94 def matches_key(self, key): |
| 94 assert isinstance(key, self.__class__) | 95 assert isinstance(key, self.__class__) |
| 95 assert key != TransitionKey.epsilon() | 96 assert key != TransitionKey.epsilon() |
| 96 assert len(key.__ranges) == 1 | 97 assert len(key.__ranges) == 1 |
| 97 subkey = key.__ranges[0] | 98 subkey = key.__ranges[0] |
| 98 for k in self.__ranges: | 99 for k in self.__ranges: |
| 99 if k[0] <= subkey[0] and k[1] >= subkey[1]: return True | 100 if k[0] <= subkey[0] and k[1] >= subkey[1]: return True |
| 101 # TODO assert disjoint |
| 100 return False | 102 return False |
| 101 | 103 |
| 102 def __hash__(self): | 104 def __hash__(self): |
| 103 if self.__cached_hash == None: | 105 if self.__cached_hash == None: |
| 104 initial_hash = hash((-1, TransitionKey.__upper_bound + 1)) | 106 initial_hash = hash((-1, TransitionKey.__upper_bound + 1)) |
| 105 f = lambda acc, r: acc ^ hash(r) | 107 f = lambda acc, r: acc ^ hash(r) |
| 106 self.__cached_hash = reduce(f, self.__ranges, initial_hash) | 108 self.__cached_hash = reduce(f, self.__ranges, initial_hash) |
| 107 return self.__cached_hash | 109 return self.__cached_hash |
| 108 | 110 |
| 109 def __eq__(self, other): | 111 def __eq__(self, other): |
| 110 return isinstance(other, self.__class__) and self.__ranges == other.__ranges | 112 return isinstance(other, self.__class__) and self.__ranges == other.__ranges |
| 111 | 113 |
| 114 __printable_cache = {} |
| 115 |
| 112 @staticmethod | 116 @staticmethod |
| 113 def __print_range(r): | 117 def __print_range(r): |
| 114 def to_str(x): | 118 def to_str(x): |
| 115 if x <= TransitionKey.__latin_1_upper_bound: | 119 if x <= TransitionKey.__latin_1_upper_bound: |
| 116 return chr(x) | 120 if not x in TransitionKey.__printable_cache: |
| 121 res = "'%s'" % chr(x) if chr(x) in printable else str(x) |
| 122 TransitionKey.__printable_cache[x] = res |
| 123 return TransitionKey.__printable_cache[x] |
| 117 if x == TransitionKey.__unicode_literal_bounds[0]: | 124 if x == TransitionKey.__unicode_literal_bounds[0]: |
| 118 return "literal" | 125 return "literal" |
| 119 if x == TransitionKey.__unicode_whitespace_bounds[0]: | 126 if x == TransitionKey.__unicode_whitespace_bounds[0]: |
| 120 return "whitespace" | 127 return "whitespace" |
| 121 assert False | 128 assert False |
| 122 if r[0] == r[1]: | 129 if r[0] == r[1]: |
| 123 return "'%s'" % to_str(r[0]) | 130 return "%s" % to_str(r[0]) |
| 124 else: | 131 else: |
| 125 return "['%s'-'%s']" % (to_str(r[0]), to_str(r[1])) | 132 return "[%s-%s]" % (to_str(r[0]), to_str(r[1])) |
| 126 | 133 |
| 127 def __str__(self): | 134 def __str__(self): |
| 128 if self == self.epsilon(): | 135 if self == self.epsilon(): |
| 129 return "epsilon" | 136 return "epsilon" |
| 130 if self == self.any(): | 137 if self == self.any(): |
| 131 return "any" | 138 return "any" |
| 132 return ", ".join(TransitionKey.__print_range(x) for x in self.__ranges) | 139 return ", ".join(TransitionKey.__print_range(x) for x in self.__ranges) |
| 133 | 140 |
| 134 @staticmethod | 141 @staticmethod |
| 135 def disjoint_keys(key_set): | 142 def disjoint_keys(key_set): |
| 136 ranges = sorted(reduce(lambda acc, x : acc + x.__ranges, key_set, [])) | 143 range_map = {} |
| 137 for i in range(0, len(ranges)): | 144 for x in key_set: |
| 138 right = ranges[i][1] | 145 for r in x.__ranges: |
| 139 limit = i | 146 if not r[0] in range_map: |
| 140 for j in range(i + 1, len(ranges)): | 147 range_map[r[0]] = [] |
| 141 if ranges[j][0] > right: | 148 range_map[r[0]].append(r[1]) |
| 142 break | 149 sort = lambda x : sorted(set(x)) |
| 143 assert ranges[j][0] >= ranges[i][0] | 150 range_map = sorted(map(lambda (k, v): (k, sort(v)), range_map.items())) |
| 144 limit = j | 151 ranges = [] |
| 145 if limit == i: continue | 152 upper_bound = TransitionKey.__upper_bound + 1 |
| 146 for j in range(i + 1, limit + 1): | 153 for i in range(len(range_map)): |
| 147 ranges[j] = (right, ranges[j][1]) | 154 (left, left_values) = range_map[i] |
| 155 next = range_map[i + 1][0] if i != len(range_map) - 1 else upper_bound |
| 156 to_push = [] |
| 157 for v in left_values: |
| 158 if v >= next: |
| 159 if not to_push: |
| 160 ranges.append((left, next - 1)) |
| 161 to_push.append(v) |
| 162 else: |
| 163 ranges.append((left, v)) |
| 164 left = v + 1 |
| 165 if to_push: |
| 166 current = range_map[i + 1] |
| 167 range_map[i + 1] = (current[0], sort(current[1] + to_push)) |
| 148 TransitionKey.__verify_ranges(ranges) | 168 TransitionKey.__verify_ranges(ranges) |
| 149 return map(lambda x : TransitionKey.__create([x]), ranges) | 169 return map(lambda x : TransitionKey.__create([x]), ranges) |
| OLD | NEW |