[RFC] revision sets

Bill Barry after.fallout at gmail.com
Tue Apr 20 09:39:01 CDT 2010


Matt Mackall wrote:
> You must be new here. There's nothing we care about being
> backward-compatible with. Mercurial is not a library and explicitly has
> no stable API. We only care about Mercurial's internal API being
> friendly for Mercurial's future development. If you decide to link to
> Mercurial internals, then you have to expect things to break on a
> regular basis because we're not going to stop improving the core any
> time soon.
>
> There are three kinds of backward compatibility in the world:
>
> - the kind offered by Mercurial's command line API where you should
> expect things to work forever or get lots of advanced notice that
> they'll be breaking
>   
This was exactly what I was talking about. Keeping this without any 
required extra effort is a good thing (for one example it has less 
opportunity to introduce bugs). I don't care about the backward 
compatibility inside the codebase, just at the CLI level.
>>  step 4: eval this statement
>>     
>
> eval is banned from use in hg. And regex parsing is insufficient to
> properly handle the quoting and nesting requirements here.
>   
It doesn't have to be eval, that was just the easy way out. you could 
almost as easily push the method calls onto a stack and use getattr instead.

without regexes (though I think they could have been used just as easily 
as the simple tokenizer below) or eval, still not a formal grammer of 
any kind (again the usual warnings about untested code and the fact that 
python isn't a language I feel strong with):

class revfinder(object):
    unquoteddelims = "()\t\n \"'"
    def __init__(self, repo, query):
        self.repo=repo
       
        """goal:
        turn:
            descendant(parent2(1.0)) and ancestor(2.0)
            and author(george) and sorted('date') and reversed()
        into:
            [reversed, [sorted, [andf, [andf, [descendant, parent2, "1.0"],
            ancestor, "2.0"], author, "george"], "date"]]
        """
        charstack = []
        delimiters = unquoteddelims
        tokens = []
        for char in query:
            if delimiters.find(char) != -1:
                charstack.append(char)
            else
                token = chartoken = ''.join(charstack)
                if chartoken:
                    charstack = []
                    if token=='and' or token=='or':
                        token = token+'f'
                    if delimiters == unquoteddelims:
                        try:
                            token = getattr(self, token)
                        except AttributeError:
                            pass
                    if isinstance(string, tokens[-1]):
                        tokens[-1] = ' '.join([tokens[-1], chartoken])
                    else:
                        # could use tags on the functions to determine 
which case here
                        # doing so would allow plugins to extend 
(examples: xor, except, ...)
                        if chartoken=='and' or chartoken=='or':
                            # infix operation
                            tokens = [token].append(tokens)
                        elif chartoken=='sorted' or chartoken=='reversed':
                            # whole-list nonfiltering operations
                            tokens = [token, tokens[1]]
                        else:
                            # other
                            tokens.append(token)
                if char=='"':
                    if token[-1]=="\\":
                        charstack = [chartoken, char]
                    elif delimiters = char:
                        delimiters = unquoteddelims
                    else:
                        delimiters = char
                elif char=="'":
                    if delimiters = char:
                        delimiters = unquoteddelims
                    else:
                        delimiters=char
        self.statement = tokens

    def evalstmt(self):
        tokens = self.statement
        return self.run(tokens[0], tokens[1:])
       
    def run(self, func, args):
        if isinstance(list, args[-1]):
            args[-1] = self.run(args[-1][0], args[-1][1:])
        if len(args) > 2:
            if isinstance(list, args[1]):
                args[1] = self.run(args[1][0], args[1][1:])
        while len(args) >= 2 and callable(args[-2]):
            # heres hoping lists and strings are not callable
            args[-2:-1] = args[-2](args[-1])
        return func(*args)
        # does self need to be a parameter here somewhere
        # or is it implicitly included because of the getattr done?


    def andf(self, set1, set2):
        pass #not interested in writing these right now
    def orf(self, set1, set2):
        pass
    def reversed(self, changes):
        pass
    def sorted(self, changes, key):
        pass
    ...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20100420/af1fa8fb/attachment.htm>


More information about the Mercurial-devel mailing list