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

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

Issue 76263003: Experimental lexer generator: make tests pass again + style fixes. (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/lexer_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
(...skipping 12 matching lines...) Expand all
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 string import printable 28 from string import printable
29 29
30 class TransitionKey: 30 class TransitionKey:
31 31
32 __class_bounds = { 32 __class_bounds = {
33 "latin_1" : (1, 255), 33 'latin_1' : (1, 255),
34 # These are not "real" ranges; they just need to be separate. 34 # These are not real ranges; they just need to be separate from any real
35 "whitespace" : (256, 256), 35 # ranges.
36 "literal" : (257, 257), 36 'whitespace' : (256, 256),
37 "eos" : (258, 258), 37 'literal' : (257, 257),
38 "zero" : (259, 259), 38 'eos' : (258, 258),
39 'zero' : (259, 259),
39 } 40 }
40 __lower_bound = 1 41 __lower_bound = 1
41 __upper_bound = reduce(lambda acc, (k, v): max(acc, v[1]), __class_bounds.item s(), 0) 42 __upper_bound = reduce(lambda acc, (k, v): max(acc, v[1]), __class_bounds.item s(), 0)
42 43
43 __cached_keys = {} 44 __cached_keys = {}
44 45
45 __unique_key_counter = -1 46 __unique_key_counter = -1
46 47
47 @staticmethod 48 @staticmethod
48 def __in_latin_1(char): 49 def __in_latin_1(char):
49 bound = TransitionKey.__class_bounds["latin_1"] 50 bound = TransitionKey.__class_bounds['latin_1']
50 return (bound[0] <= char and char <= bound[1]) 51 return (bound[0] <= char and char <= bound[1])
51 52
52 @staticmethod 53 @staticmethod
53 def __is_class_range(r): 54 def __is_class_range(r):
54 return r[0] == r[1] and not TransitionKey.__in_latin_1(r[0]) 55 return r[0] == r[1] and not TransitionKey.__in_latin_1(r[0])
55 56
56 @staticmethod 57 @staticmethod
57 def __is_unique_range(r): 58 def __is_unique_range(r):
58 return r[0] == r[1] and r[0] < TransitionKey.__lower_bound 59 return r[0] == r[1] and r[0] < TransitionKey.__lower_bound
59 60
60 @staticmethod 61 @staticmethod
61 def __verify_ranges(ranges, check_merged): 62 def __verify_ranges(ranges, check_merged):
62 assert ranges 63 assert ranges
63 if len(ranges) == 1 and TransitionKey.__is_class_range(ranges[0]): 64 if len(ranges) == 1 and TransitionKey.__is_class_range(ranges[0]):
64 return 65 return
65 last = None 66 last = None
66 for r in ranges: 67 for r in ranges:
67 assert TransitionKey.__lower_bound <= r[0] 68 assert TransitionKey.__lower_bound <= r[0]
68 assert r[1] <= TransitionKey.__upper_bound 69 assert r[1] <= TransitionKey.__upper_bound
69 assert r[0] <= r[1] 70 assert r[0] <= r[1]
70 r_is_class = TransitionKey.__is_class_range(r) 71 r_is_class = TransitionKey.__is_class_range(r)
72 # Assert that the ranges are in order.
71 if last != None and check_merged: 73 if last != None and check_merged:
72 assert last[1] + 1 < r[0] or r_is_class 74 assert last[1] + 1 < r[0] or r_is_class
73 if not TransitionKey.__in_latin_1(r[0]): 75 if not TransitionKey.__in_latin_1(r[0]):
74 assert r_is_class 76 assert r_is_class
75 if not TransitionKey.__in_latin_1(r[1]): 77 if not TransitionKey.__in_latin_1(r[1]):
76 assert r_is_class 78 assert r_is_class
77 last = r 79 last = r
78 80
79 @staticmethod 81 @staticmethod
80 def __create(ranges, name = None): 82 def __create(ranges, name = None):
(...skipping 13 matching lines...) Expand all
94 96
95 @staticmethod 97 @staticmethod
96 def __cached_key(name, bounds_getter): 98 def __cached_key(name, bounds_getter):
97 if not name in TransitionKey.__cached_keys: 99 if not name in TransitionKey.__cached_keys:
98 bounds = bounds_getter(name) 100 bounds = bounds_getter(name)
99 TransitionKey.__cached_keys[name] = TransitionKey.__create(bounds, name) 101 TransitionKey.__cached_keys[name] = TransitionKey.__create(bounds, name)
100 return TransitionKey.__cached_keys[name] 102 return TransitionKey.__cached_keys[name]
101 103
102 @staticmethod 104 @staticmethod
103 def epsilon(): 105 def epsilon():
104 return TransitionKey.__cached_key("epsilon", lambda name : []) 106 return TransitionKey.__cached_key('epsilon', lambda name : [])
105 107
106 @staticmethod 108 @staticmethod
107 def any(): 109 def any():
108 return TransitionKey.__cached_key("any", 110 def bounds_getter(name):
109 lambda name : TransitionKey.__class_bounds.values()) 111 bounds = TransitionKey.__class_bounds.values()
112 bounds.sort()
113 return bounds
114 return TransitionKey.__cached_key('any', bounds_getter)
110 115
111 @staticmethod 116 @staticmethod
112 def single_char(char): 117 def single_char(char):
113 char = ord(char) 118 char = ord(char)
114 assert TransitionKey.__in_latin_1(char) 119 assert TransitionKey.__in_latin_1(char)
115 return TransitionKey.__create([(char, char)]) 120 return TransitionKey.__create([(char, char)])
116 121
117 @staticmethod 122 @staticmethod
118 def unique(name): 123 def unique(name):
119 def get_bounds(name): 124 def get_bounds(name):
120 bound = TransitionKey.__unique_key_counter 125 bound = TransitionKey.__unique_key_counter
121 TransitionKey.__unique_key_counter -= 1 126 TransitionKey.__unique_key_counter -= 1
122 return [(bound, bound)] 127 return [(bound, bound)]
123 name = "__" + name 128 name = '__' + name
124 return TransitionKey.__cached_key(name, get_bounds) 129 return TransitionKey.__cached_key(name, get_bounds)
125 130
126 @staticmethod 131 @staticmethod
127 def __process_graph(graph, ranges, key_map): 132 def __process_graph(graph, ranges, key_map):
128 key = graph[0] 133 key = graph[0]
129 if key == 'RANGE': 134 if key == 'RANGE':
130 ranges.append((ord(graph[1]), ord(graph[2]))) 135 ranges.append((ord(graph[1]), ord(graph[2])))
131 elif key == 'LITERAL': 136 elif key == 'LITERAL':
132 ranges.append((ord(graph[1]), ord(graph[1]))) 137 ranges.append((ord(graph[1]), ord(graph[1])))
133 elif key == 'CAT': 138 elif key == 'CAT':
134 for x in [graph[1], graph[2]]: 139 for x in [graph[1], graph[2]]:
135 TransitionKey.__process_graph(x, ranges, key_map) 140 TransitionKey.__process_graph(x, ranges, key_map)
136 elif key == 'CHARACTER_CLASS': 141 elif key == 'CHARACTER_CLASS':
137 class_name = graph[1] 142 class_name = graph[1]
138 if class_name == 'ws': 143 if class_name == 'ws':
139 ranges.append(TransitionKey.__class_bounds['whitespace']) 144 ranges.append(TransitionKey.__class_bounds['whitespace'])
140 elif class_name == 'lit': 145 elif class_name == 'lit':
141 ranges.append(TransitionKey.__class_bounds['literal']) 146 ranges.append(TransitionKey.__class_bounds['literal'])
142 elif class_name == 'eos': 147 elif class_name == 'eos':
143 ranges.append(TransitionKey.__class_bounds['eos']) 148 ranges.append(TransitionKey.__class_bounds['eos'])
144 elif class_name == 'zero': 149 elif class_name == 'zero':
145 ranges.append(TransitionKey.__class_bounds['zero']) 150 ranges.append(TransitionKey.__class_bounds['zero'])
146 elif class_name in key_map: 151 elif class_name in key_map:
147 ranges += key_map[class_name].__ranges 152 ranges += key_map[class_name].__ranges
148 else: 153 else:
149 raise Exception("unknown character class [%s]" % graph[1]) 154 raise Exception('unknown character class [%s]' % graph[1])
150 else: 155 else:
151 raise Exception("bad key [%s]" % key) 156 raise Exception('bad key [%s]' % key)
152 157
153 @staticmethod 158 @staticmethod
154 def character_class(graph, key_map): 159 def character_class(graph, key_map):
155 ranges = [] 160 ranges = []
156 assert graph[0] == 'CLASS' or graph[0] == 'NOT_CLASS' 161 assert graph[0] == 'CLASS' or graph[0] == 'NOT_CLASS'
157 invert = graph[0] == 'NOT_CLASS' 162 invert = graph[0] == 'NOT_CLASS'
158 TransitionKey.__process_graph(graph[1], ranges, key_map) 163 TransitionKey.__process_graph(graph[1], ranges, key_map)
159 return TransitionKey.__key_from_ranges(invert, ranges) 164 return TransitionKey.__key_from_ranges(invert, ranges)
160 165
161 def matches_char(self, char): 166 def matches_char(self, char):
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 def __range_str(r): 236 def __range_str(r):
232 if TransitionKey.__is_class_range(r): 237 if TransitionKey.__is_class_range(r):
233 return TransitionKey.__class_name(r) 238 return TransitionKey.__class_name(r)
234 def to_str(x): 239 def to_str(x):
235 assert TransitionKey.__in_latin_1(x) 240 assert TransitionKey.__in_latin_1(x)
236 if not x in TransitionKey.__printable_cache: 241 if not x in TransitionKey.__printable_cache:
237 res = "'%s'" % chr(x) if chr(x) in printable else str(x) 242 res = "'%s'" % chr(x) if chr(x) in printable else str(x)
238 TransitionKey.__printable_cache[x] = res 243 TransitionKey.__printable_cache[x] = res
239 return TransitionKey.__printable_cache[x] 244 return TransitionKey.__printable_cache[x]
240 if r[0] == r[1]: 245 if r[0] == r[1]:
241 return "%s" % to_str(r[0]) 246 return '%s' % to_str(r[0])
242 else: 247 else:
243 return "[%s-%s]" % (to_str(r[0]), to_str(r[1])) 248 return '[%s-%s]' % (to_str(r[0]), to_str(r[1]))
244 249
245 def __str__(self): 250 def __str__(self):
246 if self.__name: 251 if self.__name:
247 return self.__name 252 return self.__name
248 return ", ".join(TransitionKey.__range_str(x) for x in self.__ranges) 253 return ', '.join(TransitionKey.__range_str(x) for x in self.__ranges)
249 254
250 @staticmethod 255 @staticmethod
251 def __disjoint_keys(range_map): 256 def __disjoint_keys(range_map):
252 sort = lambda x : sorted(set(x)) 257 sort = lambda x : sorted(set(x))
253 range_map = sorted(map(lambda (k, v): (k, sort(v)), range_map.items())) 258 range_map = sorted(map(lambda (k, v): (k, sort(v)), range_map.items()))
254 ranges = [] 259 ranges = []
255 upper_bound = TransitionKey.__upper_bound + 1 260 upper_bound = TransitionKey.__upper_bound + 1
256 for i in range(len(range_map)): 261 for i in range(len(range_map)):
257 (left, left_values) = range_map[i] 262 (left, left_values) = range_map[i]
258 next = range_map[i + 1][0] if i != len(range_map) - 1 else upper_bound 263 next = range_map[i + 1][0] if i != len(range_map) - 1 else upper_bound
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 @staticmethod 338 @staticmethod
334 def merged_key(keys): 339 def merged_key(keys):
335 f = lambda acc, key: acc + list(key.__ranges) 340 f = lambda acc, key: acc + list(key.__ranges)
336 return TransitionKey.__key_from_ranges(False, reduce(f, keys, [])) 341 return TransitionKey.__key_from_ranges(False, reduce(f, keys, []))
337 342
338 @staticmethod 343 @staticmethod
339 def __invert_ranges(ranges): 344 def __invert_ranges(ranges):
340 inverted = [] 345 inverted = []
341 last = None 346 last = None
342 classes = set(TransitionKey.__class_bounds.values()) 347 classes = set(TransitionKey.__class_bounds.values())
343 latin_1 = TransitionKey.__class_bounds["latin_1"] 348 latin_1 = TransitionKey.__class_bounds['latin_1']
344 classes.remove(latin_1) 349 classes.remove(latin_1)
345 for r in ranges: 350 for r in ranges:
346 assert not TransitionKey.__is_unique_range(r) 351 assert not TransitionKey.__is_unique_range(r)
347 if TransitionKey.__is_class_range(r): 352 if TransitionKey.__is_class_range(r):
348 classes.remove(r) 353 classes.remove(r)
349 continue 354 continue
350 if last == None: 355 if last == None:
351 if r[0] != TransitionKey.__lower_bound: 356 if r[0] != TransitionKey.__lower_bound:
352 inverted.append((TransitionKey.__lower_bound, r[0] - 1)) 357 inverted.append((TransitionKey.__lower_bound, r[0] - 1))
353 elif last[1] + 1 < r[0]: 358 elif last[1] + 1 < r[0]:
354 inverted.append((last[1] + 1, r[0] - 1)) 359 inverted.append((last[1] + 1, r[0] - 1))
355 last = r 360 last = r
356 upper_bound = latin_1[1] 361 upper_bound = latin_1[1]
357 if last == None: 362 if last == None:
358 inverted.append(latin_1) 363 inverted.append(latin_1)
359 elif last[1] < upper_bound: 364 elif last[1] < upper_bound:
360 inverted.append((last[1] + 1, upper_bound)) 365 inverted.append((last[1] + 1, upper_bound))
361 inverted += list(classes) 366 inverted += list(classes)
362 return inverted 367 return inverted
OLDNEW
« no previous file with comments | « tools/lexer_generator/lexer_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698