Source code for curry.toolchain.flat2icurry.casecompletion

'''
Case completion, the second pass.  It follows ``FlatCurry.CaseCompletion``
of the Curry package ``icurry``.

Every case over constructors is rewritten so that its branches follow the
constructor order of the data declaration.  A missing constructor ``c`` of
arity ``n`` gets the branch ``c 101 .. 100+n -> Prelude.failed``.  A case
over literals is left as it is.  The data declarations come from the module
and from the interfaces of its imports.
'''

from . import flatcurry as fc
from .errors import Flat2ICurryError
from ...utility.trampoline import trampoline

__all__ = ['complete_prog', 'complete_exp', 'failed_branch', 'type_of_constructor']

[docs] def type_of_constructor(datadecls, qn): '''The first data declaration that holds the constructor ``qn``.''' for decl in datadecls: for cname, _ in decl[1]: if cname == qn: return decl raise Flat2ICurryError("Type of constructor '%s' not found!" % qn[1])
[docs] def complete_prog(datadecls, prog): '''Completes every case in a program.''' return fc.Prog( prog.name, prog.imports, prog.types , [complete_fun(datadecls, fd) for fd in prog.functions], prog.operators )
def complete_fun(datadecls, fd): return fc.Func( fd.name, fd.arity, fd.visibility, fd.typeexpr, complete_rule(datadecls, fd.rule) ) def complete_rule(datadecls, rule): if isinstance(rule, fc.External): return rule return fc.Rule(rule.args, complete_exp(datadecls, rule.body))
[docs] def complete_exp(datadecls, e): ''' Completes every case in an expression. The walk runs on a stack of its own (:func:`utility.trampoline.trampoline`), so a nested application of any depth needs no recursion (issue #125). ''' return trampoline(_complete(datadecls, e))
def _complete(datadecls, e): if isinstance(e, (fc.Var, fc.Lit)): return e elif isinstance(e, fc.Comb): args = [] for arg in e.args: arg = yield _complete(datadecls, arg) args.append(arg) return fc.Comb(e.combtype, e.name, args) elif isinstance(e, fc.Let): bindings = [] for v, b in e.bindings: b = yield _complete(datadecls, b) bindings.append((v, b)) body = yield _complete(datadecls, e.body) return fc.Let(bindings, body) elif isinstance(e, fc.Free): body = yield _complete(datadecls, e.body) return fc.Free(e.vars, body) elif isinstance(e, fc.Or): lhs = yield _complete(datadecls, e.lhs) rhs = yield _complete(datadecls, e.rhs) return fc.Or(lhs, rhs) elif isinstance(e, fc.Typed): expr = yield _complete(datadecls, e.expr) return fc.Typed(expr, e.typeexpr) elif isinstance(e, fc.Case): ce = yield _complete(datadecls, e.scrutinee) cbrs = [] for br in e.branches: body = yield _complete(datadecls, br.body) cbrs.append(fc.Branch(br.pattern, body)) if not cbrs or isinstance(cbrs[0].pattern, fc.LPattern): return fc.Case(e.casetype, ce, cbrs) _, consdecls = type_of_constructor(datadecls, cbrs[0].pattern.name) sbrs = [branch_for_cons(cbrs, c, ar) for c, ar in consdecls] return fc.Case(e.casetype, ce, sbrs) raise TypeError('not an expression: %r' % (e,)) def branch_for_cons(branches, c, ar): for br in branches: if isinstance(br.pattern, fc.Pattern) and br.pattern.name == c: return br return failed_branch(c, ar)
[docs] def failed_branch(c, ar): '''The branch for a constructor the case does not mention.''' return fc.Branch( fc.Pattern(c, list(range(101, 101 + ar))) , fc.Comb(fc.FuncCall, fc.prelude('failed'), []) )