Mercurial > public > mercurial-scm > hg-stable
diff 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 |
line wrap: on
line diff
--- a/mercurial/parser.py Mon Feb 29 22:10:48 2016 +0900 +++ b/mercurial/parser.py Mon Feb 29 22:15:44 2016 +0900 @@ -472,3 +472,73 @@ a = cls.build(decl, defn) aliases[a.name] = a return aliases + + @classmethod + def _getalias(cls, aliases, tree): + """If tree looks like an unexpanded alias, return it. Return None + otherwise. + """ + if not isinstance(tree, tuple): + return None + if tree[0] == cls._symbolnode: + name = tree[1] + a = aliases.get(name) + if a and a.args is None and a.tree == tree: + return a + if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: + name = tree[1][1] + a = aliases.get(name) + if a and a.args is not None and a.tree == tree[:2]: + return a + return None + + @classmethod + def _expandargs(cls, tree, args): + """Replace _aliasarg instances with the substitution value of the + same name in args, recursively. + """ + if not isinstance(tree, tuple): + return tree + if tree[0] == '_aliasarg': + sym = tree[1] + return args[sym] + return tuple(cls._expandargs(t, args) for t in tree) + + @classmethod + def _expand(cls, aliases, tree, expanding, cache): + if not isinstance(tree, tuple): + return tree + a = cls._getalias(aliases, tree) + if a is not None: + if a.error: + raise error.Abort(a.error) + if a in expanding: + raise error.ParseError(_('infinite expansion of %(section)s ' + '"%(name)s" detected') + % {'section': cls._section, + 'name': a.name}) + expanding.append(a) + if a.name not in cache: + cache[a.name] = cls._expand(aliases, a.replacement, expanding, + cache) + result = cache[a.name] + expanding.pop() + if a.args is not None: + l = cls._getlist(tree[2]) + if len(l) != len(a.args): + raise error.ParseError(_('invalid number of arguments: %d') + % len(l)) + l = [cls._expand(aliases, t, [], cache) for t in l] + result = cls._expandargs(result, dict(zip(a.args, l))) + else: + result = tuple(cls._expand(aliases, t, expanding, cache) + for t in tree) + return result + + @classmethod + def expand(cls, aliases, tree): + """Expand aliases in tree, recursively. + + 'aliases' is a dictionary mapping user defined aliases to alias objects. + """ + return cls._expand(aliases, tree, [], {})