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
@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