mercurial/parser.py
author Manuel Jacob <me@manueljacob.de>
Thu, 15 Sep 2022 01:48:38 +0200
changeset 49494 c96ed4029fda
parent 48946 642e31cb55f0
permissions -rw-r--r--
templates: add filter to reverse list The filter supports only lists because for lists, it’s straightforward to implement. Reversing text doesn’t seem very useful and is hard to implement. Reversing the bytes would break multi-bytes encodings. Reversing the code points would break characters consisting of multiple code points. Reversing graphemes is non-trivial without using a library not included in the standard library.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# parser.py - simple top-down operator precedence parser for mercurial
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
46819
d4ba4d51f85f contributor: change mentions of mpm to olivia
Raphaël Gomès <rgomes@octobus.net>
parents: 45942
diff changeset
     3
# Copyright 2010 Olivia Mackall <olivia@selenic.com>
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
11449
05af334bac05 parser: fix URL to effbot
Julian Cowley <julian@lava.net>
parents: 11412
diff changeset
     8
# see http://effbot.org/zone/simple-top-down-parsing.htm and
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     9
# http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    10
# for background
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
# takes a tokenizer and elements
25655
b8b73652c1c9 parser: update documentation about tokenizer and elements
Yuya Nishihara <yuya@tcha.org>
parents: 25654
diff changeset
    13
# tokenizer is an iterator that returns (type, value, pos) tuples
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    14
# elements is a mapping of types to binding strength, primary, prefix, infix
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    15
# and suffix actions
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    16
# an action is a tree node name, a tree label, and an optional match
17500
8ac8db8dc346 en-us: labeled
timeless@mozdev.org
parents: 14701
diff changeset
    17
# __call__(program) parses program into a labeled tree
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
25963
7448df709b2e parser: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25818
diff changeset
    19
7448df709b2e parser: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25818
diff changeset
    20
from .i18n import _
31484
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    21
from . import (
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    22
    error,
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    23
    util,
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    24
)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    25
from .utils import stringutil
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    26
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    27
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
    28
class parser:
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
    29
    def __init__(self, elements, methods=None):
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
        self._elements = elements
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
        self._methods = methods
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 11449
diff changeset
    32
        self.current = None
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    33
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
    def _advance(self):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    35
        """advance the tokenizer"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
        t = self.current
25171
d647f97f88dd parsers: use 'next' instead of try/except
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20778
diff changeset
    37
        self.current = next(self._iter, None)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
        return t
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    39
25804
f0a77cb6316a parser: extract function that tests if next token may start new term
Yuya Nishihara <yuya@tcha.org>
parents: 25803
diff changeset
    40
    def _hasnewterm(self):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    41
        """True if next token may start new term"""
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    42
        return any(self._elements[self.current[0]][1:3])
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    43
25802
cc741c76b26a parser: remove unused parameter 'pos' from _match()
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    44
    def _match(self, m):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    45
        """make sure the tokenizer matches an end condition"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    46
        if self.current[0] != m:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    47
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    48
                _(b"unexpected token: %s") % self.current[0], self.current[2]
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    49
            )
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
        self._advance()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    51
25803
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    52
    def _parseoperand(self, bind, m=None):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    53
        """gather right-hand-side operand until an end condition or binding
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    54
        met"""
25803
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    55
        if m and self.current[0] == m:
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    56
            expr = None
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    57
        else:
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    58
            expr = self._parse(bind)
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    59
        if m:
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    60
            self._match(m)
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    61
        return expr
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    62
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
    def _parse(self, bind=0):
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    64
        token, value, pos = self._advance()
25816
43a8a87fc175 parser: resolve ambiguity where both prefix and primary actions are defined
Yuya Nishihara <yuya@tcha.org>
parents: 25815
diff changeset
    65
        # handle prefix rules on current token, take as primary if unambiguous
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    66
        primary, prefix = self._elements[token][1:3]
25816
43a8a87fc175 parser: resolve ambiguity where both prefix and primary actions are defined
Yuya Nishihara <yuya@tcha.org>
parents: 25815
diff changeset
    67
        if primary and not (prefix and self._hasnewterm()):
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    68
            expr = (primary, value)
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    69
        elif prefix:
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    70
            expr = (prefix[0], self._parseoperand(*prefix[1:]))
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    71
        else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    72
            raise error.ParseError(_(b"not a prefix: %s") % token, pos)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
        # gather tokens until we meet a lower binding strength
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
        while bind < self._elements[self.current[0]][0]:
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    75
            token, value, pos = self._advance()
25817
42ac9d1d1572 parser: reorder infix/suffix handling to be similar to prefix/primary flow
Yuya Nishihara <yuya@tcha.org>
parents: 25816
diff changeset
    76
            # handle infix rules, take as suffix if unambiguous
25815
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    77
            infix, suffix = self._elements[token][3:]
25818
455190fb4e51 parser: take suffix action if no infix action is defined
Yuya Nishihara <yuya@tcha.org>
parents: 25817
diff changeset
    78
            if suffix and not (infix and self._hasnewterm()):
29767
e5b794063fd4 parser: remove unused binding parameter from suffix action
Yuya Nishihara <yuya@tcha.org>
parents: 29059
diff changeset
    79
                expr = (suffix, expr)
25817
42ac9d1d1572 parser: reorder infix/suffix handling to be similar to prefix/primary flow
Yuya Nishihara <yuya@tcha.org>
parents: 25816
diff changeset
    80
            elif infix:
42ac9d1d1572 parser: reorder infix/suffix handling to be similar to prefix/primary flow
Yuya Nishihara <yuya@tcha.org>
parents: 25816
diff changeset
    81
                expr = (infix[0], expr, self._parseoperand(*infix[1:]))
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
            else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    83
                raise error.ParseError(_(b"not an infix: %s") % token, pos)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
        return expr
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    85
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
    86
    def parse(self, tokeniter):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    87
        """generate a parse tree from tokens"""
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
    88
        self._iter = tokeniter
13176
895f54a79c6e templater: use the parser.py parser to extend the templater syntax
Matt Mackall <mpm@selenic.com>
parents: 11449
diff changeset
    89
        self._advance()
13665
e798e430c5e5 revset: report a parse error if a revset is not parsed completely (issue2654)
Bernhard Leiner <bleiner@gmail.com>
parents: 13176
diff changeset
    90
        res = self._parse()
e798e430c5e5 revset: report a parse error if a revset is not parsed completely (issue2654)
Bernhard Leiner <bleiner@gmail.com>
parents: 13176
diff changeset
    91
        token, value, pos = self.current
e798e430c5e5 revset: report a parse error if a revset is not parsed completely (issue2654)
Bernhard Leiner <bleiner@gmail.com>
parents: 13176
diff changeset
    92
        return res, pos
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    93
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
    def eval(self, tree):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    95
        """recursively evaluate a parse tree using node methods"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
        if not isinstance(tree, tuple):
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
            return tree
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
        return self._methods[tree[0]](*[self.eval(t) for t in tree[1:]])
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    99
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
   100
    def __call__(self, tokeniter):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
   101
        """parse tokens into a parse tree and evaluate if methods given"""
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
   102
        t = self.parse(tokeniter)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
        if self._methods:
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104
            return self.eval(t)
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
        return t
25253
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   106
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   107
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   108
def splitargspec(spec):
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   109
    """Parse spec of function arguments into (poskeys, varkey, keys, optkey)
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   110
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   111
    >>> splitargspec(b'')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   112
    ([], None, [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   113
    >>> splitargspec(b'foo bar')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   114
    ([], None, ['foo', 'bar'], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   115
    >>> splitargspec(b'foo *bar baz **qux')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   116
    (['foo'], 'bar', ['baz'], 'qux')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   117
    >>> splitargspec(b'*foo')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   118
    ([], 'foo', [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   119
    >>> splitargspec(b'**foo')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   120
    ([], None, [], 'foo')
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   121
    """
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   122
    optkey = None
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   123
    pre, sep, post = spec.partition(b'**')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   124
    if sep:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   125
        posts = post.split()
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   126
        if not posts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   127
            raise error.ProgrammingError(b'no **optkey name provided')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   128
        if len(posts) > 1:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   129
            raise error.ProgrammingError(b'excessive **optkey names provided')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   130
        optkey = posts[0]
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   131
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   132
    pre, sep, post = pre.partition(b'*')
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   133
    pres = pre.split()
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   134
    posts = post.split()
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   135
    if sep:
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   136
        if not posts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   137
            raise error.ProgrammingError(b'no *varkey name provided')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   138
        return pres, posts[0], posts[1:], optkey
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   139
    return [], None, pres, optkey
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   140
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   141
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   142
def buildargsdict(trees, funcname, argspec, keyvaluenode, keynode):
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   143
    """Build dict from list containing positional and keyword arguments
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   144
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   145
    Arguments are specified by a tuple of ``(poskeys, varkey, keys, optkey)``
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   146
    where
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   147
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   148
    - ``poskeys``: list of names of positional arguments
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   149
    - ``varkey``: optional argument name that takes up remainder
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   150
    - ``keys``: list of names that can be either positional or keyword arguments
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   151
    - ``optkey``: optional argument name that takes up excess keyword arguments
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   152
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   153
    If ``varkey`` specified, all ``keys`` must be given as keyword arguments.
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   154
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   155
    Invalid keywords, too few positional arguments, or too many positional
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   156
    arguments are rejected, but missing keyword arguments are just omitted.
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   157
    """
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   158
    poskeys, varkey, keys, optkey = argspec
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   159
    kwstart = next(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   160
        (i for i, x in enumerate(trees) if x and x[0] == keyvaluenode),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   161
        len(trees),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   162
    )
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   163
    if kwstart < len(poskeys):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   164
        raise error.ParseError(
43117
8ff1ecfadcd1 cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents: 43077
diff changeset
   165
            _(b"%(func)s takes at least %(nargs)d positional arguments")
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   166
            % {b'func': funcname, b'nargs': len(poskeys)}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   167
        )
31920
a98540ea1e42 parser: verify excessive number of args excluding kwargs in buildargsdict()
Yuya Nishihara <yuya@tcha.org>
parents: 31484
diff changeset
   168
    if not varkey and kwstart > len(poskeys) + len(keys):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   169
        raise error.ParseError(
43117
8ff1ecfadcd1 cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents: 43077
diff changeset
   170
            _(b"%(func)s takes at most %(nargs)d positional arguments")
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   171
            % {b'func': funcname, b'nargs': len(poskeys) + len(keys)}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   172
        )
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   173
    args = util.sortdict()
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   174
    # consume positional arguments
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   175
    for k, x in zip(poskeys, trees[:kwstart]):
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   176
        args[k] = x
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   177
    if varkey:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   178
        args[varkey] = trees[len(args) : kwstart]
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   179
    else:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   180
        for k, x in zip(keys, trees[len(args) : kwstart]):
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   181
            args[k] = x
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   182
    # remainder should be keyword arguments
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   183
    if optkey:
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   184
        args[optkey] = util.sortdict()
30752
ffd324eaf994 parser: make buildargsdict() precompute position where keyword args start
Yuya Nishihara <yuya@tcha.org>
parents: 30332
diff changeset
   185
    for x in trees[kwstart:]:
42232
29798c9ba5c9 parser: fix crash by parsing "()" in keyword argument position
Yuya Nishihara <yuya@tcha.org>
parents: 39050
diff changeset
   186
        if not x or x[0] != keyvaluenode or x[1][0] != keynode:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   187
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   188
                _(b"%(func)s got an invalid argument") % {b'func': funcname}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   189
            )
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   190
        k = x[1][1]
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   191
        if k in keys:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   192
            d = args
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   193
        elif not optkey:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   194
            raise error.ParseError(
43117
8ff1ecfadcd1 cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents: 43077
diff changeset
   195
                _(b"%(func)s got an unexpected keyword argument '%(key)s'")
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   196
                % {b'func': funcname, b'key': k}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   197
            )
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   198
        else:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   199
            d = args[optkey]
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   200
        if k in d:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   201
            raise error.ParseError(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   202
                _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   203
                    b"%(func)s got multiple values for keyword "
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   204
                    b"argument '%(key)s'"
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   205
                )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   206
                % {b'func': funcname, b'key': k}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   207
            )
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   208
        d[k] = x[2]
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   209
    return args
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   210
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   211
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   212
def unescapestr(s):
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   213
    try:
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36547
diff changeset
   214
        return stringutil.unescapestr(s)
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   215
    except ValueError as e:
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   216
        # mangle Python's exception into our format
48011
8655a77dce94 parser: force a `ValueError` to bytes before passing to `error.ParseError`
Matt Harbison <matt_harbison@yahoo.com>
parents: 46819
diff changeset
   217
        # TODO: remove this suppression.  For some reason, pytype 2021.09.09
8655a77dce94 parser: force a `ValueError` to bytes before passing to `error.ParseError`
Matt Harbison <matt_harbison@yahoo.com>
parents: 46819
diff changeset
   218
        #   thinks .lower() is being called on Union[ValueError, bytes].
8655a77dce94 parser: force a `ValueError` to bytes before passing to `error.ParseError`
Matt Harbison <matt_harbison@yahoo.com>
parents: 46819
diff changeset
   219
        # pytype: disable=attribute-error
8655a77dce94 parser: force a `ValueError` to bytes before passing to `error.ParseError`
Matt Harbison <matt_harbison@yahoo.com>
parents: 46819
diff changeset
   220
        raise error.ParseError(stringutil.forcebytestr(e).lower())
8655a77dce94 parser: force a `ValueError` to bytes before passing to `error.ParseError`
Matt Harbison <matt_harbison@yahoo.com>
parents: 46819
diff changeset
   221
        # pytype: enable=attribute-error
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   222
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   223
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   224
def _prettyformat(tree, leafnodes, level, lines):
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   225
    if not isinstance(tree, tuple):
39050
0a2ce5b43574 parser: replace bespoke _brepr with stringutil.pprint
Augie Fackler <augie@google.com>
parents: 37084
diff changeset
   226
        lines.append((level, stringutil.pprint(tree)))
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   227
    elif tree[0] in leafnodes:
39050
0a2ce5b43574 parser: replace bespoke _brepr with stringutil.pprint
Augie Fackler <augie@google.com>
parents: 37084
diff changeset
   228
        rs = map(stringutil.pprint, tree[1:])
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   229
        lines.append((level, b'(%s %s)' % (tree[0], b' '.join(rs))))
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   230
    else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   231
        lines.append((level, b'(%s' % tree[0]))
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   232
        for s in tree[1:]:
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   233
            _prettyformat(s, leafnodes, level + 1, lines)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   234
        lines[-1:] = [(lines[-1][0], lines[-1][1] + b')')]
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   235
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   236
25253
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   237
def prettyformat(tree, leafnodes):
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   238
    lines = []
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   239
    _prettyformat(tree, leafnodes, 0, lines)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   240
    output = b'\n'.join((b'  ' * l + s) for l, s in lines)
25253
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   241
    return output
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   242
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   243
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   244
def simplifyinfixops(tree, targetnodes):
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   245
    """Flatten chained infix operations to reduce usage of Python stack
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   246
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   247
    >>> from . import pycompat
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   248
    >>> def f(tree):
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   249
    ...     s = prettyformat(simplifyinfixops(tree, (b'or',)), (b'symbol',))
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   250
    ...     print(pycompat.sysstr(s))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   251
    >>> f((b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   252
    ...     (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   253
    ...       (b'symbol', b'1'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   254
    ...       (b'symbol', b'2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   255
    ...     (b'symbol', b'3')))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   256
    (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   257
      (symbol '1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   258
      (symbol '2')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   259
      (symbol '3'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   260
    >>> f((b'func',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   261
    ...     (b'symbol', b'p1'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   262
    ...     (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   263
    ...       (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   264
    ...         (b'func',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   265
    ...           (b'symbol', b'sort'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   266
    ...           (b'list',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   267
    ...             (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   268
    ...               (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   269
    ...                 (b'symbol', b'1'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   270
    ...                 (b'symbol', b'2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   271
    ...               (b'symbol', b'3')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   272
    ...             (b'negate',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   273
    ...               (b'symbol', b'rev')))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   274
    ...         (b'and',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   275
    ...           (b'symbol', b'4'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   276
    ...           (b'group',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   277
    ...             (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   278
    ...               (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   279
    ...                 (b'symbol', b'5'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   280
    ...                 (b'symbol', b'6')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   281
    ...               (b'symbol', b'7'))))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   282
    ...       (b'symbol', b'8'))))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   283
    (func
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   284
      (symbol 'p1')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   285
      (or
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   286
        (func
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   287
          (symbol 'sort')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   288
          (list
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   289
            (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   290
              (symbol '1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   291
              (symbol '2')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   292
              (symbol '3'))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   293
            (negate
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   294
              (symbol 'rev'))))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   295
        (and
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   296
          (symbol '4')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   297
          (group
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   298
            (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   299
              (symbol '5')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   300
              (symbol '6')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   301
              (symbol '7'))))
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   302
        (symbol '8')))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   303
    """
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   304
    if not isinstance(tree, tuple):
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   305
        return tree
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   306
    op = tree[0]
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   307
    if op not in targetnodes:
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   308
        return (op,) + tuple(simplifyinfixops(x, targetnodes) for x in tree[1:])
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   309
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   310
    # walk down left nodes taking each right node. no recursion to left nodes
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   311
    # because infix operators are left-associative, i.e. left tree is deep.
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   312
    # e.g. '1 + 2 + 3' -> (+ (+ 1 2) 3) -> (+ 1 2 3)
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   313
    simplified = []
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   314
    x = tree
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   315
    while x[0] == op:
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   316
        l, r = x[1:]
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   317
        simplified.append(simplifyinfixops(r, targetnodes))
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   318
        x = l
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   319
    simplified.append(simplifyinfixops(x, targetnodes))
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   320
    simplified.append(op)
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   321
    return tuple(reversed(simplified))
28720
639e0f1e8ffa parser: move parsererrordetail() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 26231
diff changeset
   322
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   323
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   324
def _buildtree(template, placeholder, replstack):
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   325
    if template == placeholder:
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   326
        return replstack.pop()
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   327
    if not isinstance(template, tuple):
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   328
        return template
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   329
    return tuple(_buildtree(x, placeholder, replstack) for x in template)
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   330
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   331
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   332
def buildtree(template, placeholder, *repls):
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   333
    """Create new tree by substituting placeholders by replacements
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   334
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   335
    >>> _ = (b'symbol', b'_')
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   336
    >>> def f(template, *repls):
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   337
    ...     return buildtree(template, _, *repls)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   338
    >>> f((b'func', (b'symbol', b'only'), (b'list', _, _)),
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   339
    ...   ('symbol', '1'), ('symbol', '2'))
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   340
    ('func', ('symbol', 'only'), ('list', ('symbol', '1'), ('symbol', '2')))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   341
    >>> f((b'and', _, (b'not', _)), (b'symbol', b'1'), (b'symbol', b'2'))
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   342
    ('and', ('symbol', '1'), ('not', ('symbol', '2')))
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   343
    """
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   344
    if not isinstance(placeholder, tuple):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   345
        raise error.ProgrammingError(b'placeholder must be a node tuple')
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   346
    replstack = list(reversed(repls))
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   347
    r = _buildtree(template, placeholder, replstack)
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   348
    if replstack:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   349
        raise error.ProgrammingError(b'too many replacements')
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   350
    return r
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   351
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   352
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   353
def _matchtree(pattern, tree, placeholder, incompletenodes, matches):
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   354
    if pattern == tree:
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   355
        return True
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   356
    if not isinstance(pattern, tuple) or not isinstance(tree, tuple):
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   357
        return False
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   358
    if pattern == placeholder and tree[0] not in incompletenodes:
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   359
        matches.append(tree)
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   360
        return True
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   361
    if len(pattern) != len(tree):
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   362
        return False
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   363
    return all(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   364
        _matchtree(p, x, placeholder, incompletenodes, matches)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   365
        for p, x in zip(pattern, tree)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   366
    )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   367
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   368
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   369
def matchtree(pattern, tree, placeholder=None, incompletenodes=()):
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   370
    """If a tree matches the pattern, return a list of the tree and nodes
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   371
    matched with the placeholder; Otherwise None
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   372
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   373
    >>> def f(pattern, tree):
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   374
    ...     m = matchtree(pattern, tree, _, {b'keyvalue', b'list'})
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   375
    ...     if m:
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   376
    ...         return m[1:]
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   377
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   378
    >>> _ = (b'symbol', b'_')
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   379
    >>> f((b'func', (b'symbol', b'ancestors'), _),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   380
    ...   (b'func', (b'symbol', b'ancestors'), (b'symbol', b'1')))
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   381
    [('symbol', '1')]
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   382
    >>> f((b'func', (b'symbol', b'ancestors'), _),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   383
    ...   (b'func', (b'symbol', b'ancestors'), None))
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   384
    >>> f((b'range', (b'dagrange', _, _), _),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   385
    ...   (b'range',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   386
    ...     (b'dagrange', (b'symbol', b'1'), (b'symbol', b'2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   387
    ...     (b'symbol', b'3')))
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   388
    [('symbol', '1'), ('symbol', '2'), ('symbol', '3')]
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   389
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   390
    The placeholder does not match the specified incomplete nodes because
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   391
    an incomplete node (e.g. argument list) cannot construct an expression.
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   392
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   393
    >>> f((b'func', (b'symbol', b'ancestors'), _),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   394
    ...   (b'func', (b'symbol', b'ancestors'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   395
    ...     (b'list', (b'symbol', b'1'), (b'symbol', b'2'))))
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   396
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   397
    The placeholder may be omitted, but which shouldn't match a None node.
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   398
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   399
    >>> _ = None
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   400
    >>> f((b'func', (b'symbol', b'ancestors'), None),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   401
    ...   (b'func', (b'symbol', b'ancestors'), (b'symbol', b'0')))
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   402
    """
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   403
    if placeholder is not None and not isinstance(placeholder, tuple):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   404
        raise error.ProgrammingError(b'placeholder must be a node tuple')
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   405
    matches = [tree]
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   406
    if _matchtree(pattern, tree, placeholder, incompletenodes, matches):
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   407
        return matches
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   408
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   409
28720
639e0f1e8ffa parser: move parsererrordetail() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 26231
diff changeset
   410
def parseerrordetail(inst):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45776
diff changeset
   411
    """Compose error message from specified ParseError object"""
45776
0fc8b066928a errors: name arguments to ParseError constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 43787
diff changeset
   412
    if inst.location is not None:
0fc8b066928a errors: name arguments to ParseError constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 43787
diff changeset
   413
        return _(b'at %d: %s') % (inst.location, inst.message)
28720
639e0f1e8ffa parser: move parsererrordetail() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 26231
diff changeset
   414
    else:
45776
0fc8b066928a errors: name arguments to ParseError constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 43787
diff changeset
   415
        return inst.message
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   416
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   417
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   418
class alias:
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   419
    """Parsed result of alias"""
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   420
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   421
    def __init__(self, name, args, err, replacement):
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   422
        self.name = name
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   423
        self.args = args
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   424
        self.error = err
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   425
        self.replacement = replacement
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   426
        # whether own `error` information is already shown or not.
28898
8d398155bfda revset: rename findaliases() to expandaliases()
Yuya Nishihara <yuya@tcha.org>
parents: 28897
diff changeset
   427
        # this avoids showing same warning multiple times at each
8d398155bfda revset: rename findaliases() to expandaliases()
Yuya Nishihara <yuya@tcha.org>
parents: 28897
diff changeset
   428
        # `expandaliases`.
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   429
        self.warned = False
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   430
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   431
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   432
class basealiasrules:
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   433
    """Parsing and expansion rule set of aliases
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   434
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   435
    This is a helper for fileset/revset/template aliases. A concrete rule set
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   436
    should be made by sub-classing this and implementing class/static methods.
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   437
30332
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 29767
diff changeset
   438
    It supports alias expansion of symbol and function-call styles::
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   439
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   440
        # decl = defn
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   441
        h = heads(default)
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   442
        b($1) = ancestors($1) - ancestors(default)
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   443
    """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   444
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   445
    # typically a config section, which will be included in error messages
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   446
    _section = None
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   447
    # tag of symbol node
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   448
    _symbolnode = b'symbol'
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   449
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   450
    def __new__(cls):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   451
        raise TypeError(b"'%s' is not instantiatable" % cls.__name__)
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   452
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   453
    @staticmethod
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   454
    def _parse(spec):
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   455
        """Parse an alias name, arguments and definition"""
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   456
        raise NotImplementedError
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   457
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   458
    @staticmethod
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   459
    def _trygetfunc(tree):
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   460
        """Return (name, args) if tree is a function; otherwise None"""
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   461
        raise NotImplementedError
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   462
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   463
    @classmethod
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   464
    def _builddecl(cls, decl):
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   465
        """Parse an alias declaration into ``(name, args, errorstr)``
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   466
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   467
        This function analyzes the parsed tree. The parsing rule is provided
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   468
        by ``_parse()``.
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   469
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   470
        - ``name``: of declared alias (may be ``decl`` itself at error)
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   471
        - ``args``: list of argument names (or None for symbol declaration)
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   472
        - ``errorstr``: detail about detected error (or None)
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   473
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   474
        >>> sym = lambda x: (b'symbol', x)
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   475
        >>> symlist = lambda *xs: (b'list',) + tuple(sym(x) for x in xs)
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   476
        >>> func = lambda n, a: (b'func', sym(n), a)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   477
        >>> parsemap = {
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   478
        ...     b'foo': sym(b'foo'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   479
        ...     b'$foo': sym(b'$foo'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   480
        ...     b'foo::bar': (b'dagrange', sym(b'foo'), sym(b'bar')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   481
        ...     b'foo()': func(b'foo', None),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   482
        ...     b'$foo()': func(b'$foo', None),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   483
        ...     b'foo($1, $2)': func(b'foo', symlist(b'$1', b'$2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   484
        ...     b'foo(bar_bar, baz.baz)':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   485
        ...         func(b'foo', symlist(b'bar_bar', b'baz.baz')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   486
        ...     b'foo(bar($1, $2))':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   487
        ...         func(b'foo', func(b'bar', symlist(b'$1', b'$2'))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   488
        ...     b'foo($1, $2, nested($1, $2))':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   489
        ...         func(b'foo', (symlist(b'$1', b'$2') +
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   490
        ...                      (func(b'nested', symlist(b'$1', b'$2')),))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   491
        ...     b'foo("bar")': func(b'foo', (b'string', b'bar')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   492
        ...     b'foo($1, $2': error.ParseError(b'unexpected token: end', 10),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   493
        ...     b'foo("bar': error.ParseError(b'unterminated string', 5),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   494
        ...     b'foo($1, $2, $1)': func(b'foo', symlist(b'$1', b'$2', b'$1')),
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   495
        ... }
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   496
        >>> def parse(expr):
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   497
        ...     x = parsemap[expr]
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   498
        ...     if isinstance(x, Exception):
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   499
        ...         raise x
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   500
        ...     return x
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   501
        >>> def trygetfunc(tree):
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   502
        ...     if not tree or tree[0] != b'func' or tree[1][0] != b'symbol':
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   503
        ...         return None
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   504
        ...     if not tree[2]:
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   505
        ...         return tree[1][1], []
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   506
        ...     if tree[2][0] == b'list':
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   507
        ...         return tree[1][1], list(tree[2][1:])
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   508
        ...     return tree[1][1], [tree[2]]
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   509
        >>> class aliasrules(basealiasrules):
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   510
        ...     _parse = staticmethod(parse)
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   511
        ...     _trygetfunc = staticmethod(trygetfunc)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   512
        >>> builddecl = aliasrules._builddecl
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   513
        >>> builddecl(b'foo')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   514
        ('foo', None, None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   515
        >>> builddecl(b'$foo')
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   516
        ('$foo', None, "invalid symbol '$foo'")
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   517
        >>> builddecl(b'foo::bar')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   518
        ('foo::bar', None, 'invalid format')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   519
        >>> builddecl(b'foo()')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   520
        ('foo', [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   521
        >>> builddecl(b'$foo()')
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   522
        ('$foo()', None, "invalid function '$foo'")
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   523
        >>> builddecl(b'foo($1, $2)')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   524
        ('foo', ['$1', '$2'], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   525
        >>> builddecl(b'foo(bar_bar, baz.baz)')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   526
        ('foo', ['bar_bar', 'baz.baz'], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   527
        >>> builddecl(b'foo($1, $2, nested($1, $2))')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   528
        ('foo($1, $2, nested($1, $2))', None, 'invalid argument list')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   529
        >>> builddecl(b'foo(bar($1, $2))')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   530
        ('foo(bar($1, $2))', None, 'invalid argument list')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   531
        >>> builddecl(b'foo("bar")')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   532
        ('foo("bar")', None, 'invalid argument list')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   533
        >>> builddecl(b'foo($1, $2')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   534
        ('foo($1, $2', None, 'at 10: unexpected token: end')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   535
        >>> builddecl(b'foo("bar')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   536
        ('foo("bar', None, 'at 5: unterminated string')
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   537
        >>> builddecl(b'foo($1, $2, $1)')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   538
        ('foo', None, 'argument names collide with each other')
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   539
        """
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   540
        try:
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   541
            tree = cls._parse(decl)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   542
        except error.ParseError as inst:
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   543
            return (decl, None, parseerrordetail(inst))
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   544
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   545
        if tree[0] == cls._symbolnode:
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   546
            # "name = ...." style
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   547
            name = tree[1]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   548
            if name.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   549
                return (decl, None, _(b"invalid symbol '%s'") % name)
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   550
            return (name, None, None)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   551
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   552
        func = cls._trygetfunc(tree)
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   553
        if func:
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   554
            # "name(arg, ....) = ...." style
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   555
            name, args = func
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   556
            if name.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   557
                return (decl, None, _(b"invalid function '%s'") % name)
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   558
            if any(t[0] != cls._symbolnode for t in args):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   559
                return (decl, None, _(b"invalid argument list"))
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   560
            if len(args) != len(set(args)):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   561
                return (
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   562
                    name,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   563
                    None,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   564
                    _(b"argument names collide with each other"),
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   565
                )
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   566
            return (name, [t[1] for t in args], None)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   567
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   568
        return (decl, None, _(b"invalid format"))
28872
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   569
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   570
    @classmethod
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   571
    def _relabelargs(cls, tree, args):
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   572
        """Mark alias arguments as ``_aliasarg``"""
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   573
        if not isinstance(tree, tuple):
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   574
            return tree
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   575
        op = tree[0]
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   576
        if op != cls._symbolnode:
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   577
            return (op,) + tuple(cls._relabelargs(x, args) for x in tree[1:])
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   578
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   579
        assert len(tree) == 2
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   580
        sym = tree[1]
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   581
        if sym in args:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   582
            op = b'_aliasarg'
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   583
        elif sym.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   584
            raise error.ParseError(_(b"invalid symbol '%s'") % sym)
28872
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   585
        return (op, sym)
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   586
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   587
    @classmethod
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   588
    def _builddefn(cls, defn, args):
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   589
        """Parse an alias definition into a tree and marks substitutions
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   590
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   591
        This function marks alias argument references as ``_aliasarg``. The
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   592
        parsing rule is provided by ``_parse()``.
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   593
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   594
        ``args`` is a list of alias argument names, or None if the alias
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   595
        is declared as a symbol.
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   596
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   597
        >>> from . import pycompat
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   598
        >>> parsemap = {
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   599
        ...     b'$1 or foo': (b'or', (b'symbol', b'$1'), (b'symbol', b'foo')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   600
        ...     b'$1 or $bar':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   601
        ...         (b'or', (b'symbol', b'$1'), (b'symbol', b'$bar')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   602
        ...     b'$10 or baz':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   603
        ...         (b'or', (b'symbol', b'$10'), (b'symbol', b'baz')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   604
        ...     b'"$1" or "foo"':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   605
        ...         (b'or', (b'string', b'$1'), (b'string', b'foo')),
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   606
        ... }
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   607
        >>> class aliasrules(basealiasrules):
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   608
        ...     _parse = staticmethod(parsemap.__getitem__)
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   609
        ...     _trygetfunc = staticmethod(lambda x: None)
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   610
        >>> builddefn = aliasrules._builddefn
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   611
        >>> def pprint(tree):
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   612
        ...     s = prettyformat(tree, (b'_aliasarg', b'string', b'symbol'))
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   613
        ...     print(pycompat.sysstr(s))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   614
        >>> args = [b'$1', b'$2', b'foo']
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   615
        >>> pprint(builddefn(b'$1 or foo', args))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   616
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   617
          (_aliasarg '$1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   618
          (_aliasarg 'foo'))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   619
        >>> try:
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   620
        ...     builddefn(b'$1 or $bar', args)
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   621
        ... except error.ParseError as inst:
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   622
        ...     print(pycompat.sysstr(parseerrordetail(inst)))
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   623
        invalid symbol '$bar'
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   624
        >>> args = [b'$1', b'$10', b'foo']
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   625
        >>> pprint(builddefn(b'$10 or baz', args))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   626
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   627
          (_aliasarg '$10')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   628
          (symbol 'baz'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   629
        >>> pprint(builddefn(b'"$1" or "foo"', args))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   630
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   631
          (string '$1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   632
          (string 'foo'))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   633
        """
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   634
        tree = cls._parse(defn)
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   635
        if args:
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   636
            args = set(args)
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   637
        else:
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   638
            args = set()
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   639
        return cls._relabelargs(tree, args)
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   640
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   641
    @classmethod
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   642
    def build(cls, decl, defn):
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   643
        """Parse an alias declaration and definition into an alias object"""
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   644
        repl = efmt = None
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   645
        name, args, err = cls._builddecl(decl)
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   646
        if err:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   647
            efmt = _(b'bad declaration of %(section)s "%(name)s": %(error)s')
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   648
        else:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   649
            try:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   650
                repl = cls._builddefn(defn, args)
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   651
            except error.ParseError as inst:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   652
                err = parseerrordetail(inst)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   653
                efmt = _(b'bad definition of %(section)s "%(name)s": %(error)s')
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   654
        if err:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   655
            err = efmt % {
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   656
                b'section': cls._section,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   657
                b'name': name,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   658
                b'error': err,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   659
            }
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   660
        return alias(name, args, err, repl)
28893
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   661
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   662
    @classmethod
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   663
    def buildmap(cls, items):
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   664
        """Parse a list of alias (name, replacement) pairs into a dict of
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   665
        alias objects"""
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   666
        aliases = {}
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   667
        for decl, defn in items:
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   668
            a = cls.build(decl, defn)
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   669
            aliases[a.name] = a
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   670
        return aliases
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   671
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   672
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   673
    def _getalias(cls, aliases, tree):
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   674
        """If tree looks like an unexpanded alias, return (alias, pattern-args)
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   675
        pair. Return None otherwise.
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   676
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   677
        if not isinstance(tree, tuple):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   678
            return None
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   679
        if tree[0] == cls._symbolnode:
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   680
            name = tree[1]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   681
            a = aliases.get(name)
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   682
            if a and a.args is None:
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   683
                return a, None
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   684
        func = cls._trygetfunc(tree)
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   685
        if func:
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   686
            name, args = func
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   687
            a = aliases.get(name)
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   688
            if a and a.args is not None:
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   689
                return a, args
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   690
        return None
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   691
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   692
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   693
    def _expandargs(cls, tree, args):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   694
        """Replace _aliasarg instances with the substitution value of the
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   695
        same name in args, recursively.
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   696
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   697
        if not isinstance(tree, tuple):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   698
            return tree
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   699
        if tree[0] == b'_aliasarg':
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   700
            sym = tree[1]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   701
            return args[sym]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   702
        return tuple(cls._expandargs(t, args) for t in tree)
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   703
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   704
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   705
    def _expand(cls, aliases, tree, expanding, cache):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   706
        if not isinstance(tree, tuple):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   707
            return tree
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   708
        r = cls._getalias(aliases, tree)
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   709
        if r is None:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   710
            return tuple(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   711
                cls._expand(aliases, t, expanding, cache) for t in tree
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   712
            )
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   713
        a, l = r
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   714
        if a.error:
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   715
            raise error.Abort(a.error)
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   716
        if a in expanding:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   717
            raise error.ParseError(
43117
8ff1ecfadcd1 cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents: 43077
diff changeset
   718
                _(b'infinite expansion of %(section)s "%(name)s" detected')
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   719
                % {b'section': cls._section, b'name': a.name}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   720
            )
28897
c1f254138f44 parser: add short comment how aliases are expanded in phases
Yuya Nishihara <yuya@tcha.org>
parents: 28896
diff changeset
   721
        # get cacheable replacement tree by expanding aliases recursively
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   722
        expanding.append(a)
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   723
        if a.name not in cache:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   724
            cache[a.name] = cls._expand(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   725
                aliases, a.replacement, expanding, cache
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   726
            )
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   727
        result = cache[a.name]
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   728
        expanding.pop()
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   729
        if a.args is None:
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   730
            return result
28897
c1f254138f44 parser: add short comment how aliases are expanded in phases
Yuya Nishihara <yuya@tcha.org>
parents: 28896
diff changeset
   731
        # substitute function arguments in replacement tree
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   732
        if len(l) != len(a.args):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   733
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   734
                _(b'invalid number of arguments: %d') % len(l)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   735
            )
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   736
        l = [cls._expand(aliases, t, [], cache) for t in l]
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   737
        return cls._expandargs(result, dict(zip(a.args, l)))
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   738
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   739
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   740
    def expand(cls, aliases, tree):
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   741
        """Expand aliases in tree, recursively.
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   742
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   743
        'aliases' is a dictionary mapping user defined aliases to alias objects.
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   744
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   745
        return cls._expand(aliases, tree, [], {})