comparison mercurial/parser.py @ 34131:0fa781320203

doctest: bulk-replace string literals with b'' for Python 3 Our code transformer can't rewrite string literals in docstrings, and I don't want to make the transformer more complex.
author Yuya Nishihara <yuya@tcha.org>
date Sun, 03 Sep 2017 14:32:11 +0900
parents 7bbc4e113e5f
children a8994d08e4a2
comparison
equal deleted inserted replaced
34130:ada8a19672ab 34131:0fa781320203
95 return t 95 return t
96 96
97 def splitargspec(spec): 97 def splitargspec(spec):
98 """Parse spec of function arguments into (poskeys, varkey, keys, optkey) 98 """Parse spec of function arguments into (poskeys, varkey, keys, optkey)
99 99
100 >>> splitargspec('') 100 >>> splitargspec(b'')
101 ([], None, [], None) 101 ([], None, [], None)
102 >>> splitargspec('foo bar') 102 >>> splitargspec(b'foo bar')
103 ([], None, ['foo', 'bar'], None) 103 ([], None, ['foo', 'bar'], None)
104 >>> splitargspec('foo *bar baz **qux') 104 >>> splitargspec(b'foo *bar baz **qux')
105 (['foo'], 'bar', ['baz'], 'qux') 105 (['foo'], 'bar', ['baz'], 'qux')
106 >>> splitargspec('*foo') 106 >>> splitargspec(b'*foo')
107 ([], 'foo', [], None) 107 ([], 'foo', [], None)
108 >>> splitargspec('**foo') 108 >>> splitargspec(b'**foo')
109 ([], None, [], 'foo') 109 ([], None, [], 'foo')
110 """ 110 """
111 optkey = None 111 optkey = None
112 pre, sep, post = spec.partition('**') 112 pre, sep, post = spec.partition('**')
113 if sep: 113 if sep:
219 219
220 def simplifyinfixops(tree, targetnodes): 220 def simplifyinfixops(tree, targetnodes):
221 """Flatten chained infix operations to reduce usage of Python stack 221 """Flatten chained infix operations to reduce usage of Python stack
222 222
223 >>> def f(tree): 223 >>> def f(tree):
224 ... print prettyformat(simplifyinfixops(tree, ('or',)), ('symbol',)) 224 ... print prettyformat(simplifyinfixops(tree, (b'or',)), (b'symbol',))
225 >>> f(('or', 225 >>> f((b'or',
226 ... ('or', 226 ... (b'or',
227 ... ('symbol', '1'), 227 ... (b'symbol', b'1'),
228 ... ('symbol', '2')), 228 ... (b'symbol', b'2')),
229 ... ('symbol', '3'))) 229 ... (b'symbol', b'3')))
230 (or 230 (or
231 (symbol '1') 231 (symbol '1')
232 (symbol '2') 232 (symbol '2')
233 (symbol '3')) 233 (symbol '3'))
234 >>> f(('func', 234 >>> f((b'func',
235 ... ('symbol', 'p1'), 235 ... (b'symbol', b'p1'),
236 ... ('or', 236 ... (b'or',
237 ... ('or', 237 ... (b'or',
238 ... ('func', 238 ... (b'func',
239 ... ('symbol', 'sort'), 239 ... (b'symbol', b'sort'),
240 ... ('list', 240 ... (b'list',
241 ... ('or', 241 ... (b'or',
242 ... ('or', 242 ... (b'or',
243 ... ('symbol', '1'), 243 ... (b'symbol', b'1'),
244 ... ('symbol', '2')), 244 ... (b'symbol', b'2')),
245 ... ('symbol', '3')), 245 ... (b'symbol', b'3')),
246 ... ('negate', 246 ... (b'negate',
247 ... ('symbol', 'rev')))), 247 ... (b'symbol', b'rev')))),
248 ... ('and', 248 ... (b'and',
249 ... ('symbol', '4'), 249 ... (b'symbol', b'4'),
250 ... ('group', 250 ... (b'group',
251 ... ('or', 251 ... (b'or',
252 ... ('or', 252 ... (b'or',
253 ... ('symbol', '5'), 253 ... (b'symbol', b'5'),
254 ... ('symbol', '6')), 254 ... (b'symbol', b'6')),
255 ... ('symbol', '7'))))), 255 ... (b'symbol', b'7'))))),
256 ... ('symbol', '8')))) 256 ... (b'symbol', b'8'))))
257 (func 257 (func
258 (symbol 'p1') 258 (symbol 'p1')
259 (or 259 (or
260 (func 260 (func
261 (symbol 'sort') 261 (symbol 'sort')
302 return tuple(_buildtree(x, placeholder, replstack) for x in template) 302 return tuple(_buildtree(x, placeholder, replstack) for x in template)
303 303
304 def buildtree(template, placeholder, *repls): 304 def buildtree(template, placeholder, *repls):
305 """Create new tree by substituting placeholders by replacements 305 """Create new tree by substituting placeholders by replacements
306 306
307 >>> _ = ('symbol', '_') 307 >>> _ = (b'symbol', b'_')
308 >>> def f(template, *repls): 308 >>> def f(template, *repls):
309 ... return buildtree(template, _, *repls) 309 ... return buildtree(template, _, *repls)
310 >>> f(('func', ('symbol', 'only'), ('list', _, _)), 310 >>> f((b'func', (b'symbol', b'only'), (b'list', _, _)),
311 ... ('symbol', '1'), ('symbol', '2')) 311 ... ('symbol', '1'), ('symbol', '2'))
312 ('func', ('symbol', 'only'), ('list', ('symbol', '1'), ('symbol', '2'))) 312 ('func', ('symbol', 'only'), ('list', ('symbol', '1'), ('symbol', '2')))
313 >>> f(('and', _, ('not', _)), ('symbol', '1'), ('symbol', '2')) 313 >>> f((b'and', _, (b'not', _)), (b'symbol', b'1'), (b'symbol', b'2'))
314 ('and', ('symbol', '1'), ('not', ('symbol', '2'))) 314 ('and', ('symbol', '1'), ('not', ('symbol', '2')))
315 """ 315 """
316 if not isinstance(placeholder, tuple): 316 if not isinstance(placeholder, tuple):
317 raise error.ProgrammingError('placeholder must be a node tuple') 317 raise error.ProgrammingError('placeholder must be a node tuple')
318 replstack = list(reversed(repls)) 318 replstack = list(reversed(repls))
337 def matchtree(pattern, tree, placeholder=None, incompletenodes=()): 337 def matchtree(pattern, tree, placeholder=None, incompletenodes=()):
338 """If a tree matches the pattern, return a list of the tree and nodes 338 """If a tree matches the pattern, return a list of the tree and nodes
339 matched with the placeholder; Otherwise None 339 matched with the placeholder; Otherwise None
340 340
341 >>> def f(pattern, tree): 341 >>> def f(pattern, tree):
342 ... m = matchtree(pattern, tree, _, {'keyvalue', 'list'}) 342 ... m = matchtree(pattern, tree, _, {b'keyvalue', b'list'})
343 ... if m: 343 ... if m:
344 ... return m[1:] 344 ... return m[1:]
345 345
346 >>> _ = ('symbol', '_') 346 >>> _ = (b'symbol', b'_')
347 >>> f(('func', ('symbol', 'ancestors'), _), 347 >>> f((b'func', (b'symbol', b'ancestors'), _),
348 ... ('func', ('symbol', 'ancestors'), ('symbol', '1'))) 348 ... (b'func', (b'symbol', b'ancestors'), (b'symbol', b'1')))
349 [('symbol', '1')] 349 [('symbol', '1')]
350 >>> f(('func', ('symbol', 'ancestors'), _), 350 >>> f((b'func', (b'symbol', b'ancestors'), _),
351 ... ('func', ('symbol', 'ancestors'), None)) 351 ... (b'func', (b'symbol', b'ancestors'), None))
352 >>> f(('range', ('dagrange', _, _), _), 352 >>> f((b'range', (b'dagrange', _, _), _),
353 ... ('range', 353 ... (b'range',
354 ... ('dagrange', ('symbol', '1'), ('symbol', '2')), 354 ... (b'dagrange', (b'symbol', b'1'), (b'symbol', b'2')),
355 ... ('symbol', '3'))) 355 ... (b'symbol', b'3')))
356 [('symbol', '1'), ('symbol', '2'), ('symbol', '3')] 356 [('symbol', '1'), ('symbol', '2'), ('symbol', '3')]
357 357
358 The placeholder does not match the specified incomplete nodes because 358 The placeholder does not match the specified incomplete nodes because
359 an incomplete node (e.g. argument list) cannot construct an expression. 359 an incomplete node (e.g. argument list) cannot construct an expression.
360 360
361 >>> f(('func', ('symbol', 'ancestors'), _), 361 >>> f((b'func', (b'symbol', b'ancestors'), _),
362 ... ('func', ('symbol', 'ancestors'), 362 ... (b'func', (b'symbol', b'ancestors'),
363 ... ('list', ('symbol', '1'), ('symbol', '2')))) 363 ... (b'list', (b'symbol', b'1'), (b'symbol', b'2'))))
364 364
365 The placeholder may be omitted, but which shouldn't match a None node. 365 The placeholder may be omitted, but which shouldn't match a None node.
366 366
367 >>> _ = None 367 >>> _ = None
368 >>> f(('func', ('symbol', 'ancestors'), None), 368 >>> f((b'func', (b'symbol', b'ancestors'), None),
369 ... ('func', ('symbol', 'ancestors'), ('symbol', '0'))) 369 ... (b'func', (b'symbol', b'ancestors'), (b'symbol', b'0')))
370 """ 370 """
371 if placeholder is not None and not isinstance(placeholder, tuple): 371 if placeholder is not None and not isinstance(placeholder, tuple):
372 raise error.ProgrammingError('placeholder must be a node tuple') 372 raise error.ProgrammingError('placeholder must be a node tuple')
373 matches = [tree] 373 matches = [tree]
374 if _matchtree(pattern, tree, placeholder, incompletenodes, matches): 374 if _matchtree(pattern, tree, placeholder, incompletenodes, matches):
434 434
435 - ``name``: of declared alias (may be ``decl`` itself at error) 435 - ``name``: of declared alias (may be ``decl`` itself at error)
436 - ``args``: list of argument names (or None for symbol declaration) 436 - ``args``: list of argument names (or None for symbol declaration)
437 - ``errorstr``: detail about detected error (or None) 437 - ``errorstr``: detail about detected error (or None)
438 438
439 >>> sym = lambda x: ('symbol', x) 439 >>> sym = lambda x: (b'symbol', x)
440 >>> symlist = lambda *xs: ('list',) + tuple(sym(x) for x in xs) 440 >>> symlist = lambda *xs: (b'list',) + tuple(sym(x) for x in xs)
441 >>> func = lambda n, a: ('func', sym(n), a) 441 >>> func = lambda n, a: (b'func', sym(n), a)
442 >>> parsemap = { 442 >>> parsemap = {
443 ... 'foo': sym('foo'), 443 ... b'foo': sym(b'foo'),
444 ... '$foo': sym('$foo'), 444 ... b'$foo': sym(b'$foo'),
445 ... 'foo::bar': ('dagrange', sym('foo'), sym('bar')), 445 ... b'foo::bar': (b'dagrange', sym(b'foo'), sym(b'bar')),
446 ... 'foo()': func('foo', None), 446 ... b'foo()': func(b'foo', None),
447 ... '$foo()': func('$foo', None), 447 ... b'$foo()': func(b'$foo', None),
448 ... 'foo($1, $2)': func('foo', symlist('$1', '$2')), 448 ... b'foo($1, $2)': func(b'foo', symlist(b'$1', b'$2')),
449 ... 'foo(bar_bar, baz.baz)': 449 ... b'foo(bar_bar, baz.baz)':
450 ... func('foo', symlist('bar_bar', 'baz.baz')), 450 ... func(b'foo', symlist(b'bar_bar', b'baz.baz')),
451 ... 'foo(bar($1, $2))': 451 ... b'foo(bar($1, $2))':
452 ... func('foo', func('bar', symlist('$1', '$2'))), 452 ... func(b'foo', func(b'bar', symlist(b'$1', b'$2'))),
453 ... 'foo($1, $2, nested($1, $2))': 453 ... b'foo($1, $2, nested($1, $2))':
454 ... func('foo', (symlist('$1', '$2') + 454 ... func(b'foo', (symlist(b'$1', b'$2') +
455 ... (func('nested', symlist('$1', '$2')),))), 455 ... (func(b'nested', symlist(b'$1', b'$2')),))),
456 ... 'foo("bar")': func('foo', ('string', 'bar')), 456 ... b'foo("bar")': func(b'foo', (b'string', b'bar')),
457 ... 'foo($1, $2': error.ParseError('unexpected token: end', 10), 457 ... b'foo($1, $2': error.ParseError(b'unexpected token: end', 10),
458 ... 'foo("bar': error.ParseError('unterminated string', 5), 458 ... b'foo("bar': error.ParseError(b'unterminated string', 5),
459 ... 'foo($1, $2, $1)': func('foo', symlist('$1', '$2', '$1')), 459 ... b'foo($1, $2, $1)': func(b'foo', symlist(b'$1', b'$2', b'$1')),
460 ... } 460 ... }
461 >>> def parse(expr): 461 >>> def parse(expr):
462 ... x = parsemap[expr] 462 ... x = parsemap[expr]
463 ... if isinstance(x, Exception): 463 ... if isinstance(x, Exception):
464 ... raise x 464 ... raise x
465 ... return x 465 ... return x
466 >>> def trygetfunc(tree): 466 >>> def trygetfunc(tree):
467 ... if not tree or tree[0] != 'func' or tree[1][0] != 'symbol': 467 ... if not tree or tree[0] != b'func' or tree[1][0] != b'symbol':
468 ... return None 468 ... return None
469 ... if not tree[2]: 469 ... if not tree[2]:
470 ... return tree[1][1], [] 470 ... return tree[1][1], []
471 ... if tree[2][0] == 'list': 471 ... if tree[2][0] == b'list':
472 ... return tree[1][1], list(tree[2][1:]) 472 ... return tree[1][1], list(tree[2][1:])
473 ... return tree[1][1], [tree[2]] 473 ... return tree[1][1], [tree[2]]
474 >>> class aliasrules(basealiasrules): 474 >>> class aliasrules(basealiasrules):
475 ... _parse = staticmethod(parse) 475 ... _parse = staticmethod(parse)
476 ... _trygetfunc = staticmethod(trygetfunc) 476 ... _trygetfunc = staticmethod(trygetfunc)
477 >>> builddecl = aliasrules._builddecl 477 >>> builddecl = aliasrules._builddecl
478 >>> builddecl('foo') 478 >>> builddecl(b'foo')
479 ('foo', None, None) 479 ('foo', None, None)
480 >>> builddecl('$foo') 480 >>> builddecl(b'$foo')
481 ('$foo', None, "invalid symbol '$foo'") 481 ('$foo', None, "invalid symbol '$foo'")
482 >>> builddecl('foo::bar') 482 >>> builddecl(b'foo::bar')
483 ('foo::bar', None, 'invalid format') 483 ('foo::bar', None, 'invalid format')
484 >>> builddecl('foo()') 484 >>> builddecl(b'foo()')
485 ('foo', [], None) 485 ('foo', [], None)
486 >>> builddecl('$foo()') 486 >>> builddecl(b'$foo()')
487 ('$foo()', None, "invalid function '$foo'") 487 ('$foo()', None, "invalid function '$foo'")
488 >>> builddecl('foo($1, $2)') 488 >>> builddecl(b'foo($1, $2)')
489 ('foo', ['$1', '$2'], None) 489 ('foo', ['$1', '$2'], None)
490 >>> builddecl('foo(bar_bar, baz.baz)') 490 >>> builddecl(b'foo(bar_bar, baz.baz)')
491 ('foo', ['bar_bar', 'baz.baz'], None) 491 ('foo', ['bar_bar', 'baz.baz'], None)
492 >>> builddecl('foo($1, $2, nested($1, $2))') 492 >>> builddecl(b'foo($1, $2, nested($1, $2))')
493 ('foo($1, $2, nested($1, $2))', None, 'invalid argument list') 493 ('foo($1, $2, nested($1, $2))', None, 'invalid argument list')
494 >>> builddecl('foo(bar($1, $2))') 494 >>> builddecl(b'foo(bar($1, $2))')
495 ('foo(bar($1, $2))', None, 'invalid argument list') 495 ('foo(bar($1, $2))', None, 'invalid argument list')
496 >>> builddecl('foo("bar")') 496 >>> builddecl(b'foo("bar")')
497 ('foo("bar")', None, 'invalid argument list') 497 ('foo("bar")', None, 'invalid argument list')
498 >>> builddecl('foo($1, $2') 498 >>> builddecl(b'foo($1, $2')
499 ('foo($1, $2', None, 'at 10: unexpected token: end') 499 ('foo($1, $2', None, 'at 10: unexpected token: end')
500 >>> builddecl('foo("bar') 500 >>> builddecl(b'foo("bar')
501 ('foo("bar', None, 'at 5: unterminated string') 501 ('foo("bar', None, 'at 5: unterminated string')
502 >>> builddecl('foo($1, $2, $1)') 502 >>> builddecl(b'foo($1, $2, $1)')
503 ('foo', None, 'argument names collide with each other') 503 ('foo', None, 'argument names collide with each other')
504 """ 504 """
505 try: 505 try:
506 tree = cls._parse(decl) 506 tree = cls._parse(decl)
507 except error.ParseError as inst: 507 except error.ParseError as inst:
554 554
555 ``args`` is a list of alias argument names, or None if the alias 555 ``args`` is a list of alias argument names, or None if the alias
556 is declared as a symbol. 556 is declared as a symbol.
557 557
558 >>> parsemap = { 558 >>> parsemap = {
559 ... '$1 or foo': ('or', ('symbol', '$1'), ('symbol', 'foo')), 559 ... b'$1 or foo': (b'or', (b'symbol', b'$1'), (b'symbol', b'foo')),
560 ... '$1 or $bar': ('or', ('symbol', '$1'), ('symbol', '$bar')), 560 ... b'$1 or $bar':
561 ... '$10 or baz': ('or', ('symbol', '$10'), ('symbol', 'baz')), 561 ... (b'or', (b'symbol', b'$1'), (b'symbol', b'$bar')),
562 ... '"$1" or "foo"': ('or', ('string', '$1'), ('string', 'foo')), 562 ... b'$10 or baz':
563 ... (b'or', (b'symbol', b'$10'), (b'symbol', b'baz')),
564 ... b'"$1" or "foo"':
565 ... (b'or', (b'string', b'$1'), (b'string', b'foo')),
563 ... } 566 ... }
564 >>> class aliasrules(basealiasrules): 567 >>> class aliasrules(basealiasrules):
565 ... _parse = staticmethod(parsemap.__getitem__) 568 ... _parse = staticmethod(parsemap.__getitem__)
566 ... _trygetfunc = staticmethod(lambda x: None) 569 ... _trygetfunc = staticmethod(lambda x: None)
567 >>> builddefn = aliasrules._builddefn 570 >>> builddefn = aliasrules._builddefn
568 >>> def pprint(tree): 571 >>> def pprint(tree):
569 ... print prettyformat(tree, ('_aliasarg', 'string', 'symbol')) 572 ... print prettyformat(tree, (b'_aliasarg', b'string', b'symbol'))
570 >>> args = ['$1', '$2', 'foo'] 573 >>> args = [b'$1', b'$2', b'foo']
571 >>> pprint(builddefn('$1 or foo', args)) 574 >>> pprint(builddefn(b'$1 or foo', args))
572 (or 575 (or
573 (_aliasarg '$1') 576 (_aliasarg '$1')
574 (_aliasarg 'foo')) 577 (_aliasarg 'foo'))
575 >>> try: 578 >>> try:
576 ... builddefn('$1 or $bar', args) 579 ... builddefn(b'$1 or $bar', args)
577 ... except error.ParseError as inst: 580 ... except error.ParseError as inst:
578 ... print parseerrordetail(inst) 581 ... print parseerrordetail(inst)
579 invalid symbol '$bar' 582 invalid symbol '$bar'
580 >>> args = ['$1', '$10', 'foo'] 583 >>> args = [b'$1', b'$10', b'foo']
581 >>> pprint(builddefn('$10 or baz', args)) 584 >>> pprint(builddefn(b'$10 or baz', args))
582 (or 585 (or
583 (_aliasarg '$10') 586 (_aliasarg '$10')
584 (symbol 'baz')) 587 (symbol 'baz'))
585 >>> pprint(builddefn('"$1" or "foo"', args)) 588 >>> pprint(builddefn(b'"$1" or "foo"', args))
586 (or 589 (or
587 (string '$1') 590 (string '$1')
588 (string 'foo')) 591 (string 'foo'))
589 """ 592 """
590 tree = cls._parse(defn) 593 tree = cls._parse(defn)