o ]Lbf@sddlmZmZddlmZddlmZmZddlm Z Gddde Z dd Z d d Z d d ZddZddZddZddZddZddZd$ddZddZGd d!d!e ZGd"d#d#e ZdS)%)absolute_importprint_function)_)errorutil) stringutilc@sZeZdZdddZddZddZdd Zdd d Zdd dZddZ ddZ ddZ dS)parserNcCs||_||_d|_dSN) _elements_methodscurrent)selfelementsmethodsr2/usr/lib/python3/dist-packages/mercurial/parser.py__init__s zparser.__init__cCs|j}t|jd|_|S)zadvance the tokenizerN)r next_iter)rtrrr_advance#szparser._advancecCst|j|jdddS)z%True if next token may start new termrr)anyr r rrrr _hasnewterm)szparser._hasnewtermcCs:|jd|krttd|jd|jd|dS)z0make sure the tokenizer matches an end conditionrsunexpected token: %sN)r r ParseErrorrr)rmrrr_match-s  z parser._matchcCs4|r |jd|kr d}n||}|r|||S)zLgather right-hand-side operand until an end condition or binding metrN)r _parser)rbindrexprrrr _parseoperand5s   zparser._parseoperandrc Cs|\}}}|j|dd\}}|r|r|s||f}n|r/|d|j|ddf}n ttd||||j|jddkr|\}}}|j|dd\}} | rd|r_|sd| |f}n|ru|d||j|ddf}n ttd||||j|jddksE|S)Nrrrsnot a prefix: %ssnot an infix: %s)rr rr#rrrr ) rr!tokenvalueposprimaryprefixr"infixsuffixrrrr @s"   z parser._parsecCs*||_||}|j\}}}||fS)z!generate a parse tree from tokens)rrr r )r tokeniterresr$r%r&rrrparseWs  z parser.parsecs6t|ts|Sj|dfdd|ddDS)z4recursively evaluate a parse tree using node methodsrcsg|]}|qSr)eval.0rrrr cszparser.eval..rN) isinstancetupler )rtreerrrr._s (z parser.evalcCs||}|jr ||S|S)z>> splitargspec(b'') ([], None, [], None) >>> splitargspec(b'foo bar') ([], None, ['foo', 'bar'], None) >>> splitargspec(b'foo *bar baz **qux') (['foo'], 'bar', ['baz'], 'qux') >>> splitargspec(b'*foo') ([], 'foo', [], None) >>> splitargspec(b'**foo') ([], None, [], 'foo') Ns**sno **optkey name providedrs!excessive **optkey names providedr*sno *varkey name provided) partitionsplitrProgrammingErrorlen)specoptkeypreseppostpostspresrrr splitargspecms"     rEcs|\}}}}tfddt|Dt|} | t|kr*ttd|t|d|sH| t|t|krHttd|t|t|dt} t||d| D]\} } | | | <qU|rk|t| | | |<nt||t| | D]\} } | | | <qv|rt| |<|| dD]R} | r| dks| dd|krttd d |i| dd} | |vr| } n|sttd || d | |} | | vrttd || d | d| | <q| S)aBuild dict from list containing positional and keyword arguments Arguments are specified by a tuple of ``(poskeys, varkey, keys, optkey)`` where - ``poskeys``: list of names of positional arguments - ``varkey``: optional argument name that takes up remainder - ``keys``: list of names that can be either positional or keyword arguments - ``optkey``: optional argument name that takes up excess keyword arguments If ``varkey`` specified, all ``keys`` must be given as keyword arguments. Invalid keywords, too few positional arguments, or too many positional arguments are rejected, but missing keyword arguments are just omitted. c3s(|]\}}|r|dkr|VqdSrNr)r0ix keyvaluenoderr s&z buildargsdict..s6%(func)s takes at least %(nargs)d positional arguments)funcsnargss5%(func)s takes at most %(nargs)d positional argumentsNrrs %(func)s got an invalid argumentrLs5%(func)s got an unexpected keyword argument '%(key)s')rLskeys;%(func)s got multiple values for keyword argument '%(key)s'r) r enumerater=rrrrsortdictzip)treesfuncnameargspecrJkeynodeposkeysvarkeykeysr?kwstartargskrHdrrIr buildargsdictsf        r[c Cs:zt|WSty}z tt|d}~wwr )r unescapestr ValueErrorrr forcebytestrlower)serrrr\s  r\cCst|ts||t|fdS|d|vr3ttj|dd}||d|dd|ffdS||d|df|ddD] }t|||d|qD|dd|dddfg|dd<dS)Nrrs(%s %s) s(%s))r2r3appendrpprintmapjoin _prettyformat)r4 leafnodeslevellinesrsr`rrrris  $*ricCs*g}t||d|ddd|D}|S)Nr css |] \}}d||VqdS)s Nr)r0lr`rrrrKszprettyformat..)rirh)r4rjrloutputrrr prettyformatsrqcst|ts|S|d}|vr!|ftfdd|ddDSg}|}|d|krC|dd\}}|t||}|d|ks+|t|||tt|S)a_Flatten chained infix operations to reduce usage of Python stack >>> from . import pycompat >>> def f(tree): ... s = prettyformat(simplifyinfixops(tree, (b'or',)), (b'symbol',)) ... print(pycompat.sysstr(s)) >>> f((b'or', ... (b'or', ... (b'symbol', b'1'), ... (b'symbol', b'2')), ... (b'symbol', b'3'))) (or (symbol '1') (symbol '2') (symbol '3')) >>> f((b'func', ... (b'symbol', b'p1'), ... (b'or', ... (b'or', ... (b'func', ... (b'symbol', b'sort'), ... (b'list', ... (b'or', ... (b'or', ... (b'symbol', b'1'), ... (b'symbol', b'2')), ... (b'symbol', b'3')), ... (b'negate', ... (b'symbol', b'rev')))), ... (b'and', ... (b'symbol', b'4'), ... (b'group', ... (b'or', ... (b'or', ... (b'symbol', b'5'), ... (b'symbol', b'6')), ... (b'symbol', b'7'))))), ... (b'symbol', b'8')))) (func (symbol 'p1') (or (func (symbol 'sort') (list (or (symbol '1') (symbol '2') (symbol '3')) (negate (symbol 'rev')))) (and (symbol '4') (group (or (symbol '5') (symbol '6') (symbol '7')))) (symbol '8'))) rc3s|]}t|VqdSr )simplifyinfixopsr0rH targetnodesrrrK5sz#simplifyinfixops..rN)r2r3rerrreversed)r4ruop simplifiedrHrorrrtrrrs <$    rrcs6|krSt|ts|Stfdd|DS)Nc3s|] }t|VqdSr ) _buildtreers placeholder replstackrrrKJz_buildtree..)popr2r3)templater|r}rr{rrzEs  rzcGs>t|ts tdtt|}t|||}|rtd|S)aCreate new tree by substituting placeholders by replacements >>> _ = (b'symbol', b'_') >>> def f(template, *repls): ... return buildtree(template, _, *repls) >>> f((b'func', (b'symbol', b'only'), (b'list', _, _)), ... ('symbol', '1'), ('symbol', '2')) ('func', ('symbol', 'only'), ('list', ('symbol', '1'), ('symbol', '2'))) >>> f((b'and', _, (b'not', _)), (b'symbol', b'1'), (b'symbol', b'2')) ('and', ('symbol', '1'), ('not', ('symbol', '2'))) placeholder must be a node tuplestoo many replacements)r2r3rr<listrvrz)rr|replsr}ryrrr buildtreeMs    rcsz||krdSt|trt|tsdS|kr#|dvr#|dSt|t|kr-dStfddt||DS)NTFrc3s$|] \}}t||VqdSr ) _matchtree)r0prHincompletenodesmatchesr|rrrKls  z_matchtree..)r2r3rer=allrOpatternr4r|rrrrrrbs rNrcCs:|durt|tstd|g}t|||||r|SdS)a If a tree matches the pattern, return a list of the tree and nodes matched with the placeholder; Otherwise None >>> def f(pattern, tree): ... m = matchtree(pattern, tree, _, {b'keyvalue', b'list'}) ... if m: ... return m[1:] >>> _ = (b'symbol', b'_') >>> f((b'func', (b'symbol', b'ancestors'), _), ... (b'func', (b'symbol', b'ancestors'), (b'symbol', b'1'))) [('symbol', '1')] >>> f((b'func', (b'symbol', b'ancestors'), _), ... (b'func', (b'symbol', b'ancestors'), None)) >>> f((b'range', (b'dagrange', _, _), _), ... (b'range', ... (b'dagrange', (b'symbol', b'1'), (b'symbol', b'2')), ... (b'symbol', b'3'))) [('symbol', '1'), ('symbol', '2'), ('symbol', '3')] The placeholder does not match the specified incomplete nodes because an incomplete node (e.g. argument list) cannot construct an expression. >>> f((b'func', (b'symbol', b'ancestors'), _), ... (b'func', (b'symbol', b'ancestors'), ... (b'list', (b'symbol', b'1'), (b'symbol', b'2')))) The placeholder may be omitted, but which shouldn't match a None node. >>> _ = None >>> f((b'func', (b'symbol', b'ancestors'), None), ... (b'func', (b'symbol', b'ancestors'), (b'symbol', b'0'))) Nr)r2r3rr<rrrrr matchtreers " rcCs$|jdurtd|j|jfS|jS)z6Compose error message from specified ParseError objectNs at %d: %s)locationrmessage)instrrrparseerrordetails rc@seZdZdZddZdS)aliaszParsed result of aliascCs"||_||_||_||_d|_dS)NF)namerXr replacementwarned)rrrXerrrrrrrs  zalias.__init__N)r6r7r8__doc__rrrrrrs rc@seZdZdZdZdZddZeddZedd Z e d d Z e d d Z e ddZ e ddZe ddZe ddZe ddZe ddZe ddZdS)basealiasrulesawParsing 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 function-call styles:: # decl = defn h = heads(default) b($1) = ancestors($1) - ancestors(default) NssymbolcCstd|j)Ns'%s' is not instantiatable) TypeErrorr6clsrrr__new__szbasealiasrules.__new__cCt)z-Parse an alias name, arguments and definitionNotImplementedError)r>rrrr zbasealiasrules._parsecCr)z9Return (name, args) if tree is a function; otherwise Noner)r4rrr _trygetfuncrzbasealiasrules._trygetfuncc sz|}Wntjy!}z |dt|fWYd}~Sd}~ww|djkr@|d}|dr;|dtd|fS|ddfS|}|r|\}}|drY|dtd|fStfdd|Drk|dtd fSt |t t |kr||dtd fS|d d |DdfS|dtd fS)a Parse an alias declaration into ``(name, args, errorstr)`` This function analyzes the parsed tree. The parsing rule is provided by ``_parse()``. - ``name``: of declared alias (may be ``decl`` itself at error) - ``args``: list of argument names (or None for symbol declaration) - ``errorstr``: detail about detected error (or None) >>> sym = lambda x: (b'symbol', x) >>> symlist = lambda *xs: (b'list',) + tuple(sym(x) for x in xs) >>> func = lambda n, a: (b'func', sym(n), a) >>> parsemap = { ... b'foo': sym(b'foo'), ... b'$foo': sym(b'$foo'), ... b'foo::bar': (b'dagrange', sym(b'foo'), sym(b'bar')), ... b'foo()': func(b'foo', None), ... b'$foo()': func(b'$foo', None), ... b'foo($1, $2)': func(b'foo', symlist(b'$1', b'$2')), ... b'foo(bar_bar, baz.baz)': ... func(b'foo', symlist(b'bar_bar', b'baz.baz')), ... b'foo(bar($1, $2))': ... func(b'foo', func(b'bar', symlist(b'$1', b'$2'))), ... b'foo($1, $2, nested($1, $2))': ... func(b'foo', (symlist(b'$1', b'$2') + ... (func(b'nested', symlist(b'$1', b'$2')),))), ... b'foo("bar")': func(b'foo', (b'string', b'bar')), ... b'foo($1, $2': error.ParseError(b'unexpected token: end', 10), ... b'foo("bar': error.ParseError(b'unterminated string', 5), ... b'foo($1, $2, $1)': func(b'foo', symlist(b'$1', b'$2', b'$1')), ... } >>> def parse(expr): ... x = parsemap[expr] ... if isinstance(x, Exception): ... raise x ... return x >>> def trygetfunc(tree): ... if not tree or tree[0] != b'func' or tree[1][0] != b'symbol': ... return None ... if not tree[2]: ... return tree[1][1], [] ... if tree[2][0] == b'list': ... return tree[1][1], list(tree[2][1:]) ... return tree[1][1], [tree[2]] >>> class aliasrules(basealiasrules): ... _parse = staticmethod(parse) ... _trygetfunc = staticmethod(trygetfunc) >>> builddecl = aliasrules._builddecl >>> builddecl(b'foo') ('foo', None, None) >>> builddecl(b'$foo') ('$foo', None, "invalid symbol '$foo'") >>> builddecl(b'foo::bar') ('foo::bar', None, 'invalid format') >>> builddecl(b'foo()') ('foo', [], None) >>> builddecl(b'$foo()') ('$foo()', None, "invalid function '$foo'") >>> builddecl(b'foo($1, $2)') ('foo', ['$1', '$2'], None) >>> builddecl(b'foo(bar_bar, baz.baz)') ('foo', ['bar_bar', 'baz.baz'], None) >>> builddecl(b'foo($1, $2, nested($1, $2))') ('foo($1, $2, nested($1, $2))', None, 'invalid argument list') >>> builddecl(b'foo(bar($1, $2))') ('foo(bar($1, $2))', None, 'invalid argument list') >>> builddecl(b'foo("bar")') ('foo("bar")', None, 'invalid argument list') >>> builddecl(b'foo($1, $2') ('foo($1, $2', None, 'at 10: unexpected token: end') >>> builddecl(b'foo("bar') ('foo("bar', None, 'at 5: unterminated string') >>> builddecl(b'foo($1, $2, $1)') ('foo', None, 'argument names collide with each other') Nrr$invalid symbol '%s'sinvalid function '%s'c3s|] }|djkVqdSrF) _symbolnoder/rrrrK/sz,basealiasrules._builddecl..sinvalid argument lists&argument names collide with each othercSsg|]}|dqS)rrr/rrrr17sz-basealiasrules._builddecl..sinvalid format) r rrrr startswithrrrr=set)rdeclr4rrfuncrXrrr _builddecls2M    zbasealiasrules._builddeclcst|ts|S|d}|jkr#|ftfdd|ddDSt|dks+J|d}|vr9d}||fS|drGttd |||fS) z%Mark alias arguments as ``_aliasarg``rc3|] }|VqdSr ) _relabelargsrsrXrrrrKBr~z.basealiasrules._relabelargs..rNr _aliasargrr)r2r3rr=rrrr)rr4rXrwsymrrrr;s  & zbasealiasrules._relabelargscCs*||}|r t|}nt}|||S)aParse an alias definition into a tree and marks substitutions This function marks alias argument references as ``_aliasarg``. The parsing rule is provided by ``_parse()``. ``args`` is a list of alias argument names, or None if the alias is declared as a symbol. >>> from . import pycompat >>> parsemap = { ... b'$1 or foo': (b'or', (b'symbol', b'$1'), (b'symbol', b'foo')), ... b'$1 or $bar': ... (b'or', (b'symbol', b'$1'), (b'symbol', b'$bar')), ... b'$10 or baz': ... (b'or', (b'symbol', b'$10'), (b'symbol', b'baz')), ... b'"$1" or "foo"': ... (b'or', (b'string', b'$1'), (b'string', b'foo')), ... } >>> class aliasrules(basealiasrules): ... _parse = staticmethod(parsemap.__getitem__) ... _trygetfunc = staticmethod(lambda x: None) >>> builddefn = aliasrules._builddefn >>> def pprint(tree): ... s = prettyformat(tree, (b'_aliasarg', b'string', b'symbol')) ... print(pycompat.sysstr(s)) >>> args = [b'$1', b'$2', b'foo'] >>> pprint(builddefn(b'$1 or foo', args)) (or (_aliasarg '$1') (_aliasarg 'foo')) >>> try: ... builddefn(b'$1 or $bar', args) ... except error.ParseError as inst: ... print(pycompat.sysstr(parseerrordetail(inst))) invalid symbol '$bar' >>> args = [b'$1', b'$10', b'foo'] >>> pprint(builddefn(b'$10 or baz', args)) (or (_aliasarg '$10') (symbol 'baz')) >>> pprint(builddefn(b'"$1" or "foo"', args)) (or (string '$1') (string 'foo')) )r rr)rdefnrXr4rrr _builddefnLs /  zbasealiasrules._builddefnc Csd}}||\}}}|rtd}n$z|||}Wntjy6}zt|}td}WYd}~nd}~ww|rB||j||d}t||||S)z>Parse an alias declaration and definition into an alias objectNs4bad declaration of %(section)s "%(name)s": %(error)ss3bad definition of %(section)s "%(name)s": %(error)s)sectionnameserror)rrrrrr_sectionr) rrrreplefmtrrXrrrrrbuilds$ zbasealiasrules.buildcCs,i}|D]\}}|||}|||j<q|S)zTParse a list of alias (name, replacement) pairs into a dict of alias objects)rr)ritemsaliasesrrarrrbuildmaps    zbasealiasrules.buildmapcCs~t|tsdS|d|jkr"|d}||}|r"|jdur"|dfS||}|r=|\}}||}|r=|jdur=||fSdS)zrIf tree looks like an unexpanded alias, return (alias, pattern-args) pair. Return None otherwise. Nrr)r2r3rgetrXr)rrr4rrrrXrrr _getaliass    zbasealiasrules._getaliascsBt|ts|S|ddkr|d}|Stfdd|DS)zoReplace _aliasarg instances with the substitution value of the same name in args, recursively. rrrc3rr ) _expandargsr/rrrrKr~z-basealiasrules._expandargs..)r2r3)rr4rXrrrrrs  zbasealiasrules._expandargsc st|ts|S|}|durtfdd|DS|\}}|jr,t|j|vr>ttdj|jd ||jvrT |j |j<|j} |j durd|St|t|j krxttdt|fdd|D}|tt|j |S)Nc3s |] }|VqdSr _expandr/rcacher expandingrrrKs z)basealiasrules._expand..s5infinite expansion of %(section)s "%(name)s" detected)rrsinvalid number of arguments: %dcsg|] }|gqSrrr/)rrrrrr1sz*basealiasrules._expand..)r2r3rrAbortrrrrrerrrrXr=rdictrO) rrr4rrryrroresultrrrrs>         zbasealiasrules._expandcCs|||giS)zExpand aliases in tree, recursively. 'aliases' is a dictionary mapping user defined aliases to alias objects. r)rrr4rrrexpandszbasealiasrules.expand)r6r7r8rrrr staticmethodr r classmethodrrrrrrrrrrrrrrs6    j  5     "r)Nr) __future__rri18nrrrutilsrobjectr rEr[r\rirqrrrzrrrrrrrrrrs$  P"F  P )