Mercurial > public > mercurial-scm > hg
comparison mercurial/parser.py @ 34045:79681d8ee587
parser: add helper function to test if pattern matches parsed tree
This function will be used as follows:
match('ancestors(_) and not ancestors(_)', x)
See the next patch for details.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Wed, 17 Feb 2016 21:31:09 +0900 |
parents | 90896b61fe26 |
children | 7bbc4e113e5f |
comparison
equal
deleted
inserted
replaced
34044:b862e6fca7ac | 34045:79681d8ee587 |
---|---|
309 replstack = list(reversed(repls)) | 309 replstack = list(reversed(repls)) |
310 r = _buildtree(template, placeholder, replstack) | 310 r = _buildtree(template, placeholder, replstack) |
311 if replstack: | 311 if replstack: |
312 raise error.ProgrammingError('too many replacements') | 312 raise error.ProgrammingError('too many replacements') |
313 return r | 313 return r |
314 | |
315 def _matchtree(pattern, tree, placeholder, incompletenodes, matches): | |
316 if pattern == tree: | |
317 return True | |
318 if not isinstance(pattern, tuple) or not isinstance(tree, tuple): | |
319 return False | |
320 if pattern == placeholder and tree[0] not in incompletenodes: | |
321 matches.append(tree) | |
322 return True | |
323 if len(pattern) != len(tree): | |
324 return False | |
325 return all(_matchtree(p, x, placeholder, incompletenodes, matches) | |
326 for p, x in zip(pattern, tree)) | |
327 | |
328 def matchtree(pattern, tree, placeholder=None, incompletenodes=()): | |
329 """If a tree matches the pattern, return a list of the tree and nodes | |
330 matched with the placeholder; Otherwise None | |
331 | |
332 >>> def f(pattern, tree): | |
333 ... m = matchtree(pattern, tree, _, {'keyvalue', 'list'}) | |
334 ... if m: | |
335 ... return m[1:] | |
336 | |
337 >>> _ = ('symbol', '_') | |
338 >>> f(('func', ('symbol', 'ancestors'), _), | |
339 ... ('func', ('symbol', 'ancestors'), ('symbol', '1'))) | |
340 [('symbol', '1')] | |
341 >>> f(('func', ('symbol', 'ancestors'), _), | |
342 ... ('func', ('symbol', 'ancestors'), None)) | |
343 >>> f(('range', ('dagrange', _, _), _), | |
344 ... ('range', | |
345 ... ('dagrange', ('symbol', '1'), ('symbol', '2')), | |
346 ... ('symbol', '3'))) | |
347 [('symbol', '1'), ('symbol', '2'), ('symbol', '3')] | |
348 | |
349 The placeholder does not match the specified incomplete nodes because | |
350 an incomplete node (e.g. argument list) cannot construct an expression. | |
351 | |
352 >>> f(('func', ('symbol', 'ancestors'), _), | |
353 ... ('func', ('symbol', 'ancestors'), | |
354 ... ('list', ('symbol', '1'), ('symbol', '2')))) | |
355 | |
356 The placeholder may be omitted, but which shouldn't match a None node. | |
357 | |
358 >>> _ = None | |
359 >>> f(('func', ('symbol', 'ancestors'), None), | |
360 ... ('func', ('symbol', 'ancestors'), ('symbol', '0'))) | |
361 """ | |
362 if placeholder is not None and not isinstance(placeholder, tuple): | |
363 raise error.ProgrammingError('placeholder must be a node tuple') | |
364 matches = [tree] | |
365 if _matchtree(pattern, tree, placeholder, incompletenodes, matches): | |
366 return matches | |
314 | 367 |
315 def parseerrordetail(inst): | 368 def parseerrordetail(inst): |
316 """Compose error message from specified ParseError object | 369 """Compose error message from specified ParseError object |
317 """ | 370 """ |
318 if len(inst.args) > 1: | 371 if len(inst.args) > 1: |