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.
This commit is contained in:
Yuya Nishihara 2016-02-29 22:15:44 +09:00
parent 5da75dff02
commit 45e9c21bc0
2 changed files with 71 additions and 64 deletions

View File

@ -472,3 +472,73 @@ class basealiasrules(object):
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, [], {})

View File

@ -2256,72 +2256,9 @@ class _aliasrules(parser.basealiasrules):
_parse = staticmethod(_parsealias)
_getlist = staticmethod(getlist)
def _getalias(aliases, tree):
"""If tree looks like an unexpanded alias, return it. Return None
otherwise.
"""
if not isinstance(tree, tuple):
return None
if tree[0] == 'symbol':
name = tree[1]
alias = aliases.get(name)
if alias and alias.args is None and alias.tree == tree:
return alias
if tree[0] == 'func' and tree[1][0] == 'symbol':
name = tree[1][1]
alias = aliases.get(name)
if alias and alias.args is not None and alias.tree == tree[:2]:
return alias
return None
def _expandargs(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(_expandargs(t, args) for t in tree)
def _expandaliases(aliases, tree, expanding, cache):
"""Expand aliases in tree, recursively.
'aliases' is a dictionary mapping user defined aliases to
alias objects.
"""
if not isinstance(tree, tuple):
# Do not expand raw strings
return tree
alias = _getalias(aliases, tree)
if alias is not None:
if alias.error:
raise error.Abort(alias.error)
if alias in expanding:
raise error.ParseError(_('infinite expansion of revset alias "%s" '
'detected') % alias.name)
expanding.append(alias)
if alias.name not in cache:
cache[alias.name] = _expandaliases(aliases, alias.replacement,
expanding, cache)
result = cache[alias.name]
expanding.pop()
if alias.args is not None:
l = getlist(tree[2])
if len(l) != len(alias.args):
raise error.ParseError(
_('invalid number of arguments: %d') % len(l))
l = [_expandaliases(aliases, a, [], cache) for a in l]
result = _expandargs(result, dict(zip(alias.args, l)))
else:
result = tuple(_expandaliases(aliases, t, expanding, cache)
for t in tree)
return result
def findaliases(ui, tree, showwarning=None):
aliases = _aliasrules.buildmap(ui.configitems('revsetalias'))
tree = _expandaliases(aliases, tree, [], {})
tree = _aliasrules.expand(aliases, tree)
if showwarning:
# warn about problematic (but not referred) aliases
for name, alias in sorted(aliases.iteritems()):