Source code for curry.backends.py.materialize

from ...common import T_CTOR, T_FUNC
from ..generic.compiler import DEFINED, STEP_FUNCTION
from .graph.infotable import DataType, InfoTable
from . import compiler
from ... import icurry, objects
from io import StringIO
from ...utility import encoding, filesys, visitation
import inspect, textwrap

[docs] def materialize(interp, iobj, moduleobj): materializer = Materializer(interp) return materializer.materialize(iobj)
[docs] class Materializer(object): def __init__(self, interp): self.interp = interp
[docs] def materialize(self, iobj): info = iobj.metadata.get('py.material') if info is not None: assert isinstance(info, (DataType, InfoTable)) return info else: return self.materializeEx(iobj)
@visitation.dispatch.on('iobj') def materializeEx(self, iobj): assert False @materializeEx.when(icurry.IType) def materializeEx(self, itype): datatype = DataType( itype.name , [self.materialize(ictor) for ictor in itype.constructors] ) for ctorinfo in datatype.constructors: ctorinfo.typedef = datatype return datatype @materializeEx.when(icurry.IConstructor) def materializeEx(self, ictor): builtin = 'all.tag' in ictor.metadata return InfoTable( ictor.name , ictor.arity , T_CTOR + ictor.index if not builtin else ictor.metadata['all.tag'] , getattr(ictor.metadata, 'all.flags', 0) , None , getattr(ictor.metadata, 'py.format', None) )
[docs] @materializeEx.when(icurry.IFunction) def materializeEx(self, ifun): # If lazycompile is set, delay compilation until the function is actually # used. The step function resolves the symbols it refers to by name, so # a function compiled while its module loads must not refer to a function # of the module loaded after it: a lambda lifted from the text of an # expression, or a method derived for a data type of the module. An # expression module, which leaves the registry of the interpreter after # its compilation, is compiled right after its load (compile_pending). trampoline = Trampoline( lambda: materializeStepfunc(self.interp, ifun) ) lazy = self.interp.flags['lazycompile'] info = InfoTable( ifun.name , ifun.arity , T_FUNC , ifun.metadata.get('all.flags', 0) , trampoline if lazy else trampoline.materialize() , getattr(ifun.metadata, 'py.format', None) ) if lazy: trampoline.slot = info, 'step' return info
[docs] def compile_pending(moduleobj): ''' Compiles every step function of ``moduleobj`` that was left to its first call. Every symbol of the module is registered, so a function may refer to any function of the module. ''' for symbol in getattr(moduleobj, '.symbols').values(): step = symbol.info.step if isinstance(step, Trampoline): step.materialize()
[docs] def materializeStepfunc(interp, ifun): '''JIT-compiles a Python step function.''' target_object = compiler.compile(interp, ifun) stream = StringIO() compiler.write_module(target_object, stream, module_main=False, section_headers=False) source = stream.getvalue() closure = {'interp': interp} if interp.flags['debug']: # If debugging, write a source file so that PDB can step into this # function. assert ifun is not None srcdir = filesys.getDebugSourceDir() name = encoding.symbolToFilename(ifun.fullname) + '.py' srcfile = filesys.makeNewfile(srcdir, name) with open(srcfile, 'w') as out: out.write(source) out.write('\n') comment = ( 'This file was created by Sprite because %r was compiled in debug ' 'mode. It exists to help PDB show the compiled code.' ) % ifun.fullname out.write('\n'.join('# ' + line for line in textwrap.wrap(comment))) out.write('\n\n# ICurry:\n# -------\n') out.write('\n'.join('# ' + line for line in str(ifun).split('\n'))) co = compile(source, srcfile, 'exec') exec(co, closure) else: exec(source, closure) for symbolname, symbol in target_object.symtab.items(): if symbol.kind == STEP_FUNCTION and symbol.stat == DEFINED: stepfunc = closure[symbolname] stepfunc.source = source return stepfunc assert False
[docs] def getimpl(symbol): ''' The source of the step function of ``symbol``: the text of a step compiled in this process, or the source of the function in the generated module or in the library of built-ins. A step left to its first call is compiled now. Raises ValueError when there is no step or no source. ''' step = symbol.info.step if isinstance(step, Trampoline): step = step.materialize() if step is not None: source = getattr(step, 'source', None) if source is not None: return source try: return inspect.getsource(step) except (OSError, TypeError): pass raise ValueError( 'no implementation code available for %r' % symbol.fullname )
[docs] class Trampoline(object): def __init__(self, callback, slot=None): self.callback = callback self.slot = None
[docs] def materialize(self): value = self.callback() if self.slot: obj, attr = self.slot setattr(obj, attr, value) return value
def __call__(self, *args, **kwds): f = self.materialize() return f(*args, **kwds)