def evaluate(self):
        ops = []
        rpn = []
        for token in self.expr:
            if isinstance(token, int):
                while len(ops) and token <= ops[-1]:
                    rpn.append(ops.pop())
                ops.append(token)
            else:
                rpn.append(token)
        while len(ops):
            rpn.append(ops.pop())
        stack = []
        for token in rpn:
            if isinstance(token, int):
                if token == OPERATOR.NOT:
                    stack[-1] = IsNot(stack[-1])
                    continue
                if len(stack) < 2:
                    raise RuntimeError('Unable to build a valid expression. Not enough operands available.')
                if token == OPERATOR.OR:
                    matcher = hc.any_of(*stack[-2:])
                else:
                    matcher = hc.all_of(*stack[-2:])
                stack[-2:] = [matcher]
            else:
                stack.append(token)
        if len(stack) != 1:
            raise RuntimeError('Unable to build a valid expression. The RPN stack should have just one item.')
        matcher = stack.pop()
        if self.description:
            matcher = hc.described_as(self.description, matcher)
        return matcher