comparison mercurial/parser.py @ 28895:4bf9ed7a260e

parser: move functions that process alias expansion to rule-set class They will be commonly used by revset and templater. It isn't easy to understand how _expand() works, so I'll add comments by a follow-up patch. The local variable 'alias' is renamed to 'a' to avoid shadowing the global 'alias' class.
author Yuya Nishihara <yuya@tcha.org>
date Mon, 29 Feb 2016 22:15:44 +0900
parents ee11167fe1da
children 4c76a032ec7e
comparison
equal deleted inserted replaced
28894:0f59674dc9ff 28895:4bf9ed7a260e
470 aliases = {} 470 aliases = {}
471 for decl, defn in items: 471 for decl, defn in items:
472 a = cls.build(decl, defn) 472 a = cls.build(decl, defn)
473 aliases[a.name] = a 473 aliases[a.name] = a
474 return aliases 474 return aliases
475
476 @classmethod
477 def _getalias(cls, aliases, tree):
478 """If tree looks like an unexpanded alias, return it. Return None
479 otherwise.
480 """
481 if not isinstance(tree, tuple):
482 return None
483 if tree[0] == cls._symbolnode:
484 name = tree[1]
485 a = aliases.get(name)
486 if a and a.args is None and a.tree == tree:
487 return a
488 if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode:
489 name = tree[1][1]
490 a = aliases.get(name)
491 if a and a.args is not None and a.tree == tree[:2]:
492 return a
493 return None
494
495 @classmethod
496 def _expandargs(cls, tree, args):
497 """Replace _aliasarg instances with the substitution value of the
498 same name in args, recursively.
499 """
500 if not isinstance(tree, tuple):
501 return tree
502 if tree[0] == '_aliasarg':
503 sym = tree[1]
504 return args[sym]
505 return tuple(cls._expandargs(t, args) for t in tree)
506
507 @classmethod
508 def _expand(cls, aliases, tree, expanding, cache):
509 if not isinstance(tree, tuple):
510 return tree
511 a = cls._getalias(aliases, tree)
512 if a is not None:
513 if a.error:
514 raise error.Abort(a.error)
515 if a in expanding:
516 raise error.ParseError(_('infinite expansion of %(section)s '
517 '"%(name)s" detected')
518 % {'section': cls._section,
519 'name': a.name})
520 expanding.append(a)
521 if a.name not in cache:
522 cache[a.name] = cls._expand(aliases, a.replacement, expanding,
523 cache)
524 result = cache[a.name]
525 expanding.pop()
526 if a.args is not None:
527 l = cls._getlist(tree[2])
528 if len(l) != len(a.args):
529 raise error.ParseError(_('invalid number of arguments: %d')
530 % len(l))
531 l = [cls._expand(aliases, t, [], cache) for t in l]
532 result = cls._expandargs(result, dict(zip(a.args, l)))
533 else:
534 result = tuple(cls._expand(aliases, t, expanding, cache)
535 for t in tree)
536 return result
537
538 @classmethod
539 def expand(cls, aliases, tree):
540 """Expand aliases in tree, recursively.
541
542 'aliases' is a dictionary mapping user defined aliases to alias objects.
543 """
544 return cls._expand(aliases, tree, [], {})