Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/parser.py @ 28908:7a772deffa12
parser: drop redundant comparison between alias declaration tree and pattern
Since _getalias() explicitly tests the type and name of the pattern tree, we
don't need to compare "a.tree == tree" for 'symbol', and "a.tree == tree[:2]"
for 'func', where tree is either ('symbol', name) or ('func', ('symbol', name)).
This change helps implementing better handling of template aliases. See the
subsequent patches for details.
The alias.tree field is removed as it is no longer used.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Tue, 29 Mar 2016 16:50:16 +0900 |
parents | 8d398155bfda |
children | edbffdc7f6a0 |
comparison
equal
deleted
inserted
replaced
28907:66e647312d30 | 28908:7a772deffa12 |
---|---|
230 return inst.args[0] | 230 return inst.args[0] |
231 | 231 |
232 class alias(object): | 232 class alias(object): |
233 """Parsed result of alias""" | 233 """Parsed result of alias""" |
234 | 234 |
235 def __init__(self, name, tree, args, err, replacement): | 235 def __init__(self, name, args, err, replacement): |
236 self.name = name | 236 self.name = name |
237 self.tree = tree | |
238 self.args = args | 237 self.args = args |
239 self.error = err | 238 self.error = err |
240 self.replacement = replacement | 239 self.replacement = replacement |
241 # whether own `error` information is already shown or not. | 240 # whether own `error` information is already shown or not. |
242 # this avoids showing same warning multiple times at each | 241 # this avoids showing same warning multiple times at each |
274 """Extract a list of arguments from parsed tree""" | 273 """Extract a list of arguments from parsed tree""" |
275 raise NotImplementedError | 274 raise NotImplementedError |
276 | 275 |
277 @classmethod | 276 @classmethod |
278 def _builddecl(cls, decl): | 277 def _builddecl(cls, decl): |
279 """Parse an alias declaration into ``(name, tree, args, errorstr)`` | 278 """Parse an alias declaration into ``(name, args, errorstr)`` |
280 | 279 |
281 This function analyzes the parsed tree. The parsing rule is provided | 280 This function analyzes the parsed tree. The parsing rule is provided |
282 by ``_parse()``. | 281 by ``_parse()``. |
283 | 282 |
284 - ``name``: of declared alias (may be ``decl`` itself at error) | 283 - ``name``: of declared alias (may be ``decl`` itself at error) |
285 - ``tree``: parse result (or ``None`` at error) | |
286 - ``args``: list of argument names (or None for symbol declaration) | 284 - ``args``: list of argument names (or None for symbol declaration) |
287 - ``errorstr``: detail about detected error (or None) | 285 - ``errorstr``: detail about detected error (or None) |
288 | 286 |
289 >>> sym = lambda x: ('symbol', x) | 287 >>> sym = lambda x: ('symbol', x) |
290 >>> symlist = lambda *xs: ('list',) + tuple(sym(x) for x in xs) | 288 >>> symlist = lambda *xs: ('list',) + tuple(sym(x) for x in xs) |
322 >>> class aliasrules(basealiasrules): | 320 >>> class aliasrules(basealiasrules): |
323 ... _parse = staticmethod(parse) | 321 ... _parse = staticmethod(parse) |
324 ... _getlist = staticmethod(getlist) | 322 ... _getlist = staticmethod(getlist) |
325 >>> builddecl = aliasrules._builddecl | 323 >>> builddecl = aliasrules._builddecl |
326 >>> builddecl('foo') | 324 >>> builddecl('foo') |
327 ('foo', ('symbol', 'foo'), None, None) | 325 ('foo', None, None) |
328 >>> builddecl('$foo') | 326 >>> builddecl('$foo') |
329 ('$foo', None, None, "'$' not for alias arguments") | 327 ('$foo', None, "'$' not for alias arguments") |
330 >>> builddecl('foo::bar') | 328 >>> builddecl('foo::bar') |
331 ('foo::bar', None, None, 'invalid format') | 329 ('foo::bar', None, 'invalid format') |
332 >>> builddecl('foo()') | 330 >>> builddecl('foo()') |
333 ('foo', ('func', ('symbol', 'foo')), [], None) | 331 ('foo', [], None) |
334 >>> builddecl('$foo()') | 332 >>> builddecl('$foo()') |
335 ('$foo()', None, None, "'$' not for alias arguments") | 333 ('$foo()', None, "'$' not for alias arguments") |
336 >>> builddecl('foo($1, $2)') | 334 >>> builddecl('foo($1, $2)') |
337 ('foo', ('func', ('symbol', 'foo')), ['$1', '$2'], None) | 335 ('foo', ['$1', '$2'], None) |
338 >>> builddecl('foo(bar_bar, baz.baz)') | 336 >>> builddecl('foo(bar_bar, baz.baz)') |
339 ('foo', ('func', ('symbol', 'foo')), ['bar_bar', 'baz.baz'], None) | 337 ('foo', ['bar_bar', 'baz.baz'], None) |
340 >>> builddecl('foo($1, $2, nested($1, $2))') | 338 >>> builddecl('foo($1, $2, nested($1, $2))') |
341 ('foo($1, $2, nested($1, $2))', None, None, 'invalid argument list') | 339 ('foo($1, $2, nested($1, $2))', None, 'invalid argument list') |
342 >>> builddecl('foo(bar($1, $2))') | 340 >>> builddecl('foo(bar($1, $2))') |
343 ('foo(bar($1, $2))', None, None, 'invalid argument list') | 341 ('foo(bar($1, $2))', None, 'invalid argument list') |
344 >>> builddecl('foo("bar")') | 342 >>> builddecl('foo("bar")') |
345 ('foo("bar")', None, None, 'invalid argument list') | 343 ('foo("bar")', None, 'invalid argument list') |
346 >>> builddecl('foo($1, $2') | 344 >>> builddecl('foo($1, $2') |
347 ('foo($1, $2', None, None, 'at 10: unexpected token: end') | 345 ('foo($1, $2', None, 'at 10: unexpected token: end') |
348 >>> builddecl('foo("bar') | 346 >>> builddecl('foo("bar') |
349 ('foo("bar', None, None, 'at 5: unterminated string') | 347 ('foo("bar', None, 'at 5: unterminated string') |
350 >>> builddecl('foo($1, $2, $1)') | 348 >>> builddecl('foo($1, $2, $1)') |
351 ('foo', None, None, 'argument names collide with each other') | 349 ('foo', None, 'argument names collide with each other') |
352 """ | 350 """ |
353 try: | 351 try: |
354 tree = cls._parse(decl) | 352 tree = cls._parse(decl) |
355 except error.ParseError as inst: | 353 except error.ParseError as inst: |
356 return (decl, None, None, parseerrordetail(inst)) | 354 return (decl, None, parseerrordetail(inst)) |
357 | 355 |
358 if tree[0] == cls._symbolnode: | 356 if tree[0] == cls._symbolnode: |
359 # "name = ...." style | 357 # "name = ...." style |
360 name = tree[1] | 358 name = tree[1] |
361 if name.startswith('$'): | 359 if name.startswith('$'): |
362 return (decl, None, None, _("'$' not for alias arguments")) | 360 return (decl, None, _("'$' not for alias arguments")) |
363 return (name, tree, None, None) | 361 return (name, None, None) |
364 | 362 |
365 if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: | 363 if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: |
366 # "name(arg, ....) = ...." style | 364 # "name(arg, ....) = ...." style |
367 name = tree[1][1] | 365 name = tree[1][1] |
368 if name.startswith('$'): | 366 if name.startswith('$'): |
369 return (decl, None, None, _("'$' not for alias arguments")) | 367 return (decl, None, _("'$' not for alias arguments")) |
370 args = [] | 368 args = [] |
371 for arg in cls._getlist(tree[2]): | 369 for arg in cls._getlist(tree[2]): |
372 if arg[0] != cls._symbolnode: | 370 if arg[0] != cls._symbolnode: |
373 return (decl, None, None, _("invalid argument list")) | 371 return (decl, None, _("invalid argument list")) |
374 args.append(arg[1]) | 372 args.append(arg[1]) |
375 if len(args) != len(set(args)): | 373 if len(args) != len(set(args)): |
376 return (name, None, None, | 374 return (name, None, _("argument names collide with each other")) |
377 _("argument names collide with each other")) | 375 return (name, args, None) |
378 return (name, tree[:2], args, None) | 376 |
379 | 377 return (decl, None, _("invalid format")) |
380 return (decl, None, None, _("invalid format")) | |
381 | 378 |
382 @classmethod | 379 @classmethod |
383 def _relabelargs(cls, tree, args): | 380 def _relabelargs(cls, tree, args): |
384 """Mark alias arguments as ``_aliasarg``""" | 381 """Mark alias arguments as ``_aliasarg``""" |
385 if not isinstance(tree, tuple): | 382 if not isinstance(tree, tuple): |
447 | 444 |
448 @classmethod | 445 @classmethod |
449 def build(cls, decl, defn): | 446 def build(cls, decl, defn): |
450 """Parse an alias declaration and definition into an alias object""" | 447 """Parse an alias declaration and definition into an alias object""" |
451 repl = efmt = None | 448 repl = efmt = None |
452 name, tree, args, err = cls._builddecl(decl) | 449 name, args, err = cls._builddecl(decl) |
453 if err: | 450 if err: |
454 efmt = _('failed to parse the declaration of %(section)s ' | 451 efmt = _('failed to parse the declaration of %(section)s ' |
455 '"%(name)s": %(error)s') | 452 '"%(name)s": %(error)s') |
456 else: | 453 else: |
457 try: | 454 try: |
460 err = parseerrordetail(inst) | 457 err = parseerrordetail(inst) |
461 efmt = _('failed to parse the definition of %(section)s ' | 458 efmt = _('failed to parse the definition of %(section)s ' |
462 '"%(name)s": %(error)s') | 459 '"%(name)s": %(error)s') |
463 if err: | 460 if err: |
464 err = efmt % {'section': cls._section, 'name': name, 'error': err} | 461 err = efmt % {'section': cls._section, 'name': name, 'error': err} |
465 return alias(name, tree, args, err, repl) | 462 return alias(name, args, err, repl) |
466 | 463 |
467 @classmethod | 464 @classmethod |
468 def buildmap(cls, items): | 465 def buildmap(cls, items): |
469 """Parse a list of alias (name, replacement) pairs into a dict of | 466 """Parse a list of alias (name, replacement) pairs into a dict of |
470 alias objects""" | 467 alias objects""" |
482 if not isinstance(tree, tuple): | 479 if not isinstance(tree, tuple): |
483 return None | 480 return None |
484 if tree[0] == cls._symbolnode: | 481 if tree[0] == cls._symbolnode: |
485 name = tree[1] | 482 name = tree[1] |
486 a = aliases.get(name) | 483 a = aliases.get(name) |
487 if a and a.args is None and a.tree == tree: | 484 if a and a.args is None: |
488 return a | 485 return a |
489 if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: | 486 if tree[0] == cls._funcnode and tree[1][0] == cls._symbolnode: |
490 name = tree[1][1] | 487 name = tree[1][1] |
491 a = aliases.get(name) | 488 a = aliases.get(name) |
492 if a and a.args is not None and a.tree == tree[:2]: | 489 if a and a.args is not None: |
493 return a | 490 return a |
494 return None | 491 return None |
495 | 492 |
496 @classmethod | 493 @classmethod |
497 def _expandargs(cls, tree, args): | 494 def _expandargs(cls, tree, args): |