def expose_builtin(*args, **kwargs):
    def really_expose(func):
        return make_wrapper(func, *args, **kwargs)
    return really_expose def get_printable_location(rule, sconttype):
def get_jitcell_at(where, rule):
def set_jitcell_at(newcell, where, rule):
def driver(scont, fcont, heap):
def _process_hooks(scont, fcont, heap):
    def __init__(self, load_system=False):
    def _freeze_(self):
    def add_rule(self, ruleterm, end=True):
    def make_rule(self, ruleterm, module):
    def get_builtin(self, signature):
    def _build_and_run(self, tree, source_string, file_name):
    def _term_expand(self, term):
    def runstring(self, s, file_name=None):
    def parse(self, s, file_name=None):
    def getoperations(self):
    def run_query(self, query, module, continuation=None):
    def run_query_in_current(self, query, continuation=None):
    def call(self, query, rule, scont, fcont, heap):
    def call_in_module(self, query, module, scont, fcont, heap):
    def _get_function(self, signature, module, query): 
    def switch_module(self, modulename):
    def throw(self, exc, scont, fcont, heap, rule_likely_source=None):
    def __freeze__(self):
def _make_rule_conts(engine, scont, fcont, heap, query, rulechain):
def _dot(self, seen):
    def __new__(cls, name, bases, dct):
    def __init__(self, engine, nextcont):
    def activate(self, fcont, heap):
    def is_done(self):
    def find_end_of_cut(self):
    def __init__(self, engine, nextcont, rule):
def view(*objects, **names):
    def __init__(self, engine, nextcont, orig_fcont, heap):
    def fail(self, heap):
    def cut(self, upto, heap):
    def is_done(self):
def make_failure_continuation(make_func):
        def __init__(self, engine, scont, fcont, heap, *state):
        def fail(self, heap):
    def make_func_wrapper(*args):
    def __init__(self, engine):
    def is_done(self):
    def __init__(self, engine):
    def fail(self, heap):
    def is_done(self):
    def __init__(self, engine, rule, nextcont, body):
    def activate(self, fcont, heap):
    def __repr__(self):
    def __init__(self, engine, rule, nextcont, builtin, query):
    def activate(self, fcont, heap):
    def __repr__(self):
    def __init__(self, engine, nextcont, orig_fcont, heap, query, rulechain):
    def fail(self, heap):
    def __repr__(self):
    def __init__(self, engine, nextcont, rule, query):
    def activate(self, fcont, heap):
    def __repr__(self):
    def __init__(self, engine, nextcont, fcont_after_cut):
    def insert_scope_notifier(engine, nextcont, fcont):
    def find_end_of_cut(self):
    def activate(self, fcont, heap):
    def __init__(self, engine, rule, nextcont, fcont, catcher, recover, heap):
    def activate(self, fcont, heap):
    def __repr__(self):
class Engine(object):
class MetaCont(type):
class Continuation(object):
class ContinuationWithRule(Continuation):
class FailureContinuation(object):
    class C(FailureContinuation):
class DoneSuccessContinuation(Continuation):
class DoneFailureContinuation(FailureContinuation):
class BodyContinuation(ContinuationWithRule):
class BuiltinContinuation(ContinuationWithRule):
class UserCallContinuation(FailureContinuation):
class RuleContinuation(ContinuationWithRule):
class CutScopeNotifier(Continuation):
class CatchingDelimiter(ContinuationWithRule): class AttVar(BindingVar):
    attmap = AttMap()

    def __init__(self):
        BindingVar.__init__(self)
        self.value_list = debug.make_sure_not_resized([])

    @specialize.arg(3)
    def _unify_derefed(self, other, heap, occurs_check=False):
        if isinstance(other, AttVar):
            if other is not self:
                self.setvalue(other, heap)
            return
        if isinstance(other, Var):
            return other._unify_derefed(self, heap, occurs_check)
        return self.setvalue(other, heap)

    def setvalue(self, value, heap):
        if self.value_list is not None:
            heap.add_hook(self)
        BindingVar.setvalue(self, value, heap)

    def __repr__(self):
        attrs = []
        attmap = jit.hint(self.attmap, promote=True)
        if self.value_list is not None:
            for key, index in attmap.indexes.iteritems():
                value = self.value_list[index]
                if value is not None:
                    attrs.append("%s" % (key, ))
        return "AttVar(%s, %s)" % (self.getbinding(), "[" + ", ".join(attrs) + "]")

    def copy(self, heap, memo):
        self = self.dereference(None)
        if isinstance(self, AttVar):
            res = memo.get(self)
            if res is not None:
                return res
            newvar = heap.new_attvar()
            own_list = self.value_list
            newvar.attmap = self.attmap
            if own_list is None:
                newvar.value_list = None
            else:
                length = len(own_list)
                new_values = [None] * length
                for i in range(length):
                    if own_list[i] is None:
                        new_values[i] = None
                    else:
                        new_values[i] = own_list[i].copy(heap, memo)
                newvar.value_list = new_values

            memo.set(self, newvar)
            return newvar
        return self.copy(heap, memo)

    def add_attribute(self, attname, attribute):
        attmap = jit.hint(self.attmap, promote=True)
        index = attmap.get_index(attname)
        if index != -1:
            self.value_list[index] = attribute
            return
        self.attmap = attmap.with_extra_attribute(attname)
        self.value_list = self.value_list + [attribute]

    def del_attribute(self, attname):
        attmap = jit.hint(self.attmap, promote=True)
        index = attmap.get_index(attname)
        if self.value_list is not None:
            self.value_list[index] = None

    def get_attribute(self, attname):
        if self.value_list is None:
            return None, -1
        attmap = jit.hint(self.attmap, promote=True)
        index = attmap.get_index(attname)
        if index == -1:
            return None, -1
        return self.value_list[index], index

    def reset_field(self, index, value):
        if self.value_list is None:
            self.value_list = [None] * (index + 1)
        else:
            self.value_list = self.value_list + [None] * (
                    index - len(self.value_list) + 1)
        self.value_list[index] = value

    def get_attribute_index(self, attname):
        attmap = jit.hint(self.attmap, promote=True)
        return attmap.get_index(attname)

    def is_empty(self):
        if self.value_list is None:
            return True
        for elem in self.value_list:
            if elem is not None:
                return False
        return True class Var(PrologObject):
    TYPE_STANDARD_ORDER = 0
    __slots__ = ("created_after_choice_point", )

    def __init__(self):
        self.created_after_choice_point = None
        assert type(self) is not Var, "abstract base class"

    @specialize.arg(3)
    @jit.unroll_safe
    def unify(self, other, heap, occurs_check=False):
        other = other.dereference(heap)
        next = self.getbinding()
        while isinstance(next, Var):
            self = next
            next = next.getbinding()
        if next is None:
            assert isinstance(self, Var)
            return self._unify_derefed(other, heap, occurs_check)
        else:
            self._unify_potential_recursion(next, other, heap, occurs_check)

    @specialize.arg(4)
    def _unify_potential_recursion(self, next, other, heap, occurs_check):
        assert isinstance(next, NonVar)
        if next is not other:
            next._unify_derefed(other, heap, occurs_check)

    def getbinding(self):
        raise NotImplementedError

    @specialize.arg(3)
    def _unify_derefed(self, other, heap, occurs_check=False):
        if isinstance(other, Var) and other is self:
            pass
        elif occurs_check and other.contains_var(self, heap):
            raise UnificationFailed()
        else:
            self.setvalue(other, heap)
    
    def dereference(self, heap):
        next = self.getbinding()
        if next is None:
            return self
        else:
            result = next.dereference(heap)
            if result is not next and heap is not None:
                # do path compression
                self.setvalue(result, heap)
            return result

    def copy(self, heap, memo):
        self = self.dereference(None)
        if isinstance(self, Var):
            res = memo.get(self)
            if res is not None:
                return res
            newvar = heap.newvar()
            memo.set(self, newvar)
            return newvar
        return self.copy(heap, memo)
    
    def enumerate_vars(self, memo):
        self = self.dereference(None)
        if isinstance(self, Var):
            return memo.get(self)
        return self.enumerate_vars(memo)

    def contains_var(self, var, heap):
        self = self.dereference(heap)
        if self is var:
            return True
        if not isinstance(self, Var):
            return self.contains_var(var, heap)
        return False

    def __repr__(self):
        return "Var(%s)" % (self.getbinding(), )

    def eval_arithmetic(self, engine):
        self = self.dereference(None)
        if isinstance(self, Var):
            error.throw_instantiation_error()
        return self.eval_arithmetic(engine)
    
    @jit.dont_look_inside
    def cmp_standard_order(self, other, heap):
        assert isinstance(other, Var)
        return rcmp(compute_unique_id(self), compute_unique_id(other)) class Callable(NonVar):
    __slots__ = ()

    def __init__(self):
        pass
    
    def name(self):
        return self.signature().name
        
    def signature(self):
        raise NotImplementedError("abstract base")
    
    def get_prolog_signature(self):
        return Callable.build("/", [Callable.build(self.name()),
                                    Number(self.argument_count())])
    def arguments(self):
        argcount = self.argument_count()
        result = [None] * argcount
        for i in range(argcount):
            result[i] = self.argument_at(i)
        return result
    
    def argument_at(self, i):
        raise NotImplementedError("abstract base")
    
    def argument_count(self):
        raise NotImplementedError("abstract base")
    
    @specialize.arg(3)
    def basic_unify(self, other, heap, occurs_check):
        if (isinstance(other, Callable) and
                self.signature().eq(other.signature())):
            for i in range(self.argument_count()):
                self.argument_at(i).unify(other.argument_at(i), heap, occurs_check)
        else:
            raise UnificationFailed
    
    @jit.unroll_safe
    def basic_unify_and_standardize_apart(self, other, heap, env):
        if (isinstance(other, Callable) and
            self.signature().eq(other.signature())):
            for i in range(self.argument_count()):
                argself = self.argument_at(i)
                argother = other.argument_at(i)
                argself.unify_and_standardize_apart(argother, heap, env)
        else:
            raise UnificationFailed
    
    def copy(self, heap, memo):
        return self._copy_term(_term_copy, heap, memo)
    
    def copy_standardize_apart(self, heap, env):
        return self._copy_term(_term_copy_standardize_apart, heap, env)
    
    def enumerate_vars(self, memo):
        return self._copy_term(_term_enumerate_vars, None, memo)

    @specialize.arg(1)
    @jit.unroll_safe
    def _copy_term(self, copy_individual, heap, *extraargs):
        args = [None] * self.argument_count()
        newinstance = False
        i = 0
        while i < self.argument_count():
            arg = self.argument_at(i)
            cloned = copy_individual(arg, i, heap, *extraargs)
            newinstance = newinstance | (cloned is not arg)
            args[i] = cloned
            i += 1
        if newinstance:
            # XXX construct the right class directly
            return Callable.build(self.name(), args, self.signature(), heap=heap)
        else:
            return self
    
    def contains_var(self, var, heap):
        for arg in self.arguments():
            if arg.contains_var(var, heap):
                return True
        return False
    
    def cmp_standard_order(self, other, heap):
        assert isinstance(other, Callable)
        c = rcmp(self.argument_count(), other.argument_count())
        if c != 0:
            return c
        c = rcmp(self.name(), other.name())
        #print self.name()
        #print other.name()
        if c != 0:
            return c
        for i in range(self.argument_count()):
            a1 = self.argument_at(i).dereference(heap)
            a2 = other.argument_at(i).dereference(heap)
            c = cmp_standard_order(a1, a2, heap)
            if c != 0:
                return c
        return 0
    
    def eval_arithmetic(self, engine):
        from prolog.interpreter.arithmetic import get_arithmetic_function
        func = get_arithmetic_function(self.signature())
        jit.promote(func)
        if func is None:
            error.throw_type_error("evaluable", self.get_prolog_signature())
        return func(engine, self)
    
    @staticmethod
    @jit.unroll_safe
    def build(term_name, args=None, signature=None, heap=None, cache=True):
        if args is None:
            args = []
        if heap is not None:
            # perform variable shunting:
            # remove variables that are not needed because they are bound
            # already and cannot be backtracked
            for i in range(len(args)):
                arg = args[i]
                if (isinstance(arg, Var) and arg.getbinding() is not None and
                        arg.created_after_choice_point is heap):
                    args[i] = arg.getbinding()
        if len(args) == 0:
            if cache:
                return Atom.newatom(term_name, signature)
            return Atom(term_name, signature)
        else:
            if signature is None:
                if cache:
                    signature = Signature.getsignature(term_name, len(args))
                else:
                    signature = Signature(term_name, len(args))
            else:
                assert signature.numargs == len(args)
            assert isinstance(signature, Signature)

            cls = Callable._find_specialized_class(term_name, len(args))
            if cls is not None:
                return cls(term_name, args, signature)
            cls = Callable._find_specialized_class('Term', len(args))
            if cls is not None:
                return cls(term_name, args, signature)
            return Term(term_name, args, signature)

    @staticmethod
    @jit.elidable
    def _find_specialized_class(term_name, numargs):
        return specialized_term_classes.get((term_name, numargs), None)

    def __repr__(self):
        return "%s(%s, %r)" % (self.__class__.__name__, self.name(),
                               self.arguments())

    @jit.unroll_safe
    def quick_unify_check(self, other):
        other = other.dereference(None)
        if isinstance(other, Var):
            return True
        if not isinstance(other, Callable):
            return False
        if not self.signature().eq(other.signature()):
            return False
        for i in range(self.argument_count()):
            if not self.argument_at(i).quick_unify_check(other.argument_at(i)):
                return False
        return True class Atom(Callable):
    TYPE_STANDARD_ORDER = 2
    __slots__ = ('_name', '_signature')
    cache = {}
    _immutable_fields_ = ["_signature"]
    
    def __init__(self, name, signature=None):
        if signature is None:
            signature = Signature(name, 0)
        Callable.__init__(self)
        self._signature = signature
    
    def __str__(self):
        return self.name()
    
    def __repr__(self):
        return "Atom(%r)" % (self.name(),)
    
    @staticmethod
    @jit.elidable
    def newatom(name, signature=None):
        if signature is None:
            signature = Signature.getsignature(name, 0)
        result = Atom.cache.get(signature, None)
        if result is not None:
            return result
        Atom.cache[signature] = result = Atom(name, signature)
        return result
    
    def eval_arithmetic(self, engine):
        #XXX beautify that
        if self.name() == "pi":
            return Float.pi
        if self.name() == "e":
            return Float.e
        error.throw_type_error("evaluable", self.get_prolog_signature())
    
    def arguments(self):
        return []
    
    def argument_at(self, i):
        raise IndexError
    
    def argument_count(self):
        return 0
    
    def name(self):
        return self._signature.name
    
    def signature(self):
        return self._signature

    def basic_unify_and_standardize_apart(self, other, heap, env):
        if not isinstance(other, Atom):
            return Callable.basic_unify_and_standardize_apart(self, other, heap, env)
        if not self.signature().eq(other.signature()):
            raise UnificationFailed class UnificationFailed(PrologError):
    pass def throw_representation_error(signature, msg):
    from prolog.interpreter import term
    t = term.Callable.build("representation_error",
            [term.Callable.build(signature), term.Callable.build(msg)])
    raise wrap_error(t) def throw_instantiation_error(obj = None):
    from prolog.interpreter import term
    raise wrap_error(term.Callable.build("instantiation_error")) def wrap_list(python_list):
    curr = emptylist
    for i in range(len(python_list) - 1, -1, -1):
        curr = term.Callable.build(".", [python_list[i], curr])
    return curr def is_term(obj):
    return isinstance(obj, term.Callable) and obj.argument_count() > 0 @jit.unroll_safe
def unwrap_list(prolog_list):
    # Grrr, stupid JIT
    result = [None]
    used = 0
    curr = prolog_list
    while isinstance(curr, term.Callable) and curr.signature().eq(conssig):
        if used == len(result):
            nresult = [None] * (used * 2)
            for i in range(used):
                nresult[i] = result[i]
            result = nresult
        result[used] = curr.argument_at(0)
        used += 1
        curr = curr.argument_at(1)
        curr = curr.dereference(None)
    if isinstance(curr, term.Callable) and curr.signature().eq(nilsig):
        if used != len(result):
            nresult = [None] * used
            for i in range(used):
                nresult[i] = result[i]
            result = nresult
        return result
    error.throw_type_error("list", prolog_list) class Signature(object):
    """An object representing the signature of a Prolog term."""

    _cache = SignatureFactory()

    _immutable_fields_ = ["name", "numargs", "atom_signature", "factory"]

    def __init__(self, name, numargs, cached=False, factory=None):
        assert name is not None
        assert isinstance(name, str)
        name = rstring.assert_str0(name)
        self.name = name
        self.numargs = numargs
        self.cached = cached
        if factory is None:
            factory = self._cache
        self.factory = factory
        if numargs:
            atom_signature = factory.getsignature(name, 0, cached)
        else:
            atom_signature = self
        self.atom_signature = atom_signature
        factory.init_extra_attrs(self)

    def eq(self, other):
        # slightly evil
        if jit.isconstant(self):
            jit.promote(other)
        elif jit.isconstant(other):
            jit.promote(self)
        return self is other or (
                self.numargs == other.numargs and
                self.name == other.name)

    @specialize.arg(1)
    def get_extra(self, name):
        aname = "extra_attr_" + name
        if not we_are_translated():
            assert aname in self.factory.extra_attr_names
        self = self.ensure_cached()
        return getattr(self, aname)

    @specialize.arg(1)
    def set_extra(self, name, val):
        aname = "extra_attr_" + name
        if not we_are_translated():
            assert aname in self.factory.extra_attr_names
        self = self.ensure_cached()
        setattr(self, aname, val)


    @specialize.arg(1)
    def get_extra_engine_local(self, name, engine):
        ename = "extra_attr_engine_" + name
        if not we_are_translated():
            assert ename in self.factory.extra_attr_names
        if getattr(self, ename) is not engine:
            setattr(self, ename, engine)
            aname = "extra_attr_" + name
            setattr(self, aname, None)    
        return self.get_extra(name)

    @specialize.arg(1)
    def set_extra_engine_local(self, name, val, engine):
        ename = "extra_attr_engine_" + name
        setattr(self, ename, engine)
        self.set_extra(name, val)

    def ensure_cached(self):
        if self.cached:
            return self
        return self.factory.ensure_cached(self)

    def string(self):
        return "%s/%s" % (self.name, self.numargs)

    def __repr__(self):
        return "<Signature %s>" % (self.string(), )

    @staticmethod
    @jit.elidable
    def getsignature(name, numargs):
        return Signature._cache.getsignature(name, numargs)

    @staticmethod
    def register_extr_attr(name, engine=False, default=None):
        Signature._cache.register_extr_attr(name, engine, default) @specialize.arg(4)
def term_variables(engine, heap, prolog_term, variables, consider_attributes=False):
    varlist = []
    varc = variables
    seen = {}
    todo = [prolog_term]
    cls = Var
    if consider_attributes:
        cls = AttVar
    while todo:
        t = todo.pop()
        value = t.dereference(heap)
        if isinstance(value, cls):
            if consider_attributes and value.is_empty():
                continue
            if value not in seen:
                varlist.append(value)
                seen[value] = None
                X = heap.newvar()
                prolog_list = Callable.build(".", [value, X])
                prolog_list.unify(varc, heap)
                varc = X
        elif isinstance(value, Callable):
            numargs = value.argument_count()
            for i in range(numargs - 1, -1, -1):
                todo.append(value.argument_at(i))
    varc.unify(Callable.build("[]"), heap)
from prolog.builtin.register import expose_builtin
from prolog.interpreter import continuation
from prolog.interpreter.term import AttVar, Var, Callable, Atom
from prolog.interpreter.error import UnificationFailed,\
throw_representation_error, throw_instantiation_error
from prolog.interpreter.helper import wrap_list, is_term, unwrap_list
from prolog.interpreter.signature import Signature
from prolog.builtin.term_variables import term_variables
    from prolog.interpreter.memo import CopyMemo

conssig = Signature.getsignature(".", 2)

@expose_builtin("attvar", unwrap_spec=["obj"])
def impl_attvar(engine, heap, obj):
    if not isinstance(obj, AttVar):
        raise UnificationFailed()
    if obj.is_empty():
        raise UnificationFailed()
        
@expose_builtin("put_attr", unwrap_spec=["obj", "atom", "obj"])
def impl_put_attr(engine, heap, var, attr, value):
    if isinstance(var, AttVar):
        old_value, _ = var.get_attribute(attr)
        var.add_attribute(attr, value)
        _, index = var.get_attribute(attr)
        heap.trail_new_attr(var, index, old_value)
    elif isinstance(var, Var):
        attvar = heap.new_attvar()
        attvar.add_attribute(attr, value)
        var.unify(attvar, heap)
    else:
        throw_representation_error("put_attr/3",
                "argument must be unbound (1-st argument)")

@expose_builtin("get_attr", unwrap_spec=["obj", "atom", "obj"])
def impl_get_attr(engine, heap, var, attr, value):
    if not isinstance(var, Var):
        throw_instantiation_error(var)
    if not isinstance(var, AttVar):
        raise UnificationFailed()
    attribute_value, _ = var.get_attribute(attr)
    if attribute_value is not None:
        value.unify(attribute_value, heap)
    else:

        raise UnificationFailed()