Patchwork [2,of,7,V3,RFC] parser: add stub class that will host alias parsing and expansion

mail settings
Submitter Yuya Nishihara
Date April 3, 2016, 9:48 a.m.
Message ID <37cbd68f6cd8760b1465.1459676896@mimosa>
Download mbox | patch
Permalink /patch/14275/
State Accepted
Delegated to: Pierre-Yves David
Headers show


Yuya Nishihara - April 3, 2016, 9:48 a.m.
# HG changeset patch
# User Yuya Nishihara <>
# Date 1459670123 -32400
#      Sun Apr 03 16:55:23 2016 +0900
# Node ID 37cbd68f6cd8760b146570dd8b547589539605fd
# Parent  e2db714a290c5ae731b542011a33961bd631968a
parser: add stub class that will host alias parsing and expansion

This class will keep syntax rules that are necessary to parse and expand
aliases. The implementations will be extracted from the revset module. In
order to make the porting easier, this class keeps parsedecl and parsedefn
separately, which will be unified later. Also, getlist and funcnode will
be refactored by future patches for better handling of the template aliases.

The following public functions will be added:, defn) -> aliasobj
    parse decl and defn into an object that keeps alias name, arguments
    and replacement tree.
  aliasrules.buildmap(aliasitems) -> aliasdict
    helper to build() a dict of alias objects from a list of (decl, defn)
  aliasrules.expand(aliasdict, tree) -> tree
    expand aliases in tree recursively

Because these functions aren't introduced by this series, there would remain
a few wrapper functions in the revset module. These ugly wrappers should be
eliminated by the next series.

This class is considered an inheritable namespace, which will host only
class/static methods. That's because it won't have no object-scope variables.
I'm not a big fan of using class as a syntax sugar, but I admit it can improve
code readability at some level. So let's give it a try.


diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -228,3 +228,39 @@  def parseerrordetail(inst):
         return _('at %s: %s') % (inst.args[1], inst.args[0])
         return inst.args[0]
+class basealiasrules(object):
+    """Parsing and expansion rule set of aliases
+    This is a helper for fileset/revset/template aliases. A concrete rule set
+    should be made by sub-classing this and implementing class/static methods.
+    It supports alias expansion of symbol and funciton-call styles::
+        # decl = defn
+        h = heads(default)
+        b($1) = ancestors($1) - ancestors(default)
+    """
+    # typically a config section, which will be included in error messages
+    _section = None
+    # tags of symbol and function nodes
+    _symbolnode = 'symbol'
+    _funcnode = 'func'
+    def __new__(cls):
+        raise TypeError("'%s' is not instantiatable" % cls.__name__)
+    @staticmethod
+    def _parsedecl(spec):
+        """Parse an alias name and arguments"""
+        raise NotImplementedError
+    @staticmethod
+    def _parsedefn(spec):
+        """Parse an alias definition"""
+        raise NotImplementedError
+    @staticmethod
+    def _getlist(tree):
+        """Extract a list of arguments from parsed tree"""
+        raise NotImplementedError
diff --git a/mercurial/ b/mercurial/
--- a/mercurial/
+++ b/mercurial/
@@ -2370,6 +2370,11 @@  def _parsealiasdefn(defn, args):
     tree = parser.simplifyinfixops(tree, ('list', 'or'))
     return _relabelaliasargs(tree, args)
+class _aliasrules(parser.basealiasrules):
+    """Parsing and expansion rule set of revset aliases"""
+    _section = _('revset alias')
+    _getlist = staticmethod(getlist)
 class revsetalias(object):
     # whether own `error` information is already shown or not.
     # this avoids showing same warning multiple times at each `findaliases`.