256 ('and', ('func', ('symbol', 'f'), ('string', '1')), ('symbol', '2')) |
256 ('and', ('func', ('symbol', 'f'), ('string', '1')), ('symbol', '2')) |
257 """ |
257 """ |
258 template = _cachedtree(tmplspec) |
258 template = _cachedtree(tmplspec) |
259 return parser.buildtree(template, ('symbol', '_'), *repls) |
259 return parser.buildtree(template, ('symbol', '_'), *repls) |
260 |
260 |
|
261 def _match(patspec, tree): |
|
262 """Test if a tree matches the given pattern statement; return the matches |
|
263 |
|
264 >>> _match('f(_)', parse('f()')) |
|
265 >>> _match('f(_)', parse('f(1)')) |
|
266 [('func', ('symbol', 'f'), ('symbol', '1')), ('symbol', '1')] |
|
267 >>> _match('f(_)', parse('f(1, 2)')) |
|
268 """ |
|
269 pattern = _cachedtree(patspec) |
|
270 return parser.matchtree(pattern, tree, ('symbol', '_'), |
|
271 {'keyvalue', 'list'}) |
|
272 |
261 def _isnamedfunc(x, funcname): |
273 def _isnamedfunc(x, funcname): |
262 """Check if given tree matches named function""" |
274 """Check if given tree matches named function""" |
263 return x and x[0] == 'func' and getsymbol(x[1]) == funcname |
275 return x and x[0] == 'func' and getsymbol(x[1]) == funcname |
264 |
276 |
265 def _isposargs(x, n): |
277 def _isposargs(x, n): |
276 if not _isnamedfunc(x, funcname): |
288 if not _isnamedfunc(x, funcname): |
277 return |
289 return |
278 return x[2] |
290 return x[2] |
279 |
291 |
280 def _matchonly(revs, bases): |
292 def _matchonly(revs, bases): |
281 """ |
293 return _match('ancestors(_) and not ancestors(_)', ('and', revs, bases)) |
282 >>> f = lambda *args: _matchonly(*map(parse, args)) |
|
283 >>> f('ancestors(A)', 'not ancestors(B)') |
|
284 ('list', ('symbol', 'A'), ('symbol', 'B')) |
|
285 """ |
|
286 ta = _matchnamedfunc(revs, 'ancestors') |
|
287 tb = bases and bases[0] == 'not' and _matchnamedfunc(bases[1], 'ancestors') |
|
288 if _isposargs(ta, 1) and _isposargs(tb, 1): |
|
289 return ('list', ta, tb) |
|
290 |
294 |
291 def _fixops(x): |
295 def _fixops(x): |
292 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be |
296 """Rewrite raw parsed tree to resolve ambiguous syntax which cannot be |
293 handled well by our simple top-down parser""" |
297 handled well by our simple top-down parser""" |
294 if not isinstance(x, tuple): |
298 if not isinstance(x, tuple): |
387 # (::x and not ::y)/(not ::y and ::x) have a fast path |
391 # (::x and not ::y)/(not ::y and ::x) have a fast path |
388 m = _matchonly(ta, tb) or _matchonly(tb, ta) |
392 m = _matchonly(ta, tb) or _matchonly(tb, ta) |
389 if m: |
393 if m: |
390 return w, _build('only(_, _)', *m[1:]) |
394 return w, _build('only(_, _)', *m[1:]) |
391 |
395 |
392 if tb is not None and tb[0] == 'not': |
396 m = _match('not _', tb) |
393 return wa, ('difference', ta, tb[1]) |
397 if m: |
|
398 return wa, ('difference', ta, m[1]) |
394 if wa > wb: |
399 if wa > wb: |
395 op = 'andsmally' |
400 op = 'andsmally' |
396 return w, (op, ta, tb) |
401 return w, (op, ta, tb) |
397 elif op == 'or': |
402 elif op == 'or': |
398 # fast path for machine-generated expression, that is likely to have |
403 # fast path for machine-generated expression, that is likely to have |
422 if len(ts) == 1: |
427 if len(ts) == 1: |
423 return ws[0], ts[0] # 'or' operation is fully optimized out |
428 return ws[0], ts[0] # 'or' operation is fully optimized out |
424 return max(ws), (op, ('list',) + tuple(ts)) |
429 return max(ws), (op, ('list',) + tuple(ts)) |
425 elif op == 'not': |
430 elif op == 'not': |
426 # Optimize not public() to _notpublic() because we have a fast version |
431 # Optimize not public() to _notpublic() because we have a fast version |
427 if x[1][:3] == ('func', ('symbol', 'public'), None): |
432 if _match('public()', x[1]): |
428 o = _optimize(_build('_notpublic()'), not small) |
433 o = _optimize(_build('_notpublic()'), not small) |
429 return o[0], o[1] |
434 return o[0], o[1] |
430 else: |
435 else: |
431 o = _optimize(x[1], not small) |
436 o = _optimize(x[1], not small) |
432 return o[0], (op, o[1]) |
437 return o[0], (op, o[1]) |