mercurial/parser.py
author Pierre-Yves David <pierre-yves.david@octobus.net>
Fri, 01 Oct 2021 02:01:12 +0200
changeset 48141 42ab0bcb6ded
parent 48011 8655a77dce94
child 48875 6000f5b25c9b
permissions -rw-r--r--
dirstate: narrow gathering of parent data The parent data are only going to be useful is the file might be clean. And it might only be clean if it is tracked in both p1 and the working copy. Differential Revision: https://phab.mercurial-scm.org/D11584
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
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
    19
from __future__ import absolute_import, print_function
25963
7448df709b2e parser: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25818
diff changeset
    20
7448df709b2e parser: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25818
diff changeset
    21
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
    22
from . import (
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    23
    error,
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    24
    util,
afb335353d28 util: wrap s.decode('string_escape') calls for future py3 compatibility
Yuya Nishihara <yuya@tcha.org>
parents: 31353
diff changeset
    25
)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    26
from .utils import stringutil
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    27
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    28
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
class parser(object):
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
    30
    def __init__(self, elements, methods=None):
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
        self._elements = elements
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
        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
    33
        self.current = None
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    34
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
    def _advance(self):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    36
        """advance the tokenizer"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
        t = self.current
25171
d647f97f88dd parsers: use 'next' instead of try/except
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20778
diff changeset
    38
        self.current = next(self._iter, None)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
        return t
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    40
25804
f0a77cb6316a parser: extract function that tests if next token may start new term
Yuya Nishihara <yuya@tcha.org>
parents: 25803
diff changeset
    41
    def _hasnewterm(self):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    42
        """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
    43
        return any(self._elements[self.current[0]][1:3])
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    44
25802
cc741c76b26a parser: remove unused parameter 'pos' from _match()
Yuya Nishihara <yuya@tcha.org>
parents: 25801
diff changeset
    45
    def _match(self, m):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    46
        """make sure the tokenizer matches an end condition"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
        if self.current[0] != m:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    48
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    49
                _(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
    50
            )
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
        self._advance()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    52
25803
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    53
    def _parseoperand(self, bind, m=None):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    54
        """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
    55
        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
    56
        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
    57
            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
    58
        else:
b3004d273874 parser: factor out function that parses right-hand side of prefix/infix ops
Yuya Nishihara <yuya@tcha.org>
parents: 25802
diff changeset
    59
            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
    60
        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
    61
            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
    62
        return expr
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    63
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
    def _parse(self, bind=0):
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    65
        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
    66
        # 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
    67
        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
    68
        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
    69
            expr = (primary, value)
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    70
        elif prefix:
e71e5629e006 parser: separate actions for primary expression and prefix operator
Yuya Nishihara <yuya@tcha.org>
parents: 25804
diff changeset
    71
            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
    72
        else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    73
            raise error.ParseError(_(b"not a prefix: %s") % token, pos)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
        # gather tokens until we meet a lower binding strength
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
        while bind < self._elements[self.current[0]][0]:
11289
4215ce511134 revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents: 11278
diff changeset
    76
            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
    77
            # 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
    78
            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
    79
            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
    80
                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
    81
            elif infix:
42ac9d1d1572 parser: reorder infix/suffix handling to be similar to prefix/primary flow
Yuya Nishihara <yuya@tcha.org>
parents: 25816
diff changeset
    82
                expr = (infix[0], expr, self._parseoperand(*infix[1:]))
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
            else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    84
                raise error.ParseError(_(b"not an infix: %s") % token, pos)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    85
        return expr
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    86
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
    87
    def parse(self, tokeniter):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    88
        """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
    89
        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
    90
        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
    91
        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
    92
        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
    93
        return res, pos
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
    94
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
    def eval(self, tree):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
    96
        """recursively evaluate a parse tree using node methods"""
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
        if not isinstance(tree, tuple):
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
            return tree
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    99
        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
   100
25654
af329a84310c parser: accept iterator of tokens instead of tokenizer function and program
Yuya Nishihara <yuya@tcha.org>
parents: 25306
diff changeset
   101
    def __call__(self, tokeniter):
43787
be8552f25cab cleanup: fix docstring formatting
Matt Harbison <matt_harbison@yahoo.com>
parents: 43117
diff changeset
   102
        """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
   103
        t = self.parse(tokeniter)
11274
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104
        if self._methods:
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
            return self.eval(t)
77272d28b53f revset: introduce basic parser
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   106
        return t
25253
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   107
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   108
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   109
def splitargspec(spec):
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   110
    """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
   111
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   112
    >>> splitargspec(b'')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   113
    ([], None, [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   114
    >>> splitargspec(b'foo bar')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   115
    ([], 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
   116
    >>> 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
   117
    (['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
   118
    >>> splitargspec(b'*foo')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   119
    ([], 'foo', [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   120
    >>> splitargspec(b'**foo')
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   121
    ([], None, [], 'foo')
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   122
    """
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   123
    optkey = None
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   124
    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
   125
    if sep:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   126
        posts = post.split()
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   127
        if not posts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   128
            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
   129
        if len(posts) > 1:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   130
            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
   131
        optkey = posts[0]
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   132
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   133
    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
   134
    pres = pre.split()
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   135
    posts = post.split()
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   136
    if sep:
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   137
        if not posts:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   138
            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
   139
        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
   140
    return [], None, pres, optkey
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   141
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   142
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   143
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
   144
    """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
   145
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   146
    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
   147
    where
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   148
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   149
    - ``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
   150
    - ``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
   151
    - ``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
   152
    - ``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
   153
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   154
    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
   155
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   156
    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
   157
    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
   158
    """
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   159
    poskeys, varkey, keys, optkey = argspec
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   160
    kwstart = next(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   161
        (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
   162
        len(trees),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   163
    )
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   164
    if kwstart < len(poskeys):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   165
        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
   166
            _(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
   167
            % {b'func': funcname, b'nargs': len(poskeys)}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   168
        )
31920
a98540ea1e42 parser: verify excessive number of args excluding kwargs in buildargsdict()
Yuya Nishihara <yuya@tcha.org>
parents: 31484
diff changeset
   169
    if not varkey and kwstart > len(poskeys) + len(keys):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   170
        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
   171
            _(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
   172
            % {b'func': funcname, b'nargs': len(poskeys) + len(keys)}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   173
        )
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   174
    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
   175
    # consume positional arguments
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   176
    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
   177
        args[k] = x
30753
c3a3896a9fa8 parser: extend buildargsdict() to support variable-length positional args
Yuya Nishihara <yuya@tcha.org>
parents: 30752
diff changeset
   178
    if varkey:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   179
        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
   180
    else:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   181
        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
   182
            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
   183
    # 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
   184
    if optkey:
31922
0f41f1e3c75c parser: preserve order of keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 31921
diff changeset
   185
        args[optkey] = util.sortdict()
30752
ffd324eaf994 parser: make buildargsdict() precompute position where keyword args start
Yuya Nishihara <yuya@tcha.org>
parents: 30332
diff changeset
   186
    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
   187
        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
   188
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   189
                _(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
   190
            )
25705
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   191
        k = x[1][1]
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   192
        if k in keys:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   193
            d = args
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   194
        elif not optkey:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   195
            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
   196
                _(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
   197
                % {b'func': funcname, b'key': k}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   198
            )
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   199
        else:
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   200
            d = args[optkey]
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   201
        if k in d:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   202
            raise error.ParseError(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   203
                _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   204
                    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
   205
                    b"argument '%(key)s'"
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   206
                )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   207
                % {b'func': funcname, b'key': k}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   208
            )
31921
2156934b7917 parser: extend buildargsdict() to support arbitrary number of **kwargs
Yuya Nishihara <yuya@tcha.org>
parents: 31920
diff changeset
   209
        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
   210
    return args
48919d246a47 revset: add function to build dict of positional and keyword arguments
Yuya Nishihara <yuya@tcha.org>
parents: 25655
diff changeset
   211
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   212
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   213
def unescapestr(s):
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   214
    try:
37084
f0b6fbea00cf stringutil: bulk-replace call sites to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36547
diff changeset
   215
        return stringutil.unescapestr(s)
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   216
    except ValueError as e:
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   217
        # 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
   218
        # 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
   219
        #   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
   220
        # 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
   221
        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
   222
        # pytype: enable=attribute-error
26231
87c9c562c37a parser: move unescape helper from templater
Yuya Nishihara <yuya@tcha.org>
parents: 25963
diff changeset
   223
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   224
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   225
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
   226
    if not isinstance(tree, tuple):
39050
0a2ce5b43574 parser: replace bespoke _brepr with stringutil.pprint
Augie Fackler <augie@google.com>
parents: 37084
diff changeset
   227
        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
   228
    elif tree[0] in leafnodes:
39050
0a2ce5b43574 parser: replace bespoke _brepr with stringutil.pprint
Augie Fackler <augie@google.com>
parents: 37084
diff changeset
   229
        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
   230
        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
   231
    else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   232
        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
   233
        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
   234
            _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
   235
        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
   236
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   237
25253
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   238
def prettyformat(tree, leafnodes):
3f1a9b44b8c2 parser: move prettyformat() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 25171
diff changeset
   239
    lines = []
25254
060bdfef2517 parser: extract closure of prettyformat() to a top-level function
Yuya Nishihara <yuya@tcha.org>
parents: 25253
diff changeset
   240
    _prettyformat(tree, leafnodes, 0, lines)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   241
    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
   242
    return output
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   243
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   244
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   245
def simplifyinfixops(tree, targetnodes):
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   246
    """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
   247
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   248
    >>> from . import pycompat
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   249
    >>> 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
   250
    ...     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
   251
    ...     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
   252
    >>> f((b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   253
    ...     (b'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   254
    ...       (b'symbol', b'1'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   255
    ...       (b'symbol', b'2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   256
    ...     (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
   257
    (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   258
      (symbol '1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   259
      (symbol '2')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   260
      (symbol '3'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   261
    >>> f((b'func',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   262
    ...     (b'symbol', b'p1'),
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'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   265
    ...         (b'func',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   266
    ...           (b'symbol', b'sort'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   267
    ...           (b'list',
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'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   270
    ...                 (b'symbol', b'1'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   271
    ...                 (b'symbol', b'2')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   272
    ...               (b'symbol', b'3')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   273
    ...             (b'negate',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   274
    ...               (b'symbol', b'rev')))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   275
    ...         (b'and',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   276
    ...           (b'symbol', b'4'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   277
    ...           (b'group',
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'or',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   280
    ...                 (b'symbol', b'5'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   281
    ...                 (b'symbol', b'6')),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   282
    ...               (b'symbol', b'7'))))),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   283
    ...       (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
   284
    (func
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   285
      (symbol 'p1')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   286
      (or
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   287
        (func
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   288
          (symbol 'sort')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   289
          (list
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   290
            (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   291
              (symbol '1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   292
              (symbol '2')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   293
              (symbol '3'))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   294
            (negate
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   295
              (symbol 'rev'))))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   296
        (and
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   297
          (symbol '4')
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   298
          (group
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   299
            (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   300
              (symbol '5')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   301
              (symbol '6')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   302
              (symbol '7'))))
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   303
        (symbol '8')))
25306
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   304
    """
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   305
    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
   306
        return tree
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   307
    op = tree[0]
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   308
    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
   309
        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
   310
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   311
    # 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
   312
    # 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
   313
    # 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
   314
    simplified = []
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   315
    x = tree
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   316
    while x[0] == op:
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   317
        l, r = x[1:]
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   318
        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
   319
        x = l
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   320
    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
   321
    simplified.append(op)
c87b05925054 parser: add helper to reduce nesting of chained infix operations
Yuya Nishihara <yuya@tcha.org>
parents: 25254
diff changeset
   322
    return tuple(reversed(simplified))
28720
639e0f1e8ffa parser: move parsererrordetail() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 26231
diff changeset
   323
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   324
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   325
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
   326
    if template == placeholder:
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   327
        return replstack.pop()
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   328
    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
   329
        return template
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   330
    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
   331
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   332
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   333
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
   334
    """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
   335
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   336
    >>> _ = (b'symbol', b'_')
34043
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   337
    >>> def f(template, *repls):
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   338
    ...     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
   339
    >>> 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
   340
    ...   ('symbol', '1'), ('symbol', '2'))
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   341
    ('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
   342
    >>> 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
   343
    ('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
   344
    """
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   345
    if not isinstance(placeholder, tuple):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   346
        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
   347
    replstack = list(reversed(repls))
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   348
    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
   349
    if replstack:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   350
        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
   351
    return r
90896b61fe26 parser: add helper function that constructs parsed tree from template
Yuya Nishihara <yuya@tcha.org>
parents: 31922
diff changeset
   352
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   353
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   354
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
   355
    if pattern == tree:
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   356
        return True
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   357
    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
   358
        return False
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   359
    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
   360
        matches.append(tree)
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   361
        return True
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   362
    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
   363
        return False
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   364
    return all(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   365
        _matchtree(p, x, placeholder, incompletenodes, matches)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   366
        for p, x in zip(pattern, tree)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   367
    )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   368
34045
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   369
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   370
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
   371
    """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
   372
    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
   373
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   374
    >>> 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
   375
    ...     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
   376
    ...     if m:
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   377
    ...         return m[1:]
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   378
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   379
    >>> _ = (b'symbol', b'_')
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   380
    >>> 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
   381
    ...   (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
   382
    [('symbol', '1')]
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   383
    >>> 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
   384
    ...   (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
   385
    >>> 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
   386
    ...   (b'range',
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   387
    ...     (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
   388
    ...     (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
   389
    [('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
   390
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   391
    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
   392
    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
   393
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   394
    >>> 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
   395
    ...   (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
   396
    ...     (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
   397
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   398
    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
   399
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   400
    >>> _ = None
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   401
    >>> 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
   402
    ...   (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
   403
    """
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   404
    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
   405
        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
   406
    matches = [tree]
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   407
    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
   408
        return matches
79681d8ee587 parser: add helper function to test if pattern matches parsed tree
Yuya Nishihara <yuya@tcha.org>
parents: 34043
diff changeset
   409
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   410
28720
639e0f1e8ffa parser: move parsererrordetail() function from revset module
Yuya Nishihara <yuya@tcha.org>
parents: 26231
diff changeset
   411
def parseerrordetail(inst):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45776
diff changeset
   412
    """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
   413
    if inst.location is not None:
0fc8b066928a errors: name arguments to ParseError constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 43787
diff changeset
   414
        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
   415
    else:
45776
0fc8b066928a errors: name arguments to ParseError constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 43787
diff changeset
   416
        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
   417
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   418
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   419
class alias(object):
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   420
    """Parsed result of alias"""
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   421
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   422
    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
   423
        self.name = name
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   424
        self.args = args
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   425
        self.error = err
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   426
        self.replacement = replacement
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   427
        # 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
   428
        # this avoids showing same warning multiple times at each
8d398155bfda revset: rename findaliases() to expandaliases()
Yuya Nishihara <yuya@tcha.org>
parents: 28897
diff changeset
   429
        # `expandaliases`.
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   430
        self.warned = False
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   431
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   432
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   433
class basealiasrules(object):
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   434
    """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
   435
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   436
    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
   437
    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
   438
30332
318a24b52eeb spelling: fixes of non-dictionary words
Mads Kiilerich <madski@unity3d.com>
parents: 29767
diff changeset
   439
    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
   440
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   441
        # decl = defn
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   442
        h = heads(default)
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   443
        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
   444
    """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   445
28870
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   446
    # 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
   447
    _section = None
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   448
    # tag of symbol node
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   449
    _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
   450
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   451
    def __new__(cls):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   452
        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
   453
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   454
    @staticmethod
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   455
    def _parse(spec):
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   456
        """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
   457
        raise NotImplementedError
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   458
475dad3432fd parser: add stub class that will host alias parsing and expansion
Yuya Nishihara <yuya@tcha.org>
parents: 28720
diff changeset
   459
    @staticmethod
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   460
    def _trygetfunc(tree):
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   461
        """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
   462
        raise NotImplementedError
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   463
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   464
    @classmethod
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   465
    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
   466
        """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
   467
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   468
        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
   469
        by ``_parse()``.
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   470
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   471
        - ``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
   472
        - ``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
   473
        - ``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
   474
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   475
        >>> 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
   476
        >>> 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
   477
        >>> 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
   478
        >>> parsemap = {
34131
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': sym(b'$foo'),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   481
        ...     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
   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()': func(b'$foo', None),
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   484
        ...     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
   485
        ...     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
   486
        ...         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
   487
        ...     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
   488
        ...         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
   489
        ...     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
   490
        ...         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
   491
        ...                      (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
   492
        ...     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
   493
        ...     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
   494
        ...     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
   495
        ...     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
   496
        ... }
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   497
        >>> def parse(expr):
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   498
        ...     x = parsemap[expr]
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   499
        ...     if isinstance(x, Exception):
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   500
        ...         raise x
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   501
        ...     return x
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   502
        >>> def trygetfunc(tree):
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   503
        ...     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
   504
        ...         return None
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   505
        ...     if not tree[2]:
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   506
        ...         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
   507
        ...     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
   508
        ...         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
   509
        ...     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
   510
        >>> class aliasrules(basealiasrules):
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   511
        ...     _parse = staticmethod(parse)
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   512
        ...     _trygetfunc = staticmethod(trygetfunc)
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   513
        >>> builddecl = aliasrules._builddecl
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   514
        >>> builddecl(b'foo')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   515
        ('foo', None, None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   516
        >>> builddecl(b'$foo')
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   517
        ('$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
   518
        >>> 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
   519
        ('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
   520
        >>> builddecl(b'foo()')
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   521
        ('foo', [], None)
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   522
        >>> builddecl(b'$foo()')
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   523
        ('$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
   524
        >>> 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
   525
        ('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
   526
        >>> 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
   527
        ('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
   528
        >>> 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
   529
        ('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
   530
        >>> 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
   531
        ('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
   532
        >>> 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
   533
        ('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
   534
        >>> 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
   535
        ('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
   536
        >>> 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
   537
        ('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
   538
        >>> 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
   539
        ('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
   540
        """
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   541
        try:
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   542
            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
   543
        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
   544
            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
   545
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   546
        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
   547
            # "name = ...." style
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   548
            name = tree[1]
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   549
            if name.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   550
                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
   551
            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
   552
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   553
        func = cls._trygetfunc(tree)
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   554
        if func:
28871
6d6201fc5aae parser: move alias declaration parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28870
diff changeset
   555
            # "name(arg, ....) = ...." style
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   556
            name, args = func
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   557
            if name.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   558
                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
   559
            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
   560
                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
   561
            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
   562
                return (
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   563
                    name,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   564
                    None,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   565
                    _(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
   566
                )
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   567
            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
   568
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   569
        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
   570
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   571
    @classmethod
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   572
    def _relabelargs(cls, tree, args):
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   573
        """Mark alias arguments as ``_aliasarg``"""
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   574
        if not isinstance(tree, tuple):
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   575
            return tree
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   576
        op = tree[0]
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   577
        if op != cls._symbolnode:
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   578
            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
   579
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   580
        assert len(tree) == 2
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   581
        sym = tree[1]
5f31d2248745 parser: move _relabelaliasargs() to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28871
diff changeset
   582
        if sym in args:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   583
            op = b'_aliasarg'
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   584
        elif sym.startswith(b'$'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   585
            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
   586
        return (op, sym)
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   587
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   588
    @classmethod
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   589
    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
   590
        """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
   591
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   592
        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
   593
        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
   594
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   595
        ``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
   596
        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
   597
34137
a8994d08e4a2 doctest: use print_function and convert bytes to unicode where needed
Yuya Nishihara <yuya@tcha.org>
parents: 34131
diff changeset
   598
        >>> from . import pycompat
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   599
        >>> parsemap = {
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   600
        ...     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
   601
        ...     b'$1 or $bar':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   602
        ...         (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
   603
        ...     b'$10 or baz':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   604
        ...         (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
   605
        ...     b'"$1" or "foo"':
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   606
        ...         (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
   607
        ... }
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   608
        >>> class aliasrules(basealiasrules):
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   609
        ...     _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
   610
        ...     _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
   611
        >>> builddefn = aliasrules._builddefn
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   612
        >>> 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
   613
        ...     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
   614
        ...     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
   615
        >>> 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
   616
        >>> 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
   617
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   618
          (_aliasarg '$1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   619
          (_aliasarg 'foo'))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   620
        >>> try:
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   621
        ...     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
   622
        ... 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
   623
        ...     print(pycompat.sysstr(parseerrordetail(inst)))
29058
dbed4c4f48ae parser: rephrase "'$' not for alias arguments" message
Yuya Nishihara <yuya@tcha.org>
parents: 28910
diff changeset
   624
        invalid symbol '$bar'
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   625
        >>> 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
   626
        >>> 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
   627
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   628
          (_aliasarg '$10')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   629
          (symbol 'baz'))
34131
0fa781320203 doctest: bulk-replace string literals with b'' for Python 3
Yuya Nishihara <yuya@tcha.org>
parents: 34073
diff changeset
   630
        >>> 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
   631
        (or
34073
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   632
          (string '$1')
7bbc4e113e5f parser: stabilize output of prettyformat() by using byte-safe repr()
Yuya Nishihara <yuya@tcha.org>
parents: 34045
diff changeset
   633
          (string 'foo'))
28873
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   634
        """
28875
2e9f5453ab5a parser: unify parser function of alias declaration and definition
Yuya Nishihara <yuya@tcha.org>
parents: 28873
diff changeset
   635
        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
   636
        if args:
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   637
            args = set(args)
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   638
        else:
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   639
            args = set()
2ca3b7c563f3 parser: move alias definition parser to common rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28872
diff changeset
   640
        return cls._relabelargs(tree, args)
28892
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   641
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   642
    @classmethod
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   643
    def build(cls, decl, defn):
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   644
        """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
   645
        repl = efmt = None
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   646
        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
   647
        if err:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   648
            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
   649
        else:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   650
            try:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   651
                repl = cls._builddefn(defn, args)
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   652
            except error.ParseError as inst:
0c135f37c6f8 parser: construct alias object by rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28875
diff changeset
   653
                err = parseerrordetail(inst)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   654
                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
   655
        if err:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   656
            err = efmt % {
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   657
                b'section': cls._section,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   658
                b'name': name,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   659
                b'error': err,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   660
            }
28908
7a772deffa12 parser: drop redundant comparison between alias declaration tree and pattern
Yuya Nishihara <yuya@tcha.org>
parents: 28898
diff changeset
   661
        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
   662
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   663
    @classmethod
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   664
    def buildmap(cls, items):
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   665
        """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
   666
        alias objects"""
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   667
        aliases = {}
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   668
        for decl, defn in items:
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   669
            a = cls.build(decl, defn)
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   670
            aliases[a.name] = a
ee11167fe1da parser: extract helper that creates a dict of aliases
Yuya Nishihara <yuya@tcha.org>
parents: 28892
diff changeset
   671
        return aliases
28895
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   672
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   673
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   674
    def _getalias(cls, aliases, tree):
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   675
        """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
   676
        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
   677
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   678
        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
   679
            return None
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   680
        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
   681
            name = tree[1]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   682
            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
   683
            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
   684
                return a, None
28910
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   685
        func = cls._trygetfunc(tree)
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   686
        if func:
1203159c8928 parser: factor out _trygetfunc() that extracts function name and arguments
Yuya Nishihara <yuya@tcha.org>
parents: 28909
diff changeset
   687
            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
   688
            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
   689
            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
   690
                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
   691
        return None
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   692
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   693
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   694
    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
   695
        """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
   696
        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
   697
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   698
        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
   699
            return tree
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   700
        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
   701
            sym = tree[1]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   702
            return args[sym]
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   703
        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
   704
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   705
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   706
    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
   707
        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
   708
            return tree
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   709
        r = cls._getalias(aliases, tree)
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   710
        if r is None:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   711
            return tuple(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   712
                cls._expand(aliases, t, expanding, cache) for t in tree
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   713
            )
28909
edbffdc7f6a0 parser: make _getalias() return (alias, pattern-args) pair
Yuya Nishihara <yuya@tcha.org>
parents: 28908
diff changeset
   714
        a, l = r
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   715
        if a.error:
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   716
            raise error.Abort(a.error)
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   717
        if a in expanding:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   718
            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
   719
                _(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
   720
                % {b'section': cls._section, b'name': a.name}
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   721
            )
28897
c1f254138f44 parser: add short comment how aliases are expanded in phases
Yuya Nishihara <yuya@tcha.org>
parents: 28896
diff changeset
   722
        # 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
   723
        expanding.append(a)
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   724
        if a.name not in cache:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   725
            cache[a.name] = cls._expand(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   726
                aliases, a.replacement, expanding, cache
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   727
            )
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   728
        result = cache[a.name]
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   729
        expanding.pop()
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   730
        if a.args is None:
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   731
            return result
28897
c1f254138f44 parser: add short comment how aliases are expanded in phases
Yuya Nishihara <yuya@tcha.org>
parents: 28896
diff changeset
   732
        # 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
   733
        if len(l) != len(a.args):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   734
            raise error.ParseError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   735
                _(b'invalid number of arguments: %d') % len(l)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 42232
diff changeset
   736
            )
28896
4c76a032ec7e parser: reorder alias expansion routine to return early
Yuya Nishihara <yuya@tcha.org>
parents: 28895
diff changeset
   737
        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
   738
        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
   739
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   740
    @classmethod
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   741
    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
   742
        """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
   743
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   744
        '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
   745
        """
4bf9ed7a260e parser: move functions that process alias expansion to rule-set class
Yuya Nishihara <yuya@tcha.org>
parents: 28893
diff changeset
   746
        return cls._expand(aliases, tree, [], {})