'''
Defines the IBackend object, which mediates interations between the Python
API and backends.
This contains definitions common to all backends and the interfaces each should
implement.
'''
from .. import config
import abc, importlib
__all__ = ['IBackend', 'Node']
[docs]
class IBackend(metaclass=abc.ABCMeta):
'''
The interface to a Curry implementation.
This interface mediates all interactions bewteen the Sprite API (e.g., the
Interpreter class) and a backend implementation. This stateless object
is shared among all interpreters using the same backend.
'''
_instances = {}
def __new__(cls, backend=None):
if backend not in cls._instances:
if cls is IBackend:
assert backend is not None
# Each backend must implement this class at backends.<name>.interface.IBackend.
currypkg = config.python_package_name()
ifc = importlib.import_module('%s.backends.%s.interface' % (currypkg, backend))
cls._instances[backend] = ifc.IBackend()
else:
return object.__new__(cls)
return cls._instances[backend]
@abc.abstractproperty
def backend_name(self):
'''E.g., 'py' or 'cxx'.'''
assert 0
@abc.abstractproperty
def extend_plan_skeleton(self):
assert 0
@abc.abstractproperty
def compile(self):
'''Converts ICurry to an instance of IR.'''
assert 0
[docs]
@abc.abstractmethod
def get_interpreter_state(self, interp):
'''Gets the runtime-specific state attached to an interpreter.'''
assert 0
[docs]
@abc.abstractmethod
def find_or_create_internal_module(self, moduleobj):
assert 0
[docs]
def compile_pending(self, moduleobj):
'''
Compiles the functions of a loaded module whose compilation the backend
deferred, once every symbol of the module is registered. The Python
backend compiles a step function on its first call; an expression module
(compile.compile_expression) leaves the registry of the interpreter after
this call, so its functions are compiled here. A backend that compiles
whole modules ahead of time has nothing to do.
'''
[docs]
def module_loaded(self, interp, moduleobj, currypath):
'''
Called when the import of a module ends, after the imports of the module
were imported and its symbols were loaded. ``currypath`` is the search
path of the imports of the module: the path of a program given as a
file, or the path of the interpreter for a module given by name
(interpreter.import_.ImportEx). The C++ backend queues the background
compile of a module it interprets (see backends.cxx.tiered).
'''
[docs]
def module_unlinked(self, interp, moduleobj):
'''
Called when a module leaves the interpreter (Handle.unlink: a reset, or
the hard reset of ``reload``), after its name left ``interp.modules``.
The module object may stay alive in the hands of the user. The C++
backend hands the tables of the module to the kept store of the
runtime, so a module of the same name made later runs its own code
(issue #114; see Module::retire in cyrt/module.hpp).
'''
[docs]
def before_evaluation(self, interp):
'''
Called when an evaluation is about to start. The C++ backend applies the
compiled objects that finished in the background.
'''
[docs]
def after_evaluation(self, interp):
'''
Called when the values of an evaluation are exhausted. The C++ backend
applies and logs the compiled objects that finished during the
evaluation.
'''
[docs]
def tiered_counts(self):
'''
The functions swapped to compiled code and the background compiles that
failed in this process (Interpreter.stats reports them). A backend
without tiered execution answers zeros.
'''
return 0, 0
@abc.abstractproperty
def fundamental_symbols(self):
assert 0
[docs]
@abc.abstractmethod
def init_interpreter_state(self, interp):
'''Initializes an interpreter with the runtime-specific state.'''
assert 0
[docs]
def num_collections(self):
'''
The number of collections the garbage collector of this backend has run
in this process. A backend without a collector of its own answers zero.
'''
return 0
[docs]
def gc_seconds(self):
'''
The seconds the garbage collector of this backend has spent in its
collections in this process. A backend without a collector of its own
answers zero.
'''
return 0.0
[docs]
def gc_counters(self):
'''
The counters of the garbage collector of this backend, summed over its
collections in this process, as a dict keyed by the names in
stats.GC_COUNTERS (the seconds of the phases of a collection, the nodes
marked by age, the configurations pushed, the queues and configurations
destroyed, the writes into old nodes). A backend without a collector
of its own answers an empty dict, which Interpreter.stats reports as
zeros.
'''
return {}
[docs]
def scheduler_counters_enabled(self):
'''
True when the runtime of this backend counts the serial steps, the
lifetimes of configurations, and the shared work of an evaluation
(Interpreter.stats reports them). Only the C++ runtime built with
make COUNTERS=1 does.
'''
return False
[docs]
def getimpl(self, symbol):
'''
The implementation code of the step function of ``symbol`` (a
CurryNodeInfo) as text; see :func:`curry.inspect.getimpl`. Raises
ValueError when the backend has no code for the symbol.
'''
raise ValueError(
'no implementation code available for %r' % symbol.fullname
)
@abc.abstractproperty
def load_module(self):
'''Load the contents of a Curry module.'''
assert 0
[docs]
@abc.abstractmethod
def lookup_builtin_module(self, modulename):
'''Looks up the implementation for a built-in module.'''
assert 0
@abc.abstractproperty
def create_evaluation_rts(self):
'''Creates a new runtime state representing an evaluation.'''
assert 0
@abc.abstractproperty
def make_node(self):
assert 0
@abc.abstractproperty
def materialize(self):
assert 0
@abc.abstractproperty
def object_file_extension(self):
assert 0
@abc.abstractproperty
def write_module(self):
'''Write the contents of a Curry module to a stream.'''
assert 0
# Each backend must provide a Node object and register it with this class.
[docs]
class Node(metaclass=abc.ABCMeta):
pass
# Each backend must provide an InfoTable object and register it with this class.
class InfoTable(metaclass=abc.ABCMeta):
pass