Source code for curry.icurry.analysis.monadic

from ...common import F_MONADIC
from .. import types, visit
import sys

__all__ = ['set_monadic_metadata']

class TRUE(BaseException): pass

[docs] def set_monadic_metadata(ifun, modules): ''' Determines whether an ICurry function is monadic. The result is stored in the 'all.monadic' metadata and also in 'all.flags' by OR-ing with F_MONADIC. This apparent redundancy is needed because 'all.monadic' is actually a tristate: True or False indicates the monadic check has been performed, while its absense indicates the check needs to be performed. To determine whether a function is monadic, its call graph is walked. If the function calls any monadic function, then it is determined to be monadic. ''' if isinstance(ifun, types.IFunction): if 'all.monadic' not in ifun.metadata: flags = ifun.metadata.get('all.flags', 0) if flags & F_MONADIC: ifun.update_metadata({'all.monadic': True}) else: ifun.update_metadata({'all.monadic': False}) visitor = lambda iobj, **kwds: _checkmonadic(iobj, modules, **kwds) try: visit.visit(visitor, ifun.body) except TRUE: ifun.update_metadata({ 'all.flags': flags | F_MONADIC , 'all.monadic': True }) return True return ifun.metadata['all.monadic'] else: return False
def _lookupfunction(symbolname, modules): # interp.symbol cannot be used because analysis must occur before the symbols # are created. For example, we need to determine whether something like # Prelude.putStr is monadic before creating its symbol (which would have # set_monadic_metadata=True set). interp.symbol cannot, of course, be used # before the symbol tables are generated. obj = modules parts = iter(symbolname.split('.')) while not isinstance(obj, types.IModule): part = next(parts) obj = obj[part] obj = getattr(obj, '.icurry', obj) return obj.functions.get('.'.join(parts), None) def _checkmonadic(iobj, modules, **kwds): if isinstance(iobj, types.ICall): ifun = _lookupfunction(iobj.symbolname, modules) if ifun is not None: if set_monadic_metadata(ifun, modules): raise TRUE()