Parsing: functional inheritance for class methods in Python

116 views Asked by At

For some context I am trying to write a parser for a search language. At the moment I have a bunch of class methods for accepting a token given that it satisfies a certain criterion, however it seems that their general structure/format can be encapsulated with the (newly written) method _accept_generic.

class Parser(object):
    ...
    def now(self):
        # now = self._tokens[self._pos] if not self.end() else None
        # print(now, self._pos)
        return self._tokens[self._pos] if not self.end() else None

    def end(self):
        return self._pos == self._length
    
    def step(self):
        self._pos += 1

    def _accept_generic(self, criterion):
        if not self.end():
            if criterion:
                self.step()
                return True
        return False
    
    def _accept(self, char):
        return self._accept_generic(self.now() == char)
        # if not self.end():
        #     if self.now() == char:
        #         self.step()
        #         return True
        # return False
        
    def _accept_re(self, regex):
        return self._accept_generic(regex.match(self.now()))
        # if not self.end():
        #     if regex.match(self.now()):
        #         self.step()
        #         return True
        # return False
    
    def _accept_any_res(self, *regexes):
        return self._accept_generic(any([r.match(self.now()) for r in regexes]))
        # if any([r.match(self.now()) for r in regexes]):
        #     self.step()
        #     return True
        # return False

    def _accept_all_res(self, *regexes):
        return self._accept_generic(all([r.match(self.now()) for r in regexes]))
        # if all([r.match(self.now()) for r in regexes]):
        #     self.step()
        #     return True
        # return False

The problem with the current code is that it will throw errors (since the criterion is being evaluated in the function argument rather than within the if statement if not self.end()). Is there any way using e.g. functools to allow the functions to inherit the generic's structure, with the ability to specify new arguments in the child functions' code, and not have to write the same code blocks repeatedly? functools.partialmethods doesn't really do what I'm looking for.

1

There are 1 answers

4
Wups On BEST ANSWER

You can make the criterion a function and pass it to _accept_generic:

def _accept(self, char):
        return self._accept_generic(lambda c=char: self.now() == c)

Then call in _accept_generic:

def _accept_generic(self, criterion):
        if not self.end():
            if criterion():
                self.step()
                return True
        return False