Resolves a claripy.ast.Base into something usable by the backend.

        :param expr:    The expression.
        :param save:    Save the result in the expression's object cache
        :return:        A backend object.

def convert(self, expr): #pylint:disable=R0201
        """
        Resolves a claripy.ast.Base into something usable by the backend.

        :param expr:    The expression.
        :param save:    Save the result in the expression's object cache
        :return:        A backend object.
        """
        ast_queue = [[expr]]
        arg_queue = []
        op_queue = []

        try:
            while ast_queue:
                args_list = ast_queue[-1]

                if args_list:
                    ast = args_list.pop(0)

                    if type(ast) in {bool, int, str, float} or not isinstance(ast, Base):
                        converted = self._convert(ast)
                        arg_queue.append(converted)
                        continue

                    if self in ast._errored:
                        raise BackendError("%s can't handle operation %s (%s) due to a failed "
                                           "conversion on a child node" % (self, ast.op, ast.__class__.__name__))

                    if self._cache_objects:
                        cached_obj = self._object_cache.get(ast._cache_key, None)
                        if cached_obj is not None:
                            arg_queue.append(cached_obj)
                            continue

                    op_queue.append(ast)
                    if ast.op in self._op_expr:
                        ast_queue.append(None)
                    else:
                        ast_queue.append(list(ast.args))

                else:
                    ast_queue.pop()

                    if op_queue:
                        ast = op_queue.pop()

                        op = self._op_expr.get(ast.op, None)
                        if op is not None:
                            r = op(ast)

                        else:
                            args = arg_queue[-len(ast.args):]
                            del arg_queue[-len(ast.args):]

                            try:
                                r = self._call(ast.op, args)
                            except BackendUnsupportedError:
                                r = self.default_op(ast)

                        for a in ast.annotations:
                            r = self.apply_annotation(r, a)

                        if self._cache_objects:
                            self._object_cache[ast._cache_key] = r

                        arg_queue.append(r)

        except (RuntimeError, ctypes.ArgumentError) as e:
            raise ClaripyRecursionError("Recursion limit reached. Sorry about that.") from e

        except BackendError:
            for ast in op_queue:
                ast._errored.add(self)
            if isinstance(expr, Base):
                expr._errored.add(self)
            raise

        # Note: Uncomment the following assertions if you are touching the above implementation
        # assert len(op_queue) == 0, "op_queue is not empty"
        # assert len(ast_queue) == 0, "ast_queue is not empty"
        # assert len(arg_queue) == 1, ("arg_queue has unexpected length", len(arg_queue))

        return arg_queue.pop()