parser: factor out _trygetfunc() that extracts function name and arguments
This provides a customization point for templater. In templater, there are
two ways to call a unary function: func(x) and x|func. They are processed
differently in templater due to historical reasons, but they should be
handled in the same way while expanding aliases. In short, x|func should be
processed as syntactic sugar for func(x).
_funcnode and _getlist() are replaced by _trygetfunc().
--- a/mercurial/parser.py Tue Mar 29 17:21:11 2016 +0900
+++ b/mercurial/parser.py Tue Mar 29 17:27:34 2016 +0900
@@ -256,9 +256,8 @@
"""
# typically a config section, which will be included in error messages
_section = None
- # tags of symbol and function nodes
+ # tag of symbol node
_symbolnode = 'symbol'
- _funcnode = 'func'
def __new__(cls):
raise TypeError("'%s' is not instantiatable" % cls.__name__)
@@ -269,8 +268,8 @@
raise NotImplementedError
@staticmethod
- def _getlist(tree):
- """Extract a list of arguments from parsed tree"""
+ def _trygetfunc(tree):
+ """Return (name, args) if tree is a function; otherwise None"""
raise NotImplementedError
@classmethod
@@ -311,15 +310,17 @@
... if isinstance(x, Exception):
... raise x
... return x
- >>> def getlist(tree):
- ... if not tree:
- ... return []
- ... if tree[0] == 'list':
- ... return list(tree[1:])
- ... return [tree]
+ >>> def trygetfunc(tree):
+ ... if not tree or tree[0] != 'func' or tree[1][0] != 'symbol':
+ ... return None
+ ... if not tree[2]:
+ ... return tree[1][1], []
+ ... if tree[2][0] == 'list':
+ ... return tree[1][1], list(tree[2][1:])
+ ... return tree[1][1], [tree[2]]
>>> class aliasrules(basealiasrules):
... _parse = staticmethod(parse)
- ... _getlist = staticmethod(getlist)
+ ... _trygetfunc = staticmethod(trygetfunc)
>>> builddecl = aliasrules._builddecl
>>> builddecl('foo')
('foo', None, None)
@@ -360,19 +361,17 @@
return (decl, None, _("'$' not for alias arguments"))
return (name, None, None)
- if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode:
+ func = cls._trygetfunc(tree)
+ if func:
# "name(arg, ....) = ...." style
- name = tree[1][1]
+ name, args = func
if name.startswith('$'):
return (decl, None, _("'$' not for alias arguments"))
- args = []
- for arg in cls._getlist(tree[2]):
- if arg[0] != cls._symbolnode:
- return (decl, None, _("invalid argument list"))
- args.append(arg[1])
+ if any(t[0] != cls._symbolnode for t in args):
+ return (decl, None, _("invalid argument list"))
if len(args) != len(set(args)):
return (name, None, _("argument names collide with each other"))
- return (name, args, None)
+ return (name, [t[1] for t in args], None)
return (decl, None, _("invalid format"))
@@ -411,7 +410,7 @@
... }
>>> class aliasrules(basealiasrules):
... _parse = staticmethod(parsemap.__getitem__)
- ... _getlist = staticmethod(lambda x: [])
+ ... _trygetfunc = staticmethod(lambda x: None)
>>> builddefn = aliasrules._builddefn
>>> def pprint(tree):
... print prettyformat(tree, ('_aliasarg', 'string', 'symbol'))
@@ -483,11 +482,12 @@
a = aliases.get(name)
if a and a.args is None:
return a, None
- if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode:
- name = tree[1][1]
+ func = cls._trygetfunc(tree)
+ if func:
+ name, args = func
a = aliases.get(name)
if a and a.args is not None:
- return a, cls._getlist(tree[2])
+ return a, args
return None
@classmethod
--- a/mercurial/revset.py Tue Mar 29 17:21:11 2016 +0900
+++ b/mercurial/revset.py Tue Mar 29 17:27:34 2016 +0900
@@ -2254,7 +2254,11 @@
"""Parsing and expansion rule set of revset aliases"""
_section = _('revset alias')
_parse = staticmethod(_parsealias)
- _getlist = staticmethod(getlist)
+
+ @staticmethod
+ def _trygetfunc(tree):
+ if tree[0] == 'func' and tree[1][0] == 'symbol':
+ return tree[1][1], getlist(tree[2])
def expandaliases(ui, tree, showwarning=None):
aliases = _aliasrules.buildmap(ui.configitems('revsetalias'))