Ejemplo n.º 1
0
    def operator(self, lhs, min_precedence):
        while self.tokens.accept(self._infix_of_min_precedence, min_precedence):
            operator = self.tokens.matched.operator

            if operator.prefix:
                raise ValueError("infix+prefix operators aren't supported.")

            if operator.suffix:
                rhs = self.expression()
                self.tokens.expect(grammar.match_tokens(operator.suffix))
                rhs.end = self.tokens.matched.end
            else:
                rhs = self.atom()

            next_min_precedence = operator.precedence
            if operator.assoc == "left":
                next_min_precedence += 1

            while self.tokens.match(grammar.infix, self.operators):
                if (self.tokens.matched.operator.precedence
                        < next_min_precedence):
                    break

                rhs = self.operator(rhs,
                                    self.tokens.matched.operator.precedence)

            if not rhs:
                raise errors.EfilterParseError(
                    message="Expecting the operator RHS here.",
                    token=self.tokens.peek(0))
            lhs = operator.handler(lhs, rhs, start=lhs.start, end=rhs.end,
                                   source=self.original)

        return lhs
Ejemplo n.º 2
0
    def atom(self):
        # Unary operator.
        if self.tokens.accept(grammar.prefix, self.operators):
            operator = self.tokens.matched.operator
            start = self.tokens.matched.start
            children = [self.expression(operator.precedence)]

            # Allow infix to be repeated in circumfix operators.
            if operator.infix:
                while self.tokens.accept(grammar.match_tokens(operator.infix)):
                    children.append(self.expression())

            # If we have a suffix expect it now.
            if operator.suffix:
                self.tokens.expect(grammar.match_tokens(operator.suffix))

            return operator.handler(*children,
                                    start=start,
                                    end=self.tokens.matched.end,
                                    source=self.original)

        if self.tokens.accept(grammar.literal):
            return ast.Literal(self.tokens.matched.value,
                               source=self.original,
                               start=self.tokens.matched.start,
                               end=self.tokens.matched.end)

        if self.tokens.accept(grammar.symbol):
            return ast.Var(self.tokens.matched.value,
                           source=self.original,
                           start=self.tokens.matched.start,
                           end=self.tokens.matched.end)

        if self.tokens.accept(grammar.lparen):
            expr = self.expression()
            self.tokens.expect(grammar.rparen)
            return expr

        if self.tokens.peek(0):
            raise errors.EfilterParseError(
                message="Was not expecting %r here." %
                self.tokens.peek(0).name,
                token=self.tokens.peek(0))
        else:
            raise errors.EfilterParseError("Unexpected end of input.")
Ejemplo n.º 3
0
    def operator(self, lhs, min_precedence):
        """Climb operator precedence as long as there are operators.

        This function implements a basic precedence climbing parser to deal
        with binary operators in a sane fashion. The outer loop will keep
        spinning as long as the next token is an operator with a precedence
        of at least 'min_precedence', parsing operands as atoms (which,
        in turn, recurse into 'expression' which recurses back into 'operator').

        This supports both left- and right-associativity. The only part of the
        code that's not a regular precedence-climber deals with mixfix
        operators. A mixfix operator in DottySQL consists of an infix part
        and a suffix (they are still binary, they just have a terminator).
        """

        # Spin as long as the next token is an operator of higher
        # precedence. (This may not do anything, which is fine.)
        while self.accept_operator(precedence=min_precedence):
            operator = self.tokens.matched.operator

            # If we're parsing a mixfix operator we can keep going until
            # the suffix.
            if operator.suffix:
                rhs = self.expression()
                self.tokens.expect(common_grammar.match_tokens(
                    operator.suffix))
                rhs.end = self.tokens.matched.end
            elif operator.name == ".":
                # The dot operator changes the meaning of RHS.
                rhs = self.dot_rhs()
            else:
                # The right hand side is an atom, which might turn out to be
                # an expression. Isn't recursion exciting?
                rhs = self.atom()

            # Keep going as long as the next token is an infix operator of
            # higher precedence.
            next_min_precedence = operator.precedence
            if operator.assoc == "left":
                next_min_precedence += 1

            while self.tokens.match(grammar.infix):
                if (self.tokens.matched.operator.precedence <
                        next_min_precedence):
                    break
                rhs = self.operator(rhs,
                                    self.tokens.matched.operator.precedence)

            lhs = operator.handler(lhs,
                                   rhs,
                                   start=lhs.start,
                                   end=rhs.end,
                                   source=self.original)

        return lhs
Ejemplo n.º 4
0
    def atom(self):
        # Unary operator.
        if self.tokens.accept(grammar.prefix, self.operators):
            operator = self.tokens.matched.operator
            start = self.tokens.matched.start
            children = [self.expression(operator.precedence)]

            # Allow infix to be repeated in circumfix operators.
            if operator.infix:
                while self.tokens.accept(grammar.match_tokens(operator.infix)):
                    children.append(self.expression())

            # If we have a suffix expect it now.
            if operator.suffix:
                self.tokens.expect(grammar.match_tokens(operator.suffix))

            return operator.handler(*children, start=start,
                                    end=self.tokens.matched.end,
                                    source=self.original)

        if self.tokens.accept(grammar.literal):
            return ast.Literal(self.tokens.matched.value, source=self.original,
                               start=self.tokens.matched.start,
                               end=self.tokens.matched.end)

        if self.tokens.accept(grammar.symbol):
            return ast.Var(self.tokens.matched.value, source=self.original,
                           start=self.tokens.matched.start,
                           end=self.tokens.matched.end)

        if self.tokens.accept(grammar.lparen):
            expr = self.expression()
            self.tokens.expect(grammar.rparen)
            return expr

        if self.tokens.peek(0):
            raise errors.EfilterParseError(
                message="Was not expecting %r here." % self.tokens.peek(0).name,
                token=self.tokens.peek(0))
        else:
            raise errors.EfilterParseError("Unexpected end of input.")
Ejemplo n.º 5
0
    def operator(self, lhs, min_precedence):
        """Climb operator precedence as long as there are operators.

        This function implements a basic precedence climbing parser to deal
        with binary operators in a sane fashion. The outer loop will keep
        spinning as long as the next token is an operator with a precedence
        of at least 'min_precedence', parsing operands as atoms (which,
        in turn, recurse into 'expression' which recurses back into 'operator').

        This supports both left- and right-associativity. The only part of the
        code that's not a regular precedence-climber deals with mixfix
        operators. A mixfix operator in DottySQL consists of an infix part
        and a suffix (they are still binary, they just have a terminator).
        """

        # Spin as long as the next token is an operator of higher
        # precedence. (This may not do anything, which is fine.)
        while self.accept_operator(precedence=min_precedence):
            operator = self.tokens.matched.operator

            # If we're parsing a mixfix operator we can keep going until
            # the suffix.
            if operator.suffix:
                rhs = self.expression()
                self.tokens.expect(common_grammar.match_tokens(operator.suffix))
                rhs.end = self.tokens.matched.end
            elif operator.name == ".":
                # The dot operator changes the meaning of RHS.
                rhs = self.dot_rhs()
            else:
                # The right hand side is an atom, which might turn out to be
                # an expression. Isn't recursion exciting?
                rhs = self.atom()

            # Keep going as long as the next token is an infix operator of
            # higher precedence.
            next_min_precedence = operator.precedence
            if operator.assoc == "left":
                next_min_precedence += 1

            while self.tokens.match(grammar.infix):
                if (self.tokens.matched.operator.precedence
                        < next_min_precedence):
                    break
                rhs = self.operator(rhs,
                                    self.tokens.matched.operator.precedence)

            lhs = operator.handler(lhs, rhs, start=lhs.start, end=rhs.end,
                                   source=self.original)

        return lhs
Ejemplo n.º 6
0
    def operator(self, lhs, min_precedence):
        while self.tokens.accept(self._infix_of_min_precedence,
                                 min_precedence):
            operator = self.tokens.matched.operator

            if operator.prefix:
                raise ValueError("infix+prefix operators aren't supported.")

            if operator.suffix:
                rhs = self.expression()
                self.tokens.expect(grammar.match_tokens(operator.suffix))
                rhs.end = self.tokens.matched.end
            else:
                rhs = self.atom()

            next_min_precedence = operator.precedence
            if operator.assoc == "left":
                next_min_precedence += 1

            while self.tokens.match(grammar.infix, self.operators):
                if (self.tokens.matched.operator.precedence <
                        next_min_precedence):
                    break

                rhs = self.operator(rhs,
                                    self.tokens.matched.operator.precedence)

            if not rhs:
                raise errors.EfilterParseError(
                    message="Expecting the operator RHS here.",
                    token=self.tokens.peek(0))
            lhs = operator.handler(lhs,
                                   rhs,
                                   start=lhs.start,
                                   end=rhs.end,
                                   source=self.original)

        return lhs