def expose_builtin(*args, **kwargs):
    def really_expose(func):
        return make_wrapper(func, *args, **kwargs)
    return really_expose 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 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 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 Term(Callable):
    TYPE_STANDARD_ORDER = 3
    _immutable_fields_ = ["_args[*]", "_name", "_signature"]
    __slots__ = ('_name', '_signature', '_args')
    
    def __init__(self, term_name, args, signature):
        assert signature.name == term_name
        self._args = make_sure_not_resized(args)
        self._signature = signature
        Callable.__init__(self)
    
    def __repr__(self):
        return "Term(%r, %r)" % (self.name(), self.arguments())
    
    def __str__(self):
        return "%s(%s)" % (self.name(), ", ".join([str(a) for a in self.arguments()]))
    
    def arguments(self):
        return self._args
    
    def argument_at(self, i):
        return self._args[i]
    
    def argument_count(self):
        return len(self._args)
    
    def signature(self):
        return self._signature class Number(Numeric):#, UnboxedValue):
    TYPE_STANDARD_ORDER = 1
    __slots__ = ("num", )
    _immutable_fields_ = ["num"]

    def __init__(self, val):
        self.num = val

    @specialize.arg(3)
    def basic_unify(self, other, heap, occurs_check):
        if isinstance(other, Number) and other.num == self.num:
            return
        raise UnificationFailed

    def __str__(self):
        return repr(self.num)
    
    def __repr__(self):
        return "Number(%r)" % (self.num, )
    
    def cmp_standard_order(self, other, heap):
        # XXX looks a bit terrible
        if isinstance(other, Number):
            return rcmp(self.num, other.num)
        elif isinstance(other, Float):
            # int/float mixed are always compared as floats
            return rcmp(float(self.num), other.floatval)
        elif isinstance(other, BigInt):
            return bigint_cmp(rbigint.fromint(self.num), other.value)
        assert 0

    def quick_unify_check(self, other):
        other = other.dereference(None)
        if isinstance(other, Var):
            return True
        return isinstance(other, Number) and other.num == self.num class PrologError(Exception):
class UncatchableError(PrologError):
class PrologParseError(PrologError):
class TermedError(PrologError):
class CatchableError(TermedError): pass
class UncaughtError(TermedError):
class TraceFrame(object):
class UnificationFailed(PrologError):
    def __init__(self, message):
    def __init__(self, file_name, line_number, message):
    def __init__(self, term, sig_context=None):
    def get_errstr(self, engine):
    def __init__(self, term, sig_context=None, rule_likely_source=None, scont=None):
    def format_traceback(self, engine):
    def __init__(self, rule, next=None):
    def __repr__(self):
    def _format(self, out):
def _construct_traceback(scont):
def wrap_error(t):
def throw_syntax_error(msg):
def throw_import_error(modulename, signature):
def throw_existence_error(object_type, obj):
def throw_instantiation_error(obj = None):
def throw_representation_error(signature, msg):
def throw_type_error(valid_type, obj):
def throw_domain_error(valid_domain, obj):
def throw_permission_error(operation, permission_type, obj):
def throw_evaluation_error(error): def get_source(filename):
    try:
        assert isinstance(filename, str)
        fd, actual_filename = get_filehandle(filename, True)
    except OSError:
        throw_existence_error("source_sink", Callable.build(filename))
        assert 0, "unreachable" # make the flow space happy
    try:
        content = []
        while 1:
            s = os.read(fd, 4096)
            if not s:
                break
            content.append(s)
        file_content = "".join(content)
    finally:
        os.close(fd)
    return file_content, actual_filename 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): def is_term(obj):
    return isinstance(obj, term.Callable) and obj.argument_count() > 0 def unwrap_predicate_indicator(predicate):
    if not isinstance(predicate, term.Callable):
        error.throw_type_error("predicate_indicator", predicate)
        assert 0, "unreachable"
    if not predicate.name()== "/" or predicate.argument_count() != 2:
        error.throw_type_error("predicate_indicator", predicate)
    name = unwrap_atom(predicate.argument_at(0))
    arity = unwrap_int(predicate.argument_at(1))
    return name, arity 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)
import py
    import os
    import os.path
from prolog.builtin.register import expose_builtin
from prolog.interpreter.term import Atom, Callable, Var, Term, Number
from prolog.interpreter import error
from prolog.builtin.sourcehelper import get_source
from prolog.interpreter import continuation
from prolog.interpreter.helper import is_term, unwrap_predicate_indicator
from prolog.interpreter.signature import Signature
    from prolog.builtin.sourcehelper import get_filehandle
    from os.path import isdir
    try:
        imported_module = m.modules[modulename]
    except KeyError: # we did not parse a correctly defined module file
        pass
    else:
        module.use_module(imported_module, imports)

@expose_builtin("use_module", unwrap_spec=["callable"], needs_module=True)
def impl_use_module(engine, heap, module, path):
    if isinstance(path, Atom):
        handle_use_module(engine, heap, module, path)
    else:
        handle_use_module_with_library(engine, heap, module, path)

@expose_builtin("use_module", unwrap_spec=["callable", "list"], needs_module=True)
def impl_use_module_with_importlist(engine, heap, module, path, imports):
    importlist = []
    for sigatom in imports:
        importlist.append(Signature.getsignature(
                *unwrap_predicate_indicator(sigatom))) 
    if isinstance(path, Atom):
        handle_use_module(engine, heap, module, path, importlist)
    else:
        handle_use_module_with_library(engine, heap, module, path, importlist)

@expose_builtin("module", unwrap_spec=["atom"])
def impl_module_1(engine, heap, name):
    engine.switch_module(name)

@expose_builtin(":", unwrap_spec=["atom", "callable"], 
        handles_continuation=True)
def impl_module_prefixing(engine, heap, modulename, 
        call, scont, fcont):
    module = engine.modulewrapper.get_module(modulename, call)
    return engine.call_in_module(call, module, scont, fcont, heap)

@expose_builtin("add_library_dir", unwrap_spec=["atom"])
def impl_add_library_dir(engine, heap, path):
    assert path is not None
    if not isdir(path):
        error.throw_existence_error("source_sink", Callable.build(path))
    libs = engine.modulewrapper.libs
    for lib in libs:
        if lib == path:  
            return
    engine.modulewrapper.libs.append(path)

@continuation.make_failure_continuation
def continue_librarydir(Choice, engine, scont, fcont, heap, pathvar, keycount):
    if keycount < len(engine.modulewrapper.libs) - 1:
        fcont = Choice(engine, scont, fcont, heap, pathvar, keycount + 1)
        heap = heap.branch()
    pathvar.unify(Callable.build(engine.modulewrapper.libs[keycount]), heap)
    return scont, fcont, heap

@expose_builtin("library_directory", unwrap_spec=["obj"],
        handles_continuation=True)
def impl_library_directory(engine, heap, directory, scont, fcont):
    if isinstance(directory, Var):
        if not engine.modulewrapper.libs:
            raise error.UnificationFailed
        return continue_librarydir(engine, scont, fcont, heap, directory, 0)
    elif isinstance(directory, Atom):
        for lib in engine.modulewrapper.libs:
            if lib == directory.name():
                return scont, fcont, heap
    raise error.UnificationFailed()

@expose_builtin("this_module", unwrap_spec=["obj"])
def impl_this_module(engine, heap, module):
    name = engine.modulewrapper.current_module.name
    Callable.build(name).unify(module, heap)  

@expose_builtin("meta_predicate", unwrap_spec=["callable"])
def impl_meta_predicate(engine, heap, predlist):
    run = True
    while run:
        assert isinstance(predlist, Callable)
        if predlist.signature().eq(andsig):
            pred = predlist.argument_at(0)
            predlist = predlist.argument_at(1)
            if isinstance(predlist, Var):
                error.throw_instantiation_error()
        else:
            pred = predlist
            run = False
        assert isinstance(pred, Callable)
        args = unwrap_meta_arguments(pred)
        engine.modulewrapper.current_module.add_meta_predicate(
                pred.signature(), args)
          
def unwrap_meta_arguments(predicate):
    assert isinstance(predicate, Callable)
    args = predicate.arguments()
    arglist = []
    for arg in args:
        if isinstance(arg, Var):
            error.throw_instantiation_error()
            assert 0
        elif isinstance(arg, Atom) and arg.name() in meta_args:
            val = arg.name()
        elif isinstance(arg, Number) and 0 <= arg.num <= 9:
            val = str(arg.num)
        else:
            error.throw_domain_error("expected one of 0..9, :, ?, +, -", arg)
            assert 0
        arglist.append(val[0])
    return "".join(arglist)

@continuation.make_failure_continuation
def continue_current_module(Choice, engine, scont, fcont, heap, allmods, i, modvar):
    if i < len(allmods) - 1:
        fcont = Choice(engine, scont, fcont, heap, allmods, i + 1, modvar)
        heap = heap.branch()
    modvar.unify(allmods[i], heap)
    return scont, fcont, heap

@expose_builtin("current_module", unwrap_spec=["obj"],
        handles_continuation=True)
def impl_current_module(engine, heap, module, scont, fcont):

    if isinstance(module, Atom):