comparison mercurial/parser.py @ 28875:2e9f5453ab5a

parser: unify parser function of alias declaration and definition We no longer have to keep them separately.
author Yuya Nishihara <yuya@tcha.org>
date Tue, 29 Mar 2016 00:08:25 +0900
parents 2ca3b7c563f3
children 0c135f37c6f8
comparison
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)