Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: tools/lexer_generator/transition_keys.py

Issue 54183004: Experimental parser: better disjoint keys (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/lexer_generator/automata_test.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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)
OLDNEW
« no previous file with comments | « tools/lexer_generator/automata_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698