comparison mercurial/filesetlang.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents e79a69af1593
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
44 44
45 symbols = {} 45 symbols = {}
46 46
47 globchars = ".*{}[]?/\\_" 47 globchars = ".*{}[]?/\\_"
48 48
49
49 def tokenize(program): 50 def tokenize(program):
50 pos, l = 0, len(program) 51 pos, l = 0, len(program)
51 program = pycompat.bytestr(program) 52 program = pycompat.bytestr(program)
52 while pos < l: 53 while pos < l:
53 c = program[pos] 54 c = program[pos]
54 if c.isspace(): # skip inter-token whitespace 55 if c.isspace(): # skip inter-token whitespace
55 pass 56 pass
56 elif c in "(),-:|&+!": # handle simple operators 57 elif c in "(),-:|&+!": # handle simple operators
57 yield (c, None, pos) 58 yield (c, None, pos)
58 elif (c in '"\'' or c == 'r' and 59 elif (
59 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings 60 c in '"\'' or c == 'r' and program[pos : pos + 2] in ("r'", 'r"')
61 ): # handle quoted strings
60 if c == 'r': 62 if c == 'r':
61 pos += 1 63 pos += 1
62 c = program[pos] 64 c = program[pos]
63 decode = lambda x: x 65 decode = lambda x: x
64 else: 66 else:
65 decode = parser.unescapestr 67 decode = parser.unescapestr
66 pos += 1 68 pos += 1
67 s = pos 69 s = pos
68 while pos < l: # find closing quote 70 while pos < l: # find closing quote
69 d = program[pos] 71 d = program[pos]
70 if d == '\\': # skip over escaped characters 72 if d == '\\': # skip over escaped characters
71 pos += 2 73 pos += 2
72 continue 74 continue
73 if d == c: 75 if d == c:
74 yield ('string', decode(program[s:pos]), s) 76 yield ('string', decode(program[s:pos]), s)
75 break 77 break
78 raise error.ParseError(_("unterminated string"), s) 80 raise error.ParseError(_("unterminated string"), s)
79 elif c.isalnum() or c in globchars or ord(c) > 127: 81 elif c.isalnum() or c in globchars or ord(c) > 127:
80 # gather up a symbol/keyword 82 # gather up a symbol/keyword
81 s = pos 83 s = pos
82 pos += 1 84 pos += 1
83 while pos < l: # find end of symbol 85 while pos < l: # find end of symbol
84 d = program[pos] 86 d = program[pos]
85 if not (d.isalnum() or d in globchars or ord(d) > 127): 87 if not (d.isalnum() or d in globchars or ord(d) > 127):
86 break 88 break
87 pos += 1 89 pos += 1
88 sym = program[s:pos] 90 sym = program[s:pos]
89 if sym in keywords: # operator keywords 91 if sym in keywords: # operator keywords
90 yield (sym, None, s) 92 yield (sym, None, s)
91 else: 93 else:
92 yield ('symbol', sym, s) 94 yield ('symbol', sym, s)
93 pos -= 1 95 pos -= 1
94 else: 96 else:
95 raise error.ParseError(_("syntax error"), pos) 97 raise error.ParseError(_("syntax error"), pos)
96 pos += 1 98 pos += 1
97 yield ('end', None, pos) 99 yield ('end', None, pos)
98 100
101
99 def parse(expr): 102 def parse(expr):
100 p = parser.parser(elements) 103 p = parser.parser(elements)
101 tree, pos = p.parse(tokenize(expr)) 104 tree, pos = p.parse(tokenize(expr))
102 if pos != len(expr): 105 if pos != len(expr):
103 raise error.ParseError(_("invalid token"), pos) 106 raise error.ParseError(_("invalid token"), pos)
104 return parser.simplifyinfixops(tree, {'list', 'or'}) 107 return parser.simplifyinfixops(tree, {'list', 'or'})
105 108
109
106 def getsymbol(x): 110 def getsymbol(x):
107 if x and x[0] == 'symbol': 111 if x and x[0] == 'symbol':
108 return x[1] 112 return x[1]
109 raise error.ParseError(_('not a symbol')) 113 raise error.ParseError(_('not a symbol'))
110 114
115
111 def getstring(x, err): 116 def getstring(x, err):
112 if x and (x[0] == 'string' or x[0] == 'symbol'): 117 if x and (x[0] == 'string' or x[0] == 'symbol'):
113 return x[1] 118 return x[1]
114 raise error.ParseError(err) 119 raise error.ParseError(err)
120
115 121
116 def getkindpat(x, y, allkinds, err): 122 def getkindpat(x, y, allkinds, err):
117 kind = getsymbol(x) 123 kind = getsymbol(x)
118 pat = getstring(y, err) 124 pat = getstring(y, err)
119 if kind not in allkinds: 125 if kind not in allkinds:
120 raise error.ParseError(_("invalid pattern kind: %s") % kind) 126 raise error.ParseError(_("invalid pattern kind: %s") % kind)
121 return '%s:%s' % (kind, pat) 127 return '%s:%s' % (kind, pat)
122 128
129
123 def getpattern(x, allkinds, err): 130 def getpattern(x, allkinds, err):
124 if x and x[0] == 'kindpat': 131 if x and x[0] == 'kindpat':
125 return getkindpat(x[1], x[2], allkinds, err) 132 return getkindpat(x[1], x[2], allkinds, err)
126 return getstring(x, err) 133 return getstring(x, err)
134
127 135
128 def getlist(x): 136 def getlist(x):
129 if not x: 137 if not x:
130 return [] 138 return []
131 if x[0] == 'list': 139 if x[0] == 'list':
132 return list(x[1:]) 140 return list(x[1:])
133 return [x] 141 return [x]
134 142
143
135 def getargs(x, min, max, err): 144 def getargs(x, min, max, err):
136 l = getlist(x) 145 l = getlist(x)
137 if len(l) < min or len(l) > max: 146 if len(l) < min or len(l) > max:
138 raise error.ParseError(err) 147 raise error.ParseError(err)
139 return l 148 return l
149
140 150
141 def _analyze(x): 151 def _analyze(x):
142 if x is None: 152 if x is None:
143 return x 153 return x
144 154
168 if op == 'func': 178 if op == 'func':
169 getsymbol(x[1]) # function name must be a symbol 179 getsymbol(x[1]) # function name must be a symbol
170 ta = _analyze(x[2]) 180 ta = _analyze(x[2])
171 return (op, x[1], ta) 181 return (op, x[1], ta)
172 raise error.ProgrammingError('invalid operator %r' % op) 182 raise error.ProgrammingError('invalid operator %r' % op)
183
173 184
174 def _insertstatushints(x): 185 def _insertstatushints(x):
175 """Insert hint nodes where status should be calculated (first path) 186 """Insert hint nodes where status should be calculated (first path)
176 187
177 This works in bottom-up way, summing up status names and inserting hint 188 This works in bottom-up way, summing up status names and inserting hint
212 if getattr(symbols.get(f), '_callstatus', False): 223 if getattr(symbols.get(f), '_callstatus', False):
213 return (f,), ('withstatus', (op, x[1], ta), ('string', f)) 224 return (f,), ('withstatus', (op, x[1], ta), ('string', f))
214 return (), (op, x[1], ta) 225 return (), (op, x[1], ta)
215 raise error.ProgrammingError('invalid operator %r' % op) 226 raise error.ProgrammingError('invalid operator %r' % op)
216 227
228
217 def _mergestatushints(x, instatus): 229 def _mergestatushints(x, instatus):
218 """Remove redundant status hint nodes (second path) 230 """Remove redundant status hint nodes (second path)
219 231
220 This is the top-down path to eliminate inner hint nodes. 232 This is the top-down path to eliminate inner hint nodes.
221 """ 233 """
245 # don't propagate 'instatus' crossing a function boundary 257 # don't propagate 'instatus' crossing a function boundary
246 ta = _mergestatushints(x[2], instatus=False) 258 ta = _mergestatushints(x[2], instatus=False)
247 return (op, x[1], ta) 259 return (op, x[1], ta)
248 raise error.ProgrammingError('invalid operator %r' % op) 260 raise error.ProgrammingError('invalid operator %r' % op)
249 261
262
250 def analyze(x): 263 def analyze(x):
251 """Transform raw parsed tree to evaluatable tree which can be fed to 264 """Transform raw parsed tree to evaluatable tree which can be fed to
252 optimize() or getmatch() 265 optimize() or getmatch()
253 266
254 All pseudo operations should be mapped to real operations or functions 267 All pseudo operations should be mapped to real operations or functions
256 """ 269 """
257 t = _analyze(x) 270 t = _analyze(x)
258 _h, t = _insertstatushints(t) 271 _h, t = _insertstatushints(t)
259 return _mergestatushints(t, instatus=False) 272 return _mergestatushints(t, instatus=False)
260 273
274
261 def _optimizeandops(op, ta, tb): 275 def _optimizeandops(op, ta, tb):
262 if tb is not None and tb[0] == 'not': 276 if tb is not None and tb[0] == 'not':
263 return ('minus', ta, tb[1]) 277 return ('minus', ta, tb[1])
264 return (op, ta, tb) 278 return (op, ta, tb)
279
265 280
266 def _optimizeunion(xs): 281 def _optimizeunion(xs):
267 # collect string patterns so they can be compiled into a single regexp 282 # collect string patterns so they can be compiled into a single regexp
268 ws, ts, ss = [], [], [] 283 ws, ts, ss = [], [], []
269 for x in xs: 284 for x in xs:
275 ts.append(t) 290 ts.append(t)
276 if ss: 291 if ss:
277 ws.append(WEIGHT_CHECK_FILENAME) 292 ws.append(WEIGHT_CHECK_FILENAME)
278 ts.append(('patterns',) + tuple(ss)) 293 ts.append(('patterns',) + tuple(ss))
279 return ws, ts 294 return ws, ts
295
280 296
281 def _optimize(x): 297 def _optimize(x):
282 if x is None: 298 if x is None:
283 return 0, x 299 return 0, x
284 300
302 else: 318 else:
303 return wb, _optimizeandops(op, tb, ta) 319 return wb, _optimizeandops(op, tb, ta)
304 if op == 'or': 320 if op == 'or':
305 ws, ts = _optimizeunion(x[1:]) 321 ws, ts = _optimizeunion(x[1:])
306 if len(ts) == 1: 322 if len(ts) == 1:
307 return ws[0], ts[0] # 'or' operation is fully optimized out 323 return ws[0], ts[0] # 'or' operation is fully optimized out
308 ts = tuple(it[1] for it in sorted(enumerate(ts), 324 ts = tuple(
309 key=lambda it: ws[it[0]])) 325 it[1] for it in sorted(enumerate(ts), key=lambda it: ws[it[0]])
326 )
310 return max(ws), (op,) + ts 327 return max(ws), (op,) + ts
311 if op == 'list': 328 if op == 'list':
312 ws, ts = zip(*(_optimize(y) for y in x[1:])) 329 ws, ts = zip(*(_optimize(y) for y in x[1:]))
313 return sum(ws), (op,) + ts 330 return sum(ws), (op,) + ts
314 if op == 'func': 331 if op == 'func':
316 w = getattr(symbols.get(f), '_weight', 1) 333 w = getattr(symbols.get(f), '_weight', 1)
317 wa, ta = _optimize(x[2]) 334 wa, ta = _optimize(x[2])
318 return w + wa, (op, x[1], ta) 335 return w + wa, (op, x[1], ta)
319 raise error.ProgrammingError('invalid operator %r' % op) 336 raise error.ProgrammingError('invalid operator %r' % op)
320 337
338
321 def optimize(x): 339 def optimize(x):
322 """Reorder/rewrite evaluatable tree for optimization 340 """Reorder/rewrite evaluatable tree for optimization
323 341
324 All pseudo operations should be transformed beforehand. 342 All pseudo operations should be transformed beforehand.
325 """ 343 """
326 _w, t = _optimize(x) 344 _w, t = _optimize(x)
327 return t 345 return t
328 346
347
329 def prettyformat(tree): 348 def prettyformat(tree):
330 return parser.prettyformat(tree, ('string', 'symbol')) 349 return parser.prettyformat(tree, ('string', 'symbol'))