mercurial/parser.py
changeset 28875 2e9f5453ab5a
parent 28873 2ca3b7c563f3
child 28892 0c135f37c6f8
equal deleted inserted replaced
28874:552eabef663b 28875:2e9f5453ab5a
   249 
   249 
   250     def __new__(cls):
   250     def __new__(cls):
   251         raise TypeError("'%s' is not instantiatable" % cls.__name__)
   251         raise TypeError("'%s' is not instantiatable" % cls.__name__)
   252 
   252 
   253     @staticmethod
   253     @staticmethod
   254     def _parsedecl(spec):
   254     def _parse(spec):
   255         """Parse an alias name and arguments"""
   255         """Parse an alias name, arguments and definition"""
   256         raise NotImplementedError
       
   257 
       
   258     @staticmethod
       
   259     def _parsedefn(spec):
       
   260         """Parse an alias definition"""
       
   261         raise NotImplementedError
   256         raise NotImplementedError
   262 
   257 
   263     @staticmethod
   258     @staticmethod
   264     def _getlist(tree):
   259     def _getlist(tree):
   265         """Extract a list of arguments from parsed tree"""
   260         """Extract a list of arguments from parsed tree"""
   268     @classmethod
   263     @classmethod
   269     def _builddecl(cls, decl):
   264     def _builddecl(cls, decl):
   270         """Parse an alias declaration into ``(name, tree, args, errorstr)``
   265         """Parse an alias declaration into ``(name, tree, args, errorstr)``
   271 
   266 
   272         This function analyzes the parsed tree. The parsing rule is provided
   267         This function analyzes the parsed tree. The parsing rule is provided
   273         by ``_parsedecl()``.
   268         by ``_parse()``.
   274 
   269 
   275         - ``name``: of declared alias (may be ``decl`` itself at error)
   270         - ``name``: of declared alias (may be ``decl`` itself at error)
   276         - ``tree``: parse result (or ``None`` at error)
   271         - ``tree``: parse result (or ``None`` at error)
   277         - ``args``: list of argument names (or None for symbol declaration)
   272         - ``args``: list of argument names (or None for symbol declaration)
   278         - ``errorstr``: detail about detected error (or None)
   273         - ``errorstr``: detail about detected error (or None)
   309         ...         return []
   304         ...         return []
   310         ...     if tree[0] == 'list':
   305         ...     if tree[0] == 'list':
   311         ...         return list(tree[1:])
   306         ...         return list(tree[1:])
   312         ...     return [tree]
   307         ...     return [tree]
   313         >>> class aliasrules(basealiasrules):
   308         >>> class aliasrules(basealiasrules):
   314         ...     _parsedecl = staticmethod(parse)
   309         ...     _parse = staticmethod(parse)
   315         ...     _getlist = staticmethod(getlist)
   310         ...     _getlist = staticmethod(getlist)
   316         >>> builddecl = aliasrules._builddecl
   311         >>> builddecl = aliasrules._builddecl
   317         >>> builddecl('foo')
   312         >>> builddecl('foo')
   318         ('foo', ('symbol', 'foo'), None, None)
   313         ('foo', ('symbol', 'foo'), None, None)
   319         >>> builddecl('$foo')
   314         >>> builddecl('$foo')
   340         ('foo("bar', None, None, 'at 5: unterminated string')
   335         ('foo("bar', None, None, 'at 5: unterminated string')
   341         >>> builddecl('foo($1, $2, $1)')
   336         >>> builddecl('foo($1, $2, $1)')
   342         ('foo', None, None, 'argument names collide with each other')
   337         ('foo', None, None, 'argument names collide with each other')
   343         """
   338         """
   344         try:
   339         try:
   345             tree = cls._parsedecl(decl)
   340             tree = cls._parse(decl)
   346         except error.ParseError as inst:
   341         except error.ParseError as inst:
   347             return (decl, None, None, parseerrordetail(inst))
   342             return (decl, None, None, parseerrordetail(inst))
   348 
   343 
   349         if tree[0] == cls._symbolnode:
   344         if tree[0] == cls._symbolnode:
   350             # "name = ...." style
   345             # "name = ...." style
   390     @classmethod
   385     @classmethod
   391     def _builddefn(cls, defn, args):
   386     def _builddefn(cls, defn, args):
   392         """Parse an alias definition into a tree and marks substitutions
   387         """Parse an alias definition into a tree and marks substitutions
   393 
   388 
   394         This function marks alias argument references as ``_aliasarg``. The
   389         This function marks alias argument references as ``_aliasarg``. The
   395         parsing rule is provided by ``_parsedefn()``.
   390         parsing rule is provided by ``_parse()``.
   396 
   391 
   397         ``args`` is a list of alias argument names, or None if the alias
   392         ``args`` is a list of alias argument names, or None if the alias
   398         is declared as a symbol.
   393         is declared as a symbol.
   399 
   394 
   400         >>> parsemap = {
   395         >>> parsemap = {
   402         ...     '$1 or $bar': ('or', ('symbol', '$1'), ('symbol', '$bar')),
   397         ...     '$1 or $bar': ('or', ('symbol', '$1'), ('symbol', '$bar')),
   403         ...     '$10 or baz': ('or', ('symbol', '$10'), ('symbol', 'baz')),
   398         ...     '$10 or baz': ('or', ('symbol', '$10'), ('symbol', 'baz')),
   404         ...     '"$1" or "foo"': ('or', ('string', '$1'), ('string', 'foo')),
   399         ...     '"$1" or "foo"': ('or', ('string', '$1'), ('string', 'foo')),
   405         ... }
   400         ... }
   406         >>> class aliasrules(basealiasrules):
   401         >>> class aliasrules(basealiasrules):
   407         ...     _parsedefn = staticmethod(parsemap.__getitem__)
   402         ...     _parse = staticmethod(parsemap.__getitem__)
   408         ...     _getlist = staticmethod(lambda x: [])
   403         ...     _getlist = staticmethod(lambda x: [])
   409         >>> builddefn = aliasrules._builddefn
   404         >>> builddefn = aliasrules._builddefn
   410         >>> def pprint(tree):
   405         >>> def pprint(tree):
   411         ...     print prettyformat(tree, ('_aliasarg', 'string', 'symbol'))
   406         ...     print prettyformat(tree, ('_aliasarg', 'string', 'symbol'))
   412         >>> args = ['$1', '$2', 'foo']
   407         >>> args = ['$1', '$2', 'foo']
   427         >>> pprint(builddefn('"$1" or "foo"', args))
   422         >>> pprint(builddefn('"$1" or "foo"', args))
   428         (or
   423         (or
   429           ('string', '$1')
   424           ('string', '$1')
   430           ('string', 'foo'))
   425           ('string', 'foo'))
   431         """
   426         """
   432         tree = cls._parsedefn(defn)
   427         tree = cls._parse(defn)
   433         if args:
   428         if args:
   434             args = set(args)
   429             args = set(args)
   435         else:
   430         else:
   436             args = set()
   431             args = set()
   437         return cls._relabelargs(tree, args)
   432         return cls._relabelargs(tree, args)