changeset 25705:48919d246a47

revset: add function to build dict of positional and keyword arguments Keyword arguments will be convenient for functions that will take more than one optional or boolean flags. For example, file(pattern[, subrepos=false]) subrepo([[pattern], status]) Because I don't think all functions should accept key=value syntax, getkwargs() does not support variadic functions such as 'ancestor(*changeset)'. The core logic is placed in the parser module because keyword arguments will be more useful in the templater, where functions take more options. Test cases will be added by the next patch.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 27 Jun 2015 17:25:01 +0900
parents 70a2082f855a
children b7f53c474e2c
files mercurial/parser.py mercurial/revset.py
diffstat 2 files changed, 36 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/parser.py	Sat Jun 27 17:05:28 2015 +0900
+++ b/mercurial/parser.py	Sat Jun 27 17:25:01 2015 +0900
@@ -91,6 +91,38 @@
             return self.eval(t)
         return t
 
+def buildargsdict(trees, funcname, keys, keyvaluenode, keynode):
+    """Build dict from list containing positional and keyword arguments
+
+    Invalid keywords or too many positional arguments are rejected, but
+    missing arguments are just omitted.
+    """
+    if len(trees) > len(keys):
+        raise error.ParseError(_("%(func)s takes at most %(nargs)d arguments")
+                               % {'func': funcname, 'nargs': len(keys)})
+    args = {}
+    # consume positional arguments
+    for k, x in zip(keys, trees):
+        if x[0] == keyvaluenode:
+            break
+        args[k] = x
+    # remainder should be keyword arguments
+    for x in trees[len(args):]:
+        if x[0] != keyvaluenode or x[1][0] != keynode:
+            raise error.ParseError(_("%(func)s got an invalid argument")
+                                   % {'func': funcname})
+        k = x[1][1]
+        if k not in keys:
+            raise error.ParseError(_("%(func)s got an unexpected keyword "
+                                     "argument '%(key)s'")
+                                   % {'func': funcname, 'key': k})
+        if k in args:
+            raise error.ParseError(_("%(func)s got multiple values for keyword "
+                                     "argument '%(key)s'")
+                                   % {'func': funcname, 'key': k})
+        args[k] = x[2]
+    return args
+
 def _prettyformat(tree, leafnodes, level, lines):
     if not isinstance(tree, tuple) or tree[0] in leafnodes:
         lines.append((level, str(tree)))
--- a/mercurial/revset.py	Sat Jun 27 17:05:28 2015 +0900
+++ b/mercurial/revset.py	Sat Jun 27 17:25:01 2015 +0900
@@ -282,6 +282,10 @@
         raise error.ParseError(err)
     return l
 
+def getkwargs(x, funcname, keys):
+    return parser.buildargsdict(getlist(x), funcname, keys.split(),
+                                keyvaluenode='keyvalue', keynode='symbol')
+
 def isvalidsymbol(tree):
     """Examine whether specified ``tree`` is valid ``symbol`` or not
     """