def tupleToList(cls, tp): if tp.isFinal: return Type(ErlType.generateListAnyType()) else: # preprocess unions if ErlType.isUnion(tp.typ): inner_types = cc.get_inner_types_from_union(tp.typ) isCnd = lambda x: ErlType.isTuple(x) or ErlType.isTupleDet(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: tp.typ = candidates[0] if ErlType.isTupleDet(tp.typ): ts = cc.get_inner_types_from_tupledet(tp.typ) sz = len(ts) tp.matchNTuple(sz) else: # TODO Log inconsistency pass # actual type elaborations if ErlType.isTuple(tp.typ): return Type(ErlType.generateListAnyType()) elif ErlType.isTupleDet(tp.typ): children = tp.getChildren() t = Type(ErlType.generateListAnyType()) for child in reversed(children): t = cls.makeCons(child, t) return t else: # TODO Log inconsistency (if is not any()) return Type(ErlType.generateListAnyType())
def pretty_type(d): if cc.is_type_any(d): return "any" if cc.is_type_atom(d): return "atom" if cc.is_type_atomlit(d): return pretty(cc.get_literal_from_atomlit(d)) if cc.is_type_float(d): return "float" if cc.is_type_integer(d): return "integer" if cc.is_type_integerlit(d): return pretty(cc.get_literal_from_integerlit(d)) if cc.is_type_list(d): return "[%s]" % pretty_type(cc.get_inner_type_from_list(d)) if cc.is_type_nil(d): return "[]" if cc.is_type_tuple(d): return "tuple" if cc.is_type_tupledet(d): return "{%s}" % ", ".join( map(pretty_type, cc.get_inner_types_from_tupledet(d))) if cc.is_type_union(d): return "|".join(map(pretty_type, cc.get_inner_types_from_union(d))) if cc.is_type_range(d): bs = cc.get_range_bounds_from_range(d) return "%s..%s" % (cc.get_lower_bound(bs), cc.get_upper_bound(bs)) if cc.is_type_generic_fun(d): return "fun()" if cc.is_type_complete_fun(d): args, ret = d["a"][:-1], d["a"][-1] args = cc.get_parameters_from_complete_fun(d) ret = cc.get_rettype_from_fun(d) return "fun(({}) -> {})".format(", ".join(map(pretty_type, args)), pretty_type(ret))
def revMatchCons(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) candidates = [tp for tp in inner_types if not ErlType.isNonemptyList(tp)] if len(candidates) > 0: cc.set_inner_types_to_union(self.typ, candidates) new_inner_types = cc.get_inner_types_from_union(self.typ) for tp in new_inner_types: if ErlType.isList(tp): ErlType.setNilType(tp) # actual type elaborations if ErlType.isList(self.typ): ErlType.setNilType(self.typ) self.isFinal = True
def matchCons(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): isL = lambda x: ErlType.isList(x) or ErlType.isNonemptyList(x) inner_types = cc.get_inner_types_from_union(self.typ) candidates = [tp for tp in inner_types if isL(tp)] if len(candidates) > 0: self.typ = candidates[0] else: # TODO Log inconsistency pass # actual type elaborations if ErlType.isList(self.typ): it = cc.get_inner_type_from_list(self.typ) h = Type(deepcopy(it)) t = Type(deepcopy(self.typ)) ErlType.setConsType(self.typ) self.isFinal = True self.children = [h, t] elif ErlType.isNonemptyList(self.typ): it = cc.get_inner_type_from_nonempty_list(self.typ) h = Type(deepcopy(it)) t = Type(ErlType.getListTypeFromNonemptyList(self.typ)) ErlType.setConsType(self.typ) self.isFinal = True self.children = [h, t] elif ErlType.isAny(self.typ): pass else: # TODO Log inconsistency pass
def pretty_type(d): if cc.is_type_any(d): return "any" if cc.is_type_atom(d): return "atom" if cc.is_type_atomlit(d): return pretty(cc.get_literal_from_atomlit(d)) if cc.is_type_float(d): return "float" if cc.is_type_integer(d): return "integer" if cc.is_type_integerlit(d): return pretty(cc.get_literal_from_integerlit(d)) if cc.is_type_list(d): return "[%s]" % pretty_type(cc.get_inner_type_from_list(d)) if cc.is_type_nil(d): return "[]" if cc.is_type_tuple(d): return "tuple" if cc.is_type_tupledet(d): return "{%s}" % ", ".join(map(pretty_type, cc.get_inner_types_from_tupledet(d))) if cc.is_type_union(d): return "|".join(map(pretty_type, cc.get_inner_types_from_union(d))) if cc.is_type_range(d): bs = cc.get_range_bounds_from_range(d) return "%s..%s" % (cc.get_lower_bound(bs), cc.get_upper_bound(bs)) if cc.is_type_generic_fun(d): return "fun()" if cc.is_type_complete_fun(d): args, ret = d["a"][:-1], d["a"][-1] args = cc.get_parameters_from_complete_fun(d) ret = cc.get_rettype_from_fun(d) return "fun(({}) -> {})".format(", ".join(map(pretty_type, args)), pretty_type(ret))
def unifyWithFloat(self, tp): if tp.isFloat(): return True if tp.isUnion(): isCnd = lambda x: ErlType.isFloat(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True return False
def unifyWithBitstring(self, tp): if tp.isBitstring(): # FIXME Have to check if m * n is compatible return True if tp.isUnion(): isCnd = lambda x: ErlType.isBitstring(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True return False
def matchNotList(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) isCnd = lambda x: not ErlType.isList(x) and not ErlType.isNil(x) and not ErlType.isNonemptyList(x) candidates = [tp for tp in inner_types if isCnd(tp)] if len(candidates) > 0: cc.set_inner_types_to_union(self.typ, candidates) else: # TODO Log inconsistency pass if ErlType.isList(self.typ) or ErlType.isNil(self.typ) or ErlType.isNonemptyList(self.typ): # TODO Log inconsistency pass
def unifyWithAtomLit(self, tp): if tp.isAtom(): return True if tp.isAtomLit(): return cc.get_literal_from_atomlit(self.typ) == cc.get_literal_from_atomlit(tp.typ) if tp.isUnion(): isCnd = lambda x: ErlType.isAtom(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True isCnd = lambda x: ErlType.isAtomLit(x) and cc.get_literal_from_atomlit(self.typ) == cc.get_literal_from_atomlit(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True return False
def notMatchTuple(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) isCnd = lambda x: not ErlType.isTupleDet(x) and not ErlType.isTuple(x) candidates = [tp for tp in inner_types if isCnd(tp)] if len(candidates) > 0: cc.set_inner_types_to_union(self.typ, candidates) else: # TODO Log inconsistency pass # actual type elaborations if ErlType.isTupleDet(self.typ) or ErlType.isTuple(self.typ): # TODO Log inconsistency pass
def matchNotNil(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) candidates = [tp for tp in inner_types if not ErlType.isNil(tp)] for cnd in candidates: if ErlType.isList(cnd): ErlType.setNonEmptyListType(cnd) if len(candidates) > 0: cc.set_inner_types_to_union(self.typ, candidates) else: # TODO Log inconsistency pass elif ErlType.isList(self.typ): self.matchCons()
def unifyWithAtom(self, tp): if tp.isAtom(): return True if tp.isAtomLit(): self.takenOverByType(tp) return True if tp.isUnion(): isCnd = lambda x: ErlType.isAtom(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True isCnd = lambda x: ErlType.isAtomLit(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: cc.set_inner_types_to_union(tp, candidates) self.takenOverByType(tp) return True return False
def unifyWithIntegerLit(self, tp): if tp.isInteger(): return True if tp.isIntegerLit(): return cc.get_literal_from_integerlit(self.typ) == cc.get_literal_from_integerlit(tp.typ) if tp.isUnion(): isCnd = lambda x: ErlType.isInteger(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True isCnd = lambda x: ErlType.isIntegerLit(x) and cc.get_literal_from_integerlit(self.typ) == cc.get_literal_from_integerlit(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True # FIXME Check for range properly isCnd = lambda x: ErlType.isRange(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True return False
def matchNil(self): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) isCnd = lambda x: ErlType.isList(x) or ErlType.isNil(x) candidates = [tp for tp in inner_types if isCnd(tp)] if len(candidates) > 0: self.typ = candidates[0] else: # TODO Log inconsistency pass # actual type elaborations if ErlType.isList(self.typ): ErlType.setNilType(self.typ) self.isFinal = True elif ErlType.isNil(self.typ): self.isFinal = True elif ErlType.isAny(self.typ): pass else: # TODO Log inconsistency pass
def unifyWithTuple(self, tp): if tp.isTuple(): return True if tp.isTupleDet(): self.takenOverByType(tp) return True if tp.isUnion(): isCnd = lambda x: ErlType.isTuple(x) inner_types = cc.get_inner_types_from_union(tp.typ) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: return True isCnd = lambda x: ErlType.isTupleDet(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: # FIXME Have to check specify the type with tupledet return True isCnd = lambda x: ErlType.isNTuple(x) candidates = [t for t in inner_types if isCnd(t)] if len(candidates) > 0: # FIXME Have to check specify the type with ntuple return True return False
def isFinalType(self, typ): if ErlType.isAny(typ): return True elif ErlType.isAtom(typ): return True elif ErlType.isAtomLit(typ): return True elif ErlType.isFloat(typ): return True elif ErlType.isInteger(typ): return True elif ErlType.isIntegerLit(typ): return True elif ErlType.isList(typ): return False elif ErlType.isNil(typ): return True elif ErlType.isTuple(typ): return True elif ErlType.isTupleDet(typ): return all(self.isFinalType(t) for t in cc.get_inner_types_from_tupledet(typ)) elif ErlType.isUnion(typ): return all(self.isFinalType(t) for t in cc.get_inner_types_from_union(typ)) elif ErlType.isRange(typ): return True elif ErlType.isNonemptyList(typ): return False elif ErlType.isBitstring(typ): return True elif ErlType.isCons(typ): return True elif ErlType.isNTuple(typ): return True elif ErlType.isGenericFun(typ): return True elif ErlType.isFun(typ): return True
def matchNTuple(self, sz): if not self.isFinal: # preprocess unions if ErlType.isUnion(self.typ): inner_types = cc.get_inner_types_from_union(self.typ) isCnd = lambda x: ErlType.isTuple(x) or (ErlType.isTupleDet(x) and len(cc.get_inner_types_from_tupledet(x)) == sz) candidates = [tp for tp in inner_types if isCnd(tp)] if len(candidates) > 0: self.typ = candidates[0] else: # TODO Log inconsistency pass # actual type elaborations if ErlType.isTuple(self.typ): pass elif ErlType.isTupleDet(self.typ) and len(cc.get_inner_types_from_tupledet(self.typ)) == sz: self.isFinal = True self.children = [Type(deepcopy(tp)) for tp in cc.get_inner_types_from_tupledet(self.typ)] ErlType.setNTupleType(self.typ, sz) elif ErlType.isAny(self.typ): pass else: # TODO Log inconsistency pass
def build_spec(self, spec, var): if cc.is_type_any(spec): return "true" elif cc.is_type_float(spec): return ["is-real", var] elif cc.is_type_integer(spec): return ["is-int", var] elif cc.is_type_list(spec): inner_spec = cc.get_inner_type_from_list(spec) name = self.fun_rec_tlist(inner_spec) return [ "and", ["is-list", var], [name, ["lv", var]], ] elif cc.is_type_nonempty_list(spec): inner_spec = cc.get_inner_type_from_nonempty_list(spec) name = self.fun_rec_tlist(inner_spec) return [ "and", ["is-list", var], ["is-tc", ["lv", var]], [name, ["lv", var]], ] elif cc.is_type_tupledet(spec): body = ["and", ["is-tuple", var]] tlist = ["tv", var] for inner_type in cc.get_inner_types_from_tupledet(spec): body.append(["is-tc", tlist]) body.append(self.build_spec(inner_type, ["th", tlist])) tlist = ["tt", tlist] body.append(["is-tn", tlist]) return body elif cc.is_type_tuple(spec): return ["is-tuple", var] elif cc.is_type_union(spec): ret = ["or"] for inner_type in cc.get_inner_types_from_union(spec): ret.append(self.build_spec(inner_type, var)) return ret elif cc.is_type_range(spec): ret = ["and", ["is-int", var]] limits = cc.get_range_bounds_from_range(spec) if cc.has_lower_bound(limits): ret.append( [">=", ["iv", var], build_int(cc.get_lower_bound(limits))]) if cc.has_upper_bound(limits): ret.append( ["<=", ["iv", var], build_int(cc.get_upper_bound(limits))]) return ret elif cc.is_type_atom(spec): return ["is-atom", var] elif cc.is_type_bitstring(spec): segment_size = cc.get_segment_size_from_bitstring(spec) m = int(segment_size.m) n = int(segment_size.n) slist = ["sv", var] axioms = ["and"] axioms.append(["is-str", var]) while m > 0: axioms.append(["is-sc", slist]) slist = ["st", slist] m -= 1 if n == 0: axioms.append(["is-sn", slist]) elif n > 1: axioms.append(SListSpec(slist, build_int(n), self)) return axioms elif cc.is_type_complete_fun(spec): # TODO if a function is to be called with wrong arguments, program must crash par_spec = cc.get_parameters_from_complete_fun(spec) ret_spec = cc.get_rettype_from_fun(spec) name = self.fun_rec_flist(par_spec, ret_spec) return [ "and", ["is-fun", var], ["=", ["fa", ["fv", var]], build_int(len(par_spec))], [name, ["fm", ["fv", var]]], ["not", ["=", ["fm", ["fv", var]], "fn"]] ] elif cc.is_type_generic_fun(spec): par_spec = None ret_spec = cc.get_rettype_from_fun(spec) name = self.fun_rec_flist(par_spec, ret_spec) return [ "and", ["is-fun", var], [name, ["fm", ["fv", var]]], ["not", ["=", ["fm", ["fv", var]], "fn"]] ] elif cc.is_type_atomlit(spec): return ["=", var, self.decode(cc.get_literal_from_atomlit(spec))] elif cc.is_type_integerlit(spec): return [ "=", var, self.decode(cc.get_literal_from_integerlit(spec)) ] elif cc.is_type_userdef(spec): type_name = cc.get_type_name_of_userdef(spec) return ["|{}|".format(type_name), var] clg.debug_info("unknown spec: " + str(spec)) assert False