예제 #1
0
파일: cuter_smt.py 프로젝트: uldza/cuter
	def decode(self, data, shared = None):
		"""
		Decode a term to its SMT representation.
		"""
		if cc.is_symb(data):
			s = "|{}|".format(cc.get_symb(data))
			if s not in self.vars and s not in self.aux_vars:
				self.aux_vars.append(s)
				self.commands.append(["declare-const", s, "Term"])
			return s
		elif cc.is_int(data):
			return ["int", build_int(cc.get_int(data))]
		elif cc.is_float(data):
			return ["real", build_real(cc.get_float(data))]
		elif cc.is_atom(data):
			return ["atom", build_ilist(cc.get_atom_chars(data))]
		elif cc.is_list(data):
			items = cc.get_list_subterms(data)
			if shared is None:
				shared = cc.get_shared(data)
			return ["list", build_tlist([self.decode(item, shared) for item in items])]
		elif cc.is_tuple(data):
			items = cc.get_tuple_subterms(data)
			if shared is None:
				shared = cc.get_shared(data)
			return ["tuple", build_tlist([self.decode(item, shared) for item in items])]
		elif cc.is_bitstring(data):
			return ["str", build_slist(cc.get_bits(data))]
		elif cc.is_alias(data):
			return self.decode(shared[cc.get_alias(data)], shared)
		clg.debug_info("decoding failed: " + str(data))
		assert False
예제 #2
0
    def solve(self):
        """
		Solve a constraint set and returns the result.
		"""
        status = self.solver.check_sat()
        if status == "sat":
            return cc.mk_sat()
        elif status == "unsat":
            self.solver.exit()
            return cc.mk_unsat()
        elif status == "unknown":
            return cc.mk_unknown()
        elif status == "timeout":
            return cc.mk_timeout()
        clg.debug_info("solve: " + str(status))
        assert False
예제 #3
0
 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
예제 #4
0
 def encode(self, data, funs=[]):
     # TODO description
     if data[0] == "int":
         return cc.mk_int(parse_int(data[1]))
     elif data[0] == "real":
         return cc.mk_float(parse_real(data[1]))
     elif data[0] == "atom":
         node = data[1]
         v = []
         while node != "in":
             v.append(parse_int(node[1]))
             node = node[2]
         return cc.mk_atom(v)
     elif data[0] == "list":
         node = data[1]
         v = []
         while node != "tn":
             v.append(self.encode(node[1], funs))
             node = node[2]
         return cc.mk_list(v)
     elif data[0] == "tuple":
         node = data[1]
         v = []
         while node != "tn":
             v.append(self.encode(node[1], funs))
             node = node[2]
         return cc.mk_tuple(v)
     elif data[0] == "str":
         node = data[1]
         v = []
         while node != "sn":
             v.append(node[1] == "true")
             node = node[2]
         return cc.mk_bitstring(v)
     elif data[0] == "fun":
         # TODO function decoding and encoding
         assert isinstance(data, list) and len(data) == 2
         fv = parse_int(data[1])
         # if a cycle (a function calling itself recursively) is found,
         # it is obvious that the solver has selected an arbitrary term as a value
         if fv in funs:
             return cc.mk_any()
         funs = funs[:]
         funs.append(fv)
         # get function info from solver
         # TODO save function arity and entries to an array
         val = self.solver.get_value(["fa", data[1]], ["fm", data[1]])
         assert isinstance(val, list) and len(val) == 2
         assert isinstance(val[0], list) and len(val[0]) == 2
         arity = parse_int(expand_lets(val[0][1]))
         # if arity is less than or greater than 255, we assume it is an arbitrary value selected by the solver
         # because there is no constraint limiting the function's arity; thus, we set it to zero
         if arity < 0 or arity > 255:
             arity = 0
         assert isinstance(val[1], list) and len(val[1]) == 2
         node = expand_lets(val[1][1])
         entries = []
         otherwise = None
         while node != "fn":
             assert isinstance(node,
                               list) and len(node) == 4 and node[0] == "fc"
             x = cc.get_list_subterms(self.encode(["list", node[1]], funs))
             # keep only entries with argument length equal to arity
             if len(x) == arity:
                 y = self.encode(node[2], funs)
                 if otherwise is None:
                     otherwise = y
                 else:
                     entries.append(cc.mk_fun_entry(x, y))
             node = node[3]
         if otherwise is None:
             otherwise = cc.mk_any()
         return cc.mk_fun(arity, entries, otherwise)
     clg.debug_info("encoding failed: " + str(data))
     assert False
예제 #5
0
    def command_toSolver(self, log_entry, rev):
        """
        Loads the recorded trace to memory.
        """
        opts_normal = {
            # Internal commands.
            LogEntry.OP_PARAMS: self.mfa_params,
            LogEntry.OP_SPEC: self.mfa_spec,
            LogEntry.OP_UNFOLD_TUPLE: self.unfold_tuple,
            LogEntry.OP_UNFOLD_LIST: self.unfold_list,
            LogEntry.OP_MAKE_BITSTR: self.make_bitstr,
            LogEntry.OP_CONCAT_SEGS: self.concat_segs,
            LogEntry.OP_FRESH_LAMBDA_WITH_ARITY: self.fresh_closure,
            LogEntry.OP_EVALUATED_CLOSURE: self.evaluated_closure,
            # Constraints.
            LogEntry.OP_GUARD_TRUE: self.guard_true,
            LogEntry.OP_GUARD_FALSE: self.guard_false,
            LogEntry.OP_MATCH_EQUAL_TRUE: self.match_equal,
            LogEntry.OP_MATCH_EQUAL_FALSE: self.match_not_equal,
            LogEntry.OP_TUPLE_SZ: self.tuple_sz,
            LogEntry.OP_TUPLE_NOT_SZ: self.tuple_not_sz,
            LogEntry.OP_TUPLE_NOT_TPL: self.tuple_not_tpl,
            LogEntry.OP_LIST_NON_EMPTY: self.list_nonempty,
            LogEntry.OP_LIST_EMPTY: self.list_empty,
            LogEntry.OP_LIST_NOT_LST: self.list_not_lst,
            LogEntry.OP_EMPTY_BITSTR: self.empty_bitstr,
            LogEntry.OP_NONEMPTY_BITSTR: self.nonempty_bitstr,
            LogEntry.OP_BITMATCH_CONST_TRUE: self.bitmatch_const_true,
            LogEntry.OP_BITMATCH_CONST_FALSE: self.bitmatch_const_false,
            LogEntry.OP_BITMATCH_VAR_TRUE: self.bitmatch_var_true,
            LogEntry.OP_BITMATCH_VAR_FALSE: self.bitmatch_var_false,
            LogEntry.OP_LAMBDA: self.erl_lambda,
            # Erlang BIFs or MFAs treated as BIFs.
            LogEntry.OP_HD: self.head,
            LogEntry.OP_TL: self.tail,
            LogEntry.OP_IS_INTEGER: self.is_integer,
            LogEntry.OP_IS_ATOM: self.is_atom,
            LogEntry.OP_IS_FLOAT: self.is_float,
            LogEntry.OP_IS_LIST: self.is_list,
            LogEntry.OP_IS_TUPLE: self.is_tuple,
            LogEntry.OP_IS_BOOLEAN: self.is_boolean,
            LogEntry.OP_IS_NUMBER: self.is_number,
            LogEntry.OP_PLUS: self.plus,
            LogEntry.OP_MINUS: self.minus,
            LogEntry.OP_TIMES: self.times,
            LogEntry.OP_RDIV: self.rdiv,
            LogEntry.OP_IDIV_NAT: self.idiv_nat,
            LogEntry.OP_REM_NAT: self.rem_nat,
            LogEntry.OP_UNARY: self.unary,
            LogEntry.OP_EQUAL: self.equal,
            LogEntry.OP_UNEQUAL: self.unequal,
            LogEntry.OP_FLOAT: self.to_float,
            LogEntry.OP_BOGUS: self.bogus,
            LogEntry.OP_ATOM_NIL: self.atom_nil,
            LogEntry.OP_ATOM_HEAD: self.atom_head,
            LogEntry.OP_ATOM_TAIL: self.atom_tail,
            LogEntry.OP_LIST_TO_TUPLE: self.list_to_tuple,
            LogEntry.OP_TUPLE_TO_LIST: self.tuple_to_list,
            LogEntry.OP_LT_INT: self.lt_integers,
            LogEntry.OP_LT_FLOAT: self.lt_floats,
            LogEntry.OP_CONS: self.cons,
            LogEntry.OP_TCONS: self.tcons,
            LogEntry.OP_POW: self.pow,
            LogEntry.OP_IS_BITSTRING: self.is_bitstring,
            LogEntry.OP_IS_FUN: self.is_fun,
            LogEntry.OP_IS_FUN_WITH_ARITY: self.is_fun_with_arity,
            LogEntry.OP_TRUNC: self.trunc,
            LogEntry.OP_BAND: self.band,
            LogEntry.OP_BXOR: self.bxor,
            LogEntry.OP_BOR: self.bor
        }

        opts_rev = {
            # Constraints.
            LogEntry.OP_GUARD_TRUE: self.guard_true_reversed,
            LogEntry.OP_GUARD_FALSE: self.guard_false_reversed,
            LogEntry.OP_MATCH_EQUAL_TRUE: self.match_equal_reversed,
            LogEntry.OP_MATCH_EQUAL_FALSE: self.match_not_equal_reversed,
            LogEntry.OP_TUPLE_SZ: self.tuple_sz_reversed,
            LogEntry.OP_TUPLE_NOT_SZ: self.tuple_not_sz_reversed,
            LogEntry.OP_TUPLE_NOT_TPL: self.tuple_not_tpl_reversed,
            LogEntry.OP_LIST_NON_EMPTY: self.list_nonempty_reversed,
            LogEntry.OP_LIST_EMPTY: self.list_empty_reversed,
            LogEntry.OP_LIST_NOT_LST: self.list_not_lst_reversed,
            LogEntry.OP_EMPTY_BITSTR: self.empty_bitstr_reversed,
            LogEntry.OP_NONEMPTY_BITSTR: self.nonempty_bitstr_reversed,
            LogEntry.OP_BITMATCH_CONST_TRUE: self.bitmatch_const_true_reversed,
            LogEntry.OP_BITMATCH_CONST_FALSE: self.bitmatch_const_false_reversed,
            LogEntry.OP_BITMATCH_VAR_TRUE: self.bitmatch_var_true_reversed,
            LogEntry.OP_BITMATCH_VAR_FALSE: self.bitmatch_var_false_reversed,
            LogEntry.OP_NOT_LAMBDA_WITH_ARITY: self.not_lambda_with_arity_reversed,
            LogEntry.OP_LAMBDA: self.erl_lambda_reversed,
            # Erlang BIFs or MFAs treated as BIFs.
            LogEntry.OP_HD: self.head_reversed,
            LogEntry.OP_TL: self.tail_reversed
        }

        # Call the appropriate function with the given payload.
        opts = opts_rev if rev else opts_normal
        if log_entry.type not in opts:
            fmt = ("Unknown JSON Command with\n"
                   "  Data: {}\n"
                   "  Rev: {}")
            clg.debug_info(fmt.format(str(log_entry), rev))
        args = [log_entry.spec] if log_entry.type == LogEntry.OP_SPEC else log_entry.arguments
        opts[log_entry.type](*args)