Source code for curry.backends.generic.compiler

from ...exceptions import CompileError
from ... import config, icurry
from ...utility import formatDocstring, maxrecursion, strings, visitation
from ...utility.trampoline import trampoline
import abc, collections, collections.abc, contextlib, itertools, logging, re

logger = logging.getLogger(__name__)

__all__ = [
    'CompilerBase', 'SymbolTable', 'TargetObject'
  , 'decode', 'demangle', 'encode', 'mangle'

  , 'CONSTRUCTOR_TABLE', 'DATA_TYPE', 'DEFINED', 'INFO_TABLE', 'LITERAL_NODE'
  , 'MODULE_DATA', 'PARTIAL_NODE', 'STEP_FUNCTION', 'STRING_DATA', 'UNDEFINED'
  , 'VALUE_SET'
  ]


# Symbol kind.
CONSTRUCTOR_TABLE = 'CONSTRUCTOR_TABLE'
DATA_TYPE         = 'DATA_TYPE'         # A Curry data type (for narrowing).
INFO_TABLE        = 'INFO_TABLE'        # Constructor or Function info table.
MODULE_DEF        = 'MODULE_DEF'
STEP_FUNCTION     = 'STEP_FUNCTION'     # A step function.
STRING_DATA       = 'STRING_DATA'       # Static string data.
VALUE_SET_DATA    = 'VALUE_SET_DATA'    # Array data for a value set.
VALUE_SET         = 'VALUE_SET'         # Case values (for narrowing).
BUILTIN_FUNCTION  = 'BUILTIN_FUNCTION'  # A function provided by the execution environment.
METADATA          = 'METADATA'          # A metadata object.
MODULE_DATA       = 'MODULE_DATA'       # A table of the module definition.
LITERAL_NODE      = 'LITERAL_NODE'      # A node of a literal, made at load.
PARTIAL_NODE      = 'PARTIAL_NODE'      # A partial application without arguments, made at load.

# Symbol status.
DEFINED   = 'T'
UNDEFINED = 'U'

Symbol = collections.namedtuple('Symbol', ['name', 'stat', 'kind', 'descr'])
# E.g.: the symbol for Prelude.: might appear in the symbol table for the
# Prelude as follows:
#
#   ('_7Prelude4Cons', 'T', INFO_TABLE, EXTERNAL, 'Prelude.:')

[docs] class SymbolTable(dict): # {str: Symbol}
[docs] def insert(self, name, kind, descr): if name not in self: self[name] = Symbol(name, UNDEFINED, kind, descr) return True else: return False
[docs] def make_defined(self, name): existing = self[name] if existing.stat == DEFINED: raise CompileError('multiple definition of %r' % existing.descr) else: assert name == existing.name self[name] = Symbol(name, DEFINED, existing.kind, existing.descr)
TR = { '_' : '__' , '&' : '_M' , '@' : '_A' , '!' : '_B' , '`' : '_T' , '^' : '_c' , ':' : '_C' , ',' : '_m' , '$' : '_D' , '.' : '_d' , '"' : '_Q' , '=' : '_E' , '\\': '_z' , '>' : '_G' , '{' : '_R' , '[' : '_K' , '(' : '_Y' , '<' : '_L' , '-' : '_n' , '#' : '_h' , '%' : '_s' , '|' : '_p' , '+' : '_P' , '?' : '_u' , '}' : '_r' , ']' : '_k' , ')' : '_y' , ';' : '_S' , '/' : '_l' , '\'': '_q' , '*' : '_a' , '~' : '_t' } TRR = {v:k for k,v in TR.items()} # Check for duplicates in TR and TRR. assert all(n == 1 for n in collections.Counter(TR.values()).values()) assert all(n == 1 for n in collections.Counter(TRR.values()).values()) assert len(TR) == len(TRR) KIND_CODE = { BUILTIN_FUNCTION : 'B' , CONSTRUCTOR_TABLE : 'C' , DATA_TYPE : 'D' , INFO_TABLE : 'I' , LITERAL_NODE : 'L' , METADATA : 'Q' , PARTIAL_NODE : 'P' , MODULE_DATA : 'T' , MODULE_DEF : 'M' , STEP_FUNCTION : 'F' , STRING_DATA : 'S' , VALUE_SET : 'V' , VALUE_SET_DATA : 'A' } KIND_CODE_R = {v:k for k,v in KIND_CODE.items()}
[docs] def encode(name): '''Encode a Curry identifier string to alphnumeric.''' enc = ''.join(TR.get(ch, ch) for ch in name) return enc
[docs] def decode(name): '''Decode an encoded Curry identifier string.''' def gen(): i = 0 n = len(name) while i<n: if name[i] == '_': enc = name[i:i+2] yield TRR[enc] i += 2 else: yield name[i] i += 1 return ''.join(gen())
[docs] def mangle(parts, kind): # E.g., Prelude.: -> CyI7Prelude5_col_ # Cy = prefix for all Curry symbols # I = symbol kind (info table) # 7Prelude = name qualifier # 5_col_ = encoded name parts_ = parts[:-1] + [encode(parts[-1])] tail = ''.join('%s%s' % (len(p), p) for p in parts_) symbolname = 'Cy%s%s' % (KIND_CODE[kind], tail) # assert demangle(symbolname) == (parts, kind) return symbolname
P_INTEGER = re.compile(r'(^\d+)')
[docs] def demangle(symbolname): assert symbolname.startswith('Cy') kind = KIND_CODE_R[symbolname[2]] def gen(): i = 3 n = len(symbolname) while i<n: text = re.match(P_INTEGER, symbolname[i:]).group() chunksz = int(text) i += len(text) chunk = symbolname[i:i+chunksz] yield decode(chunk) i += chunksz return list(gen()), kind
[docs] class TargetObject(object): SECTIONS = ( '.header' ### Forward declarations. , '.imports' # Imported Curry modules. , '.stepfuncs.link' # Step function forward declarations. , '.infotabs.link' # InfoTable forward declarations. , '.datatypes.link' # Type definition forward declarations. ### Read-only data. , '.strings' # String literals; literal nodes on the C++ backend. , '.valuesets' # Value sets. , '.primitives' # Primitive functions. , '.metadata' # Metadata definitions. ### Code. , '.stepfuncs' # Step function definitions. ### Object definitions. , '.infotabs' # InfoTable definitions. , '.datatypes' # Type definitions. , '.moduledef' # Module definition. , '.moduleimp' # Module import. ### , '.footer' ) def __init__(self, codetype, unitname): self.codetype = codetype self.unitname = unitname self.sections = collections.defaultdict(list) # {str: [str]} self.symtab = SymbolTable() def __getitem__(self, sectname): assert sectname in self.SECTIONS return self.sections[sectname] def __repr__(self): return '<%r TargetObject for %r>' % (self.codetype, self.unitname)
[docs] class CompilerBase(abc.ABC): # Customization points. CODE_TYPE = None EXCLUDED_METADATA = None # The nesting at which a subexpression is hoisted into a temporary of the # step function (see ``hoist``), or None for no hoisting. HOIST_DEPTH = None
[docs] def vGetSymbolName(self, iobj, kind): return mangle(iobj.splitname(), kind)
locals().update({ methname: abc.abstractmethod(lambda *args: None) for methname in [ 'vEmitHeader' , 'vEmitFooter' , 'vEmitImported' , 'vEmitStepfuncLink' , 'vEmitInfotabLink' , 'vEmitDataTypeLink' , 'vEmitStepfuncHeader' , 'vEmitStepfuncEntry' , 'vEmitSynthesizedStepfunc' , 'vEmitFunctionInfotab' , 'vEmitConstructorInfotab' , 'vEmitDataType' , 'vEmitStringLiteral' , 'vEmitValueSetLiteral' , 'vEmitMetadata' , 'vEmitModuleDefinition' , 'vEmitModuleImport' , 'vEmit_compileS_IVarDecl' , 'vEmit_compileS_IFreeDecl' , 'vEmit_compileS_IVarAssign' , 'vEmit_compileS_INodeAssign' , 'vEmit_compileS_IExempt' , 'vEmit_compileS_IReturn' , 'vEmit_compileS_ICaseCons' , 'vEmit_compileS_ICaseLit' , 'vEmit_compileE_IVar' , 'vEmit_compileE_IVarAccess' , 'vEmit_compileE_ILiteral' , 'vEmit_compileE_IString' , 'vEmit_compileE_IUnboxedLiteral' , 'vEmit_compileE_ICall' , 'vEmit_compileE_IPartialCall' , 'vEmit_compileE_IOr' , 'vIsBuiltin' , 'vIsSynthesized' , 'vBackendFunctionKey' ] }) @formatDocstring(config.python_package_name()) def __init__(self, interp, iroot): ''' Compiles ICurry to a C++ target object. Args: interp: The interpreter that owns this module. iroot: The ICurry object to compile. Must be an IModule or IFunction. ''' self.interp = interp self.iroot = iroot self.target_object = TargetObject(self.CODE_TYPE, iroot.fullname) self.counts = collections.defaultdict(itertools.count) self.intern_store = {} self._is_external_check = is_external_check(iroot) # The lines hoisted out of the statement under compilation (see # ``hoisting``), the nesting of the expression under compilation, and # the count of the temporaries made so far. self.hoisted = None self.expr_depth = 0 self.hoist_count = 0 @property def root_isa_module(self): return isinstance(self.iroot, icurry.IModule)
[docs] def isExternal(self, iobj): if self.iroot.modulename != iobj.modulename: return True else: return self._is_external_check(iobj)
[docs] def next_private_symbolname(self, kind, suffix=None): i = next(self.counts[kind]) if suffix is None: return mangle(['_%s' % i], kind) else: return mangle(['_%s' % i, suffix], kind)
### importSymbol @visitation.dispatch.on('symbol') def importSymbol(self, symbol): '''Import a symbol into the taget object by name.''' assert False @importSymbol.when(str) def importSymbol(self, symbolname): cy_symbol = self.interp.symbol(symbolname) return self.importSymbol(cy_symbol.icurry)
[docs] @importSymbol.when(icurry.ISymbol) def importSymbol(self, isymbol): h_info, new = self.declareSymbol(isymbol) return h_info
### declareSymbol
[docs] def declareSymbol(self, isymbol): h_info = self.vGetSymbolName(isymbol, INFO_TABLE) new = self.symtab.insert(h_info, INFO_TABLE, 'info table for %r' % isymbol.fullname) if new: self.target_object['.infotabs.link'].extend(self.vEmitInfotabLink(isymbol, h_info)) return h_info, new
### importDataType @visitation.dispatch.on('symbol') def importDataType(self, symbol): '''Import a symbol into the taget object by name.''' assert False @importDataType.when(str) def importDataType(self, symbolname): cy_datatype = self.interp.type(symbolname) return self.importDataType(cy_datatype.icurry)
[docs] @importDataType.when(icurry.ISymbol) def importDataType(self, itype): h_datatype, new = self.declareDataType(itype) return h_datatype
### declareDataType
[docs] def declareDataType(self, itype): h_datatype = self.vGetSymbolName(itype, DATA_TYPE) new = self.symtab.insert(h_datatype, DATA_TYPE, 'datatype %r' % itype.fullname) if new: self.target_object['.datatypes.link'].extend(self.vEmitDataTypeLink(itype, h_datatype)) return h_datatype, new
[docs] def internStringLiteral(self, string): key = STRING_DATA, string existing = self.intern_store.get(key) if existing is not None: return existing else: h_string = self.next_private_symbolname(STRING_DATA) self.symtab.insert(h_string, STRING_DATA, '<string data: %r>' % string) prog_text = self.vEmitStringLiteral(string, h_string) self.target_object['.strings'].extend(prog_text) self.symtab.make_defined(h_string) self.intern_store[key] = h_string return h_string
[docs] def internValueSetLiteral(self, values): key = VALUE_SET, values existing = self.intern_store.get(key) if existing is not None: return existing else: h_valueset_data = self.next_private_symbolname(VALUE_SET_DATA) self.symtab.insert(h_valueset_data, VALUE_SET_DATA, '<case value array: %r>' % (values,)) h_valueset = self.next_private_symbolname(VALUE_SET) self.symtab.insert(h_valueset, VALUE_SET, '<case values: %r>' % (values,)) prog_text = self.vEmitValueSetLiteral(values, h_valueset, h_valueset_data) self.target_object['.valuesets'].extend(prog_text) self.symtab.make_defined(h_valueset) self.symtab.make_defined(h_valueset_data) self.intern_store[key] = h_valueset return h_valueset
[docs] def internBackendFunction(self, func): key = BUILTIN_FUNCTION, self.vBackendFunctionKey(func) existing = self.intern_store.get(key) if existing is not None: return existing else: h_func = self.next_private_symbolname(BUILTIN_FUNCTION, func.__name__) self.symtab.insert(h_func, BUILTIN_FUNCTION, '<function: %r>' % func) prog_text = self.vEmitImportBackendFunction(func, h_func) self.target_object['.primitives'].extend(prog_text) self.symtab.make_defined(h_func) self.intern_store[key] = h_func return h_func
[docs] def internMetadata(self, metadata): metadata = getattr(metadata, '_asdict', metadata) if self.EXCLUDED_METADATA: metadata = { k:v for k,v in metadata.items() if k not in self.EXCLUDED_METADATA } prefixes = 'all.', self.interp.backend.backend_name + '.' relevant_keys = tuple( k for k in sorted(metadata.keys()) if any(k.startswith(prefix) for prefix in prefixes) ) key = tuple((k, metadata[k]) for k in relevant_keys) key = METADATA, key existing = self.intern_store.get(key) if existing is not None: return existing else: h_md = self.next_private_symbolname(METADATA) self.symtab.insert(h_md, METADATA, '<metadata>') metadata_reduced = { k:v for k,v in metadata.items() if k in relevant_keys } md_def = self.vEmitMetadata(metadata_reduced, h_md) self.target_object['.metadata'].extend(md_def) self.symtab.make_defined(h_md) self.intern_store[key] = h_md return h_md
@property def symtab(self): return self.target_object.symtab
[docs] def compile(self): ''' Performs compilation. Returns: A target object containing the generated object code. ''' self.target_object['.header'].extend(self.vEmitHeader()) with maxrecursion(): self.compileEx(self.iroot) self.target_object['.footer'].extend(self.vEmitFooter()) return self.target_object
@visitation.dispatch.on('icy') def compileEx(self, icy): ''' Compiles an ICurry object. Updates the TargetObject and returns a new ICurry 'interface' object in which each function body has been replaced with IMaterial. Args: ``icy`` An IPackage, IModule, or IFunction to compile. Returns: The ICurry interface. ''' raise TypeError('Cannot compile type %r' % type(icy).__name__) @compileEx.when(icurry.IModule) def compileEx(self, imodule): imported_names = set(imodule.imports) for imported in sorted(imported_names): self.target_object['.imports'].extend(self.vEmitImported(imported)) for itype in imodule.types.values(): self.compileEx(itype) for ifun in imodule.functions.values(): self.compileEx(ifun) h_module = self.vGetSymbolName(imodule, MODULE_DEF) self.symtab.insert(h_module, MODULE_DEF, 'module %r' % imodule.fullname) self.target_object['.moduledef'].extend( self.vEmitModuleDefinition(imodule, h_module) ) self.symtab.make_defined(h_module) self.target_object['.moduleimp'].extend( self.vEmitModuleImport(imodule, h_module) ) @compileEx.when(icurry.IFunction) def compileEx(self, ifun): if self.vIsBuiltin(ifun): h_info, new = self.declareSymbol(ifun) if new: self.target_object['.infotabs.link'].extend( self.vEmitInfotabLink(ifun, h_info) ) else: # Build the symbol and update the symbol table. h_stepfunc = self.vGetSymbolName(ifun, STEP_FUNCTION) self.symtab.insert( h_stepfunc, STEP_FUNCTION, 'step function for %r' % ifun.fullname ) self.target_object['.stepfuncs.link'].extend( self.vEmitStepfuncLink(ifun, h_stepfunc) ) # Append to section '.stepfuncs'. out = self.target_object['.stepfuncs'] if out: out.append('') out.extend(self.vEmitStepfuncHeader(ifun, h_stepfunc)) linesF = [] # the function body out.append(linesF) self.compileF(ifun, h_stepfunc, linesF) self.symtab.make_defined(h_stepfunc) # Emit the info table. h_info, _ = self.declareSymbol(ifun) self.target_object['.infotabs'].extend( self.vEmitFunctionInfotab(ifun, h_info, h_stepfunc) ) self.symtab.make_defined(h_info)
[docs] @compileEx.when(icurry.IDataType) def compileEx(self, itype): if self.vIsBuiltin(itype): h_type, new = self.declareDataType(itype) if new: self.target_object['.datatypes.link'].extend( self.vEmitDataTypeLink(itype, h_type) ) for ictor in itype.constructors: assert self.vIsBuiltin(ictor) h_info, new = self.declareSymbol(ictor) if new: self.target_object['.infotabs.link'].extend( self.vEmitInfotabLink(ictor, h_info) ) else: h_datatype, _ = self.declareDataType(itype) ctor_handles = [] for ictor in itype.constructors: h_ctorinfo, new = self.declareSymbol(ictor) assert new ctor_handles.append(h_ctorinfo) self.target_object['.infotabs'].extend( self.vEmitConstructorInfotab(ictor, h_ctorinfo, h_datatype) ) self.symtab.make_defined(h_ctorinfo) self.target_object['.datatypes'].extend( self.vEmitDataType(itype, h_datatype, ctor_handles) ) self.symtab.make_defined(h_datatype)
################ ### compileF ### ################ @visitation.dispatch.on('iobj') def compileF(self, iobj, h_stepfunc, linesF): assert False @compileF.when(collections.abc.Sequence, no=str) def compileF(self, seq, h_stepfunc, linesF): for x in seq: self.compileF(x, h_stepfunc, linesF) @compileF.when(icurry.IFunction) def compileF(self, ifun, h_stepfunc, linesF): if self.vIsSynthesized(ifun): linesF.extend(self.vEmitSynthesizedStepfunc(ifun, h_stepfunc)) else: try: return self.compileF(ifun.body, h_stepfunc, linesF) except CompileError as e: raise CompileError( 'failed to compile function %r: %s' % (ifun.fullname, e) ) @compileF.when(icurry.IExternal) def compileF(self, iexternal, h_stepfunc, linesF): msg = 'external function %r is not defined' % iexternal.symbolname logger.warning(msg) stmt = icurry.IReturn(icurry.IFCall('Prelude.prim_error', [msg])) body = icurry.IBody(stmt) self.compileF(body, h_stepfunc, linesF) @compileF.when(icurry.IBody) def compileF(self, ibody, h_stepfunc, linesF): linesF.extend(self.vEmitStepfuncEntry()) linesF.extend(self.compileS(ibody.block))
[docs] @compileF.when(icurry.IStatement) def compileF(self, stmt, h_stepfunc, linesF): linesS = list(self.compileS(stmt)) linesF.append(linesS)
################ ### compileS ### ################ @visitation.dispatch.on('stmt') def compileS(self, stmt): ''' Compile a statement into nested lists of target code lines. ''' assert False @compileS.when(collections.abc.Sequence, no=str) def compileS(self, seq): for lines in (self.compileS(x) for x in seq): for line in lines: yield line @compileS.when(icurry.IVarDecl) def compileS(self, vardecl): varname = self.compileE(vardecl.lhs) return self.vEmit_compileS_IVarDecl(vardecl, varname) @compileS.when(icurry.IFreeDecl) def compileS(self, vardecl): varname = self.compileE(vardecl.lhs) return self.vEmit_compileS_IFreeDecl(vardecl, varname) @compileS.when(icurry.IVarAssign) def compileS(self, assign): with self.hoisting() as hoisted: lhs = self.compileE(assign.lhs, primary=True) rhs = self.compileE(assign.rhs, primary=True) return itertools.chain(hoisted, self.vEmit_compileS_IVarAssign(assign, lhs, rhs)) @compileS.when(icurry.INodeAssign) def compileS(self, assign): with self.hoisting() as hoisted: lhs = self.compileE(assign.lhs) rhs = self.compileE(assign.rhs, primary=True) return itertools.chain(hoisted, self.vEmit_compileS_INodeAssign(assign, lhs, rhs)) @compileS.when(icurry.IBlock) def compileS(self, block): for sect in [block.vardecls, block.assigns, block.stmt]: for line in self.compileS(sect): yield line @compileS.when(icurry.IExempt) def compileS(self, exempt): return self.vEmit_compileS_IExempt(exempt) @compileS.when(icurry.IReturn) def compileS(self, iret): primary = isinstance(iret.expr, icurry.IReference) with self.hoisting() as hoisted: expr = self.compileE(iret.expr, primary=primary) return itertools.chain(hoisted, self.vEmit_compileS_IReturn(iret, expr))
[docs] @contextlib.contextmanager def hoisting(self): ''' Collects the lines hoisted out of the statement compiled inside the context (see ``hoist``): a list, complete when the context ends, that the caller emits before the statement. ''' saved = self.hoisted, self.expr_depth self.hoisted, self.expr_depth = [], 0 try: yield self.hoisted finally: self.hoisted, self.expr_depth = saved
[docs] def compileArgs(self, exprs): '''The arguments of a node as primary expressions, one level down.''' return trampoline(self._compileArgs(exprs))
def _compileArgs(self, exprs): ''' The walk of compileArgs (see compileE). The nesting is counted while the arguments are compiled; a walk that fails leaves the compiler, so no finally clause restores it. ''' self.expr_depth += 1 args = [] for expr in exprs: args.append((yield self._compileE(expr, primary=True))) self.expr_depth -= 1 return args
[docs] def hoist(self, text, primary): ''' The text of a primary node, or the name of a temporary that holds it. A backend with ``HOIST_DEPTH`` moves a node at that nesting under the statement, and at every multiple of it, into a temporary assigned before the statement (``vEmitHoisted``), so the nesting of the generated text stays bounded whatever the depth of the expression. The Python backend needs it: the parser of Python refuses more than 200 nested parentheses, and a literal list of 1200 elements is one nested call (issue #125). ''' limit = self.HOIST_DEPTH if limit is None or not primary or self.hoisted is None \ or self.expr_depth == 0 or self.expr_depth % limit: return text name = '_h%d' % self.hoist_count self.hoist_count += 1 self.hoisted.extend(self.vEmitHoisted(name, text)) return name
[docs] def vEmitHoisted(self, name, text): '''The lines that assign the hoisted text to the temporary ``name``.''' raise NotImplementedError('the %s backend hoists no subexpression' % self.CODE_TYPE)
@compileS.when(icurry.ICaseCons) def compileS(self, icase): assert icase.branches cy_ctorobj = self.interp.symbol(icase.branches[0].symbolname) h_datatype = self.importDataType(cy_ctorobj.typename) varident = self.compileE(icase.var) return self.vEmit_compileS_ICaseCons(icase, h_datatype, varident)
[docs] @compileS.when(icurry.ICaseLit) def compileS(self, icase): h_sel = self.compileE(icase.var) values = tuple(branch.lit.value for branch in icase.branches) h_values = self.internValueSetLiteral(values) return self.vEmit_compileS_ICaseLit(icase, h_sel, h_values)
################ ### compileE ### ################
[docs] def compileE(self, expr, primary=False): ''' Compile an expression into a string. For primary expressions, the string evaluates to a value (boxed or unboxed). For non-primary expressions, it contains comma-separated arguments that may be passed to the Node constructor or Node->forward_to. The walk runs on the trampoline (utility.trampoline): the case of a node with arguments is a generator that yields the walk of each argument, so the depth of the expression costs no frame of Python. A nested call per level ran out of frames at about 4000 elements of a literal list under maxrecursion (issue #125). The symbols are imported in the order of the recursive walk: the node's own before those of its arguments. ''' return trampoline(self._compileE(expr, primary))
@visitation.dispatch.on('expr') def _compileE(self, expr, primary=False): '''The walk of compileE: a result for a leaf, a generator for a node.''' assert False @_compileE.when(icurry.IVar) def _compileE(self, ivar, primary=False): return self.vEmit_compileE_IVar(ivar) @_compileE.when(icurry.IVarAccess) def _compileE(self, ivaraccess, primary=False): var = self.compileE(ivaraccess.var, primary=primary) return self.vEmit_compileE_IVarAccess(ivaraccess, var) @_compileE.when(icurry.ILiteral) def _compileE(self, iliteral, primary=False): h_ctor = self.importSymbol(iliteral.fullname) return self.vEmit_compileE_ILiteral(iliteral, h_ctor, primary) @_compileE.when(icurry.IString) def _compileE(self, istring, primary=False): string = strings.ensure_str(istring.value) h_string = self.internStringLiteral(string) return self.vEmit_compileE_IString(istring, h_string, primary) @_compileE.when(icurry.IUnboxedLiteral) def _compileE(self, iunboxed, primary=False): return self.vEmit_compileE_IUnboxedLiteral(iunboxed, primary) @_compileE.when(icurry.ILit) def _compileE(self, ilit, primary=False): return self.compileE(ilit.lit, primary) @_compileE.when(icurry.ICall) def _compileE(self, icall, primary=False): h_info = self.importSymbol(icall.symbolname) args = yield self._compileArgs(icall.exprs) text = self.vEmit_compileE_ICall(icall, h_info, args, primary) return self.hoist(text, primary) @_compileE.when(icurry.IPartialCall) def _compileE(self, ipcall, primary=False): h_info = self.importSymbol(ipcall.symbolname) args = yield self._compileArgs(ipcall.exprs) text = self.vEmit_compileE_IPartialCall(ipcall, h_info, args, primary) return self.hoist(text, primary) @_compileE.when(icurry.IOr) def _compileE(self, ior, primary=False): lhs, rhs = yield self._compileArgs([ior.lhs, ior.rhs]) text = self.vEmit_compileE_IOr(ior, lhs, rhs, primary) return self.hoist(text, primary)
@visitation.dispatch.on('iobj') def is_external_check(iobj): assert False @is_external_check.when(icurry.IModule) def is_external_check(imodule): @visitation.dispatch.on('iobj') def check(iobj): assert False @check.when((icurry.IDataType, icurry.IConstructor)) def check(iobj): _, _, name = iobj.typename.rpartition('.') return name not in imodule.types @check.when(icurry.IFunction) def check(ifun): return ifun.name not in imodule.functions return check @is_external_check.when(icurry.IFunction) def is_external_check(ifun): @visitation.dispatch.on('iobj') def check(iobj): assert False @check.when((icurry.IDataType, icurry.IConstructor)) def check(iobj): return True @check.when(icurry.IFunction) def check(ifun2): return ifun2.name != ifun.name return check