Example #1
0
def pull_temps(s: Stm, decls_out: [SDecl], exp_is_bad) -> Stm:
    def pull(e: Exp) -> Exp:
        if exp_is_bad(e):
            v = fresh_var(e.type)
            decls_out.append(SDecl(v.id, e))
            return v
        return e

    if isinstance(s, SNoOp):
        return s
    if isinstance(s, SSeq):
        s1 = pull_temps(s.s1, decls_out, exp_is_bad)
        s2 = pull_temps(s.s2, decls_out, exp_is_bad)
        return SSeq(s1, s2)
    if isinstance(s, SIf):
        cond = pull(s.cond)
        s1 = pull_temps(s.then_branch, decls_out, exp_is_bad)
        s2 = pull_temps(s.else_branch, decls_out, exp_is_bad)
        return SIf(cond, s1, s2)
    if isinstance(s, SForEach):
        bag = pull(s.iter)
        d_tmp = []
        body = pull_temps(s.body, d_tmp, exp_is_bad)
        to_fix, ok = partition(d_tmp, lambda d: s.id in free_vars(d.val))
        decls_out.extend(ok)
        for d in to_fix:
            v = EVar(d.id).with_type(d.val.type)
            mt = TMap(s.id.type, v.type)
            m = EMakeMap2(bag, ELambda(s.id, d.val)).with_type(mt)
            mv = fresh_var(m.type)
            md = SDecl(mv.id, m)
            decls_out.append(md)
            body = subst(body, {v.id: EMapGet(mv, s.id).with_type(v.type)})
        return SForEach(s.id, bag, body)
    if isinstance(s, SAssign):
        return SAssign(s.lhs, pull(s.rhs))
    if isinstance(s, SCall):
        return SCall(s.target, s.func, tuple(pull(arg) for arg in s.args))
    if isinstance(s, SMapDel):
        return SMapDel(s.map, pull(s.key))
    if isinstance(s, SMapPut):
        return SMapPut(s.map, pull(s.key), pull(s.value))
    if isinstance(s, SMapUpdate):
        key = pull(s.key)
        d_tmp = []
        change = pull_temps(s.change, d_tmp, exp_is_bad)
        for d in d_tmp:
            if s.val_var in free_vars(d.val):
                decls_out.append(
                    SDecl(
                        d.id,
                        subst(
                            d.val, {
                                s.val_var.id:
                                EMapGet(s.map, key).with_type(s.val_var.type)
                            })))
            else:
                decls_out.append(d)
        return SMapUpdate(s.map, key, s.val_var, change)
    raise NotImplementedError(s)
Example #2
0
File: core.py Project: uwplse/cozy
def can_elim_vars(spec : Exp, assumptions : Exp, vs : [EVar]):
    """Does any execution of `spec` actually depend on any of `vs`?

    It is possible for a variable to appear in an expression like `spec`
    without affecting its value.  This function uses the solver to
    determine whether any of the given variables can affect the output of
    `spec`.
    """
    spec = strip_EStateVar(spec)
    sub = { v.id : fresh_var(v.type) for v in vs }
    return valid(EImplies(
        EAll([assumptions, subst(assumptions, sub)]),
        EEq(spec, subst(spec, sub))))
Example #3
0
def can_elim_vars(spec: Exp, assumptions: Exp, vs: [EVar]):
    """Does any execution of `spec` actually depend on any of `vs`?

    It is possible for a variable to appear in an expression like `spec`
    without affecting its value.  This function uses the solver to
    determine whether any of the given variables can affect the output of
    `spec`.
    """
    spec = strip_EStateVar(spec)
    sub = {v.id: fresh_var(v.type) for v in vs}
    return valid(
        EImplies(EAll([assumptions, subst(assumptions, sub)]),
                 EEq(spec, subst(spec, sub))))
Example #4
0
 def always(self, op, other, cards : Exp, **kwargs) -> bool:
     """
     Partial order on costs.
     """
     if isinstance(self.formula, ENum) and isinstance(other.formula, ENum):
         return eval(EBinOp(self.formula, op, other.formula).with_type(BOOL), env={})
     f = EImplies(cards, EBinOp(self.formula, op, other.formula).with_type(BOOL))
     if integer_cardinalities.value:
         try:
             return valid(f, logic="QF_LIA", timeout=1, **kwargs)
         except SolverReportedUnknown:
             # If we accidentally made an unsolveable integer arithmetic formula,
             # then try again with real numbers. This will admit some models that
             # are not possible (since bags must have integer cardinalities), but
             # returning false is always a safe move here, so it's fine.
             print("Warning: not able to solve {}".format(pprint(f)))
     f = subst(f, { v.id : EVar(v.id).with_type(REAL) for v in free_vars(cards) })
     # This timeout is dangerous! Sufficiently complex specifications
     # will cause this to timeout _every_time_, meaning we never make
     # progress.
     #   However, this timeout helps ensure liveness: the Python process
     # never gets deadlocked waiting for Z3. In the Distant Future it
     # would be nice to move away from Z3Py and invoke Z3 as a subprocess
     # instead. That would allow the Python process to break out if it is
     # asked to stop while Z3 is running. It would also give us added
     # protection against Z3 segfaults, which have been observed in the
     # wild from time to time.
     timeout = 60
     try:
         return valid(f, logic="QF_NRA", timeout=timeout, **kwargs)
     except SolverReportedUnknown:
         print("Giving up!")
         return False
Example #5
0
    def set_impl(self, q : Query, rep : [(EVar, Exp)], ret : Exp):
        with task("updating implementation", query=q.name):
            with task("finding duplicated state vars"):
                to_remove = set()
                for (v, e) in rep:
                    aeq = find_one(vv for (vv, ee) in self.concrete_state if e.type == ee.type and self.state_solver.valid(EImplies(EAll(self.spec.assumptions), EEq(e, ee))))
                    # aeq = find_one(vv for (vv, ee) in self.concrete_state if e.type == ee.type and alpha_equivalent(e, ee))
                    if aeq is not None:
                        event("state var {} is equivalent to {}".format(v.id, aeq.id))
                        ret = subst(ret, { v.id : aeq })
                        to_remove.add(v)
                rep = [ x for x in rep if x[0] not in to_remove ]

            self.concrete_state.extend(rep)
            self.query_impls[q.name] = rewrite_ret(q, lambda prev: ret, keep_assumptions=False)

            for op in self.op_specs:
                with task("incrementalizing query", query=q.name, op=op.name):
                    for new_member, projection in rep:
                        subqueries = []
                        state_update_stm = inc.mutate_in_place(
                            new_member,
                            projection,
                            op.body,
                            abstract_state=self.abstract_state,
                            assumptions=op.assumptions,
                            subgoals_out=subqueries)
                        for sub_q in subqueries:
                            sub_q.docstring = "[{}] {}".format(op.name, sub_q.docstring)
                            state_update_stm = self._add_subquery(sub_q=sub_q, used_by=state_update_stm)
                        self.updates[(new_member, op.name)] = state_update_stm
Example #6
0
 def adapt(self, e : Exp, ctx) -> Exp:
     if self == ctx:
         return e
     if self.alpha_equivalent(ctx):
         e = self._parent.adapt(e, ctx._parent)
         return subst(e, { ctx.var.id : self.var })
     return self._parent.adapt(e, ctx)
Example #7
0
def desugar(spec: Spec) -> Spec:

    # rewrite enums
    repl = {
        name: EEnumEntry(name).with_type(t)
        for t in all_types(spec) if isinstance(t, TEnum) for name in t.cases
    }
    spec = subst(spec, repl)

    # convert all collection types to bags
    spec = Spec(spec.name, list(spec.types), list(spec.extern_funcs),
                list(spec.statevars), list(spec.assumptions),
                list(spec.methods), spec.header, spec.footer, spec.docstring)

    for i in range(len(spec.statevars)):
        v, t = spec.statevars[i]
        if isinstance(t, TSet):
            # Sets become bags w/ implicit unique assumptions.
            t = TBag(t.t)
            spec.statevars[i] = (v, t)
            v = EVar(v).with_type(t)
            spec.assumptions.append(EUnaryOp(UOp.AreUnique, v).with_type(BOOL))

    assert retypecheck(spec, env={})

    # organize queries by name
    queries = {q.name: q for q in spec.methods if isinstance(q, Query)}

    class V(BottomUpRewriter):
        def visit_ECall(self, e):
            q = queries.get(e.func)
            if q is not None:
                return self.visit(
                    subst(
                        q.ret, {
                            arg_name: arg
                            for ((arg_name, ty), arg) in zip(q.args, e.args)
                        }))
            else:
                return ECall(e.func, tuple(self.visit(a)
                                           for a in e.args)).with_type(e.type)

    spec = V().visit(spec)
    spec.methods = [
        m for m in spec.methods
        if not (isinstance(m, Query) and m.visibility == Visibility.Private)
    ]

    class V(BottomUpRewriter):
        def visit_Exp(self, e):
            return desugar_list_comprehensions(e)

    spec = V().visit(spec)

    assert retypecheck(spec, env={})

    return spec
Example #8
0
File: subst.py Project: uwplse/cozy
    def test_no_argument_conflict_lambda(self):
        x = EVar("x").with_type(TInt())
        y = EVar("y").with_type(TInt())
        f = ELambda(x, EBinOp(y, "+", ENum(1).with_type(INT)))
        assert retypecheck(f)

        g = subst(f, { y.id : x })
        a = EVar("a").with_type(TInt())
        b = EVar("b").with_type(TInt())
        assert valid(EEq(g.apply_to(a), g.apply_to(b)))
Example #9
0
    def test_no_argument_conflict_lambda(self):
        x = EVar("x").with_type(TInt())
        y = EVar("y").with_type(TInt())
        f = ELambda(x, EBinOp(y, "+", ENum(1).with_type(INT)))
        assert retypecheck(f)

        g = subst(f, {y.id: x})
        a = EVar("a").with_type(TInt())
        b = EVar("b").with_type(TInt())
        assert valid(equal(g.apply_to(a), g.apply_to(b)))
Example #10
0
    def _setup_handle_updates(self):
        """
        This method creates update code for handle objects modified by each op.
        Must be called once after all user-specified queries have been added.
        """
        for op in self.op_specs:
            handles = reachable_handles_at_method(self.spec, op)
            # print("-"*60)
            for t, bag in handles.items():
                # print("  {} : {}".format(pprint(t), pprint(bag)))
                h = fresh_var(t)
                delta = inc.delta_form(
                    self.spec.statevars + op.args + [(h.id, h.type)], op)
                lval = EGetField(h, "val").with_type(t.value_type)
                new_val = simplify(subst(lval, delta))

                # get set of modified handles
                modified_handles = Query(
                    fresh_name("modified_handles"), Visibility.Internal, [],
                    op.assumptions,
                    EFilter(
                        EUnaryOp(UOp.Distinct, bag).with_type(bag.type),
                        ELambda(h, ENot(EEq(lval,
                                            new_val)))).with_type(bag.type),
                    "[{}] modified handles of type {}".format(
                        op.name, pprint(t)))
                query_vars = [
                    v for v in free_vars(modified_handles)
                    if v not in self.abstract_state
                ]
                modified_handles.args = [(arg.id, arg.type)
                                         for arg in query_vars]

                # modify each one
                (state_update_stm, subqueries) = inc.sketch_update(
                    lval, lval, new_val, self.abstract_state,
                    list(op.assumptions) +
                    [EDeepIn(h, bag),
                     EIn(h, modified_handles.ret)])
                # print("  got {} subqueries".format(len(subqueries)))
                # print("  to update {} in {}, use\n{}".format(pprint(t), op.name, pprint(state_update_stm)))
                for sub_q in subqueries:
                    sub_q.docstring = "[{}] {}".format(op.name,
                                                       sub_q.docstring)
                    state_update_stm = self._add_subquery(
                        sub_q=sub_q, used_by=state_update_stm)
                if state_update_stm != SNoOp():
                    state_update_stm = SForEach(
                        h,
                        ECall(modified_handles.name,
                              query_vars).with_type(bag.type),
                        state_update_stm)
                    state_update_stm = self._add_subquery(
                        sub_q=modified_handles, used_by=state_update_stm)
                self.handle_updates[(t, op.name)] = state_update_stm
Example #11
0
 def visit_ECall(self, e):
     q = queries.get(e.func)
     if q is not None:
         return self.visit(
             subst(
                 q.ret, {
                     arg_name: arg
                     for ((arg_name, ty), arg) in zip(q.args, e.args)
                 }))
     else:
         return ECall(e.func, tuple(self.visit(a)
                                    for a in e.args)).with_type(e.type)
Example #12
0
 def adapt(self, e : Exp, ctx, e_fvs=None) -> Exp:
     if self == ctx:
         return e
     if e_fvs is None:
         e_fvs = free_vars(e)
     if isinstance(ctx, UnderBinder):
         if ctx.var not in e_fvs:
             return self.adapt(e, ctx.parent(), e_fvs=e_fvs)
         if alpha_equivalent(self.bag, self._parent.adapt(ctx.bag, ctx._parent)):
             e = self._parent.adapt(e, ctx._parent, e_fvs=e_fvs)
             return subst(e, { ctx.var.id : self.var })
     return self._parent.adapt(e, ctx, e_fvs=e_fvs)
Example #13
0
def mutate(e: syntax.Exp, op: syntax.Stm) -> syntax.Exp:
    """Return the new value of `e` after executing `op`."""
    if isinstance(op, syntax.SNoOp):
        return e
    elif isinstance(op, syntax.SAssign):
        return _do_assignment(op.lhs, op.rhs, e)
    elif isinstance(op, syntax.SCall):
        if op.func == "add":
            return mutate(
                e,
                syntax.SCall(op.target, "add_all", (syntax.ESingleton(
                    op.args[0]).with_type(op.target.type), )))
        elif op.func == "add_all":
            return mutate(
                e,
                syntax.SAssign(
                    op.target,
                    syntax.EBinOp(op.target, "+",
                                  op.args[0]).with_type(op.target.type)))
        elif op.func == "remove":
            return mutate(
                e,
                syntax.SCall(op.target, "remove_all", (syntax.ESingleton(
                    op.args[0]).with_type(op.target.type), )))
        elif op.func == "remove_all":
            return mutate(
                e,
                syntax.SAssign(
                    op.target,
                    syntax.EBinOp(op.target, "-",
                                  op.args[0]).with_type(op.target.type)))
        else:
            raise Exception("Unknown func: {}".format(op.func))
    elif isinstance(op, syntax.SIf):
        then_branch = mutate(e, op.then_branch)
        else_branch = mutate(e, op.else_branch)
        if alpha_equivalent(then_branch, else_branch):
            return then_branch
        return syntax.ECond(op.cond, then_branch,
                            else_branch).with_type(e.type)
    elif isinstance(op, syntax.SSeq):
        if isinstance(op.s1, syntax.SSeq):
            return mutate(e, syntax.SSeq(op.s1.s1,
                                         syntax.SSeq(op.s1.s2, op.s2)))
        e2 = mutate(mutate(e, op.s2), op.s1)
        if isinstance(op.s1, syntax.SDecl):
            e2 = subst(e2, {op.s1.id: op.s1.val})
        return e2
    elif isinstance(op, syntax.SDecl):
        return e
    else:
        raise NotImplementedError(type(op))
Example #14
0
    def set_impl(self, q: Query, rep: [(EVar, Exp)], ret: Exp):
        to_remove = set()
        from cozy.solver import valid
        for (v, e) in rep:
            aeq = find_one(
                vv for (vv, ee) in self.concrete_state if e.type == ee.type
                and valid(EImplies(EAll(self.spec.assumptions), EEq(e, ee))))
            # aeq = find_one(vv for (vv, ee) in self.concrete_state if e.type == ee.type and alpha_equivalent(e, ee))
            if aeq is not None:
                print("########### state var {} is equivalent to {}".format(
                    v.id, aeq.id))
                ret = subst(ret, {v.id: aeq})
                to_remove.add(v)
        rep = [x for x in rep if x[0] not in to_remove]

        self.concrete_state.extend(rep)
        self.query_impls[q.name] = rewrite_ret(q,
                                               lambda prev: ret,
                                               keep_assumptions=False)
        op_deltas = {
            op.name: inc.delta_form(self.spec.statevars, op)
            for op in self.op_specs
        }

        for op in self.op_specs:
            # print("###### INCREMENTALIZING: {}".format(op.name))
            delta = op_deltas[op.name]
            for new_member, projection in rep:
                (state_update_stm,
                 subqueries) = inc.sketch_update(new_member, projection,
                                                 subst(projection, delta),
                                                 self.abstract_state,
                                                 list(op.assumptions))
                for sub_q in subqueries:
                    sub_q.docstring = "[{}] {}".format(op.name,
                                                       sub_q.docstring)
                    state_update_stm = self._add_subquery(
                        sub_q=sub_q, used_by=state_update_stm)
                self.updates[(new_member, op.name)] = state_update_stm
Example #15
0
 def adapt(self, e: Exp, ctx, e_fvs=None) -> Exp:
     if self == ctx:
         return e
     if e_fvs is None:
         e_fvs = free_vars(e)
     if isinstance(ctx, UnderBinder):
         if ctx.var not in e_fvs:
             return self.adapt(e, ctx.parent(), e_fvs=e_fvs)
         if alpha_equivalent(self.bag,
                             self._parent.adapt(ctx.bag, ctx._parent)):
             e = self._parent.adapt(e, ctx._parent, e_fvs=e_fvs)
             return subst(e, {ctx.var.id: self.var})
     return self._parent.adapt(e, ctx, e_fvs=e_fvs)
Example #16
0
    def set_impl(self, q: Query, rep: [(EVar, Exp)], ret: Exp):
        """Update the implementation of a query.

        The query having the same name as `q` will have its implementation
        replaced by the given concrete representation and computation.

        This call may add additional "subqueries" to the implementation to
        maintain the new representation when each update operation is called.
        """
        with task("updating implementation", query=q.name):
            with task("finding duplicated state vars"):
                to_remove = set()
                for (v, e) in rep:
                    aeq = find_one(vv
                                   for (vv,
                                        ee) in self._concretization_functions
                                   if e.type == ee.type
                                   and self.state_solver.valid(EEq(e, ee)))
                    # aeq = find_one(vv for (vv, ee) in self._concretization_functions if e.type == ee.type and alpha_equivalent(e, ee))
                    if aeq is not None:
                        event("state var {} is equivalent to {}".format(
                            v.id, aeq.id))
                        ret = subst(ret, {v.id: aeq})
                        to_remove.add(v)
                rep = [x for x in rep if x[0] not in to_remove]

            self._concretization_functions.extend(rep)
            self.query_impls[q.name] = rewrite_ret(q,
                                                   lambda prev: ret,
                                                   keep_assumptions=False)

            for op in self.op_specs:
                with task("incrementalizing query", query=q.name, op=op.name):
                    for new_member, projection in rep:
                        subqueries = []
                        state_update_stm = inc.mutate_in_place(
                            new_member,
                            projection,
                            op.body,
                            abstract_state=self.abstract_state,
                            assumptions=op.assumptions,
                            invariants=self.abstract_invariants,
                            subgoals_out=subqueries)
                        for sub_q in subqueries:
                            sub_q.docstring = "[{}] {}".format(
                                op.name, sub_q.docstring)
                            state_update_stm = self._add_subquery(
                                sub_q=sub_q, used_by=state_update_stm)
                        self.updates[(new_member, op.name)] = state_update_stm
Example #17
0
def check_calls_wf(spec : Spec):
    res = []
    queries = { m.name : m for m in spec.methods if isinstance(m, Query) }
    for ctx in enumerate_fragments(spec):
        e = ctx.e
        if isinstance(e, ECall):
            q = queries.get(e.func)
            if q is None:
                continue
            print("Checking call {}...".format(pprint(e)))
            a = EAll(ctx.facts)
            for precond in q.assumptions:
                precond = mutate(subst(precond, { v : val for (v, t), val in zip(q.args, e.args) }), ctx.mutations)
                if not valid(inline_calls(spec, EImplies(a, precond))):
                    res.append("at {}: call may not satisfy precondition {}".format(pprint(e), pprint(precond)))
    return res
Example #18
0
def inline_enum_constants(syntax_tree: ADT) -> ADT:
    """Convert variables that refer to enum constants into EEnumEntry nodes.

    Enum types introduce both a type name and a set of constants.  This
    function replaces variables that refer to those constants with a special
    kind of AST node representing the constant.  Most other functions in Cozy
    assume that this transformation has taken place, and that variables are not
    names for enum constants.
    """

    repl = {
        name: EEnumEntry(name).with_type(t)
        for t in all_types(syntax_tree) if isinstance(t, TEnum)
        for name in t.cases
    }
    return subst(syntax_tree, repl)
Example #19
0
def check_ops_preserve_invariants(spec : Spec):
    if not invariant_preservation_check.value:
        return []
    res = []
    for m in spec.methods:
        if not isinstance(m, Op):
            continue
        remap = delta_form(spec.statevars, m)
        # print(m.name)
        # for id, e in remap.items():
        #     print("  {id} ---> {e}".format(id=id, e=pprint(e)))
        for a in spec.assumptions:
            a_post_delta = subst(a, remap)
            assumptions = list(m.assumptions) + list(spec.assumptions)
            if not valid(cse(EImplies(EAll(assumptions), a_post_delta))):
                res.append("{.name!r} may not preserve invariant {}".format(m, pprint(a)))
    return res
Example #20
0
def _do_assignment(lval: syntax.Exp, new_value: syntax.Exp,
                   e: syntax.Exp) -> syntax.Exp:
    """
    Return the value of `e` after the assignment `lval = new_value`.
    """
    if isinstance(lval, syntax.EVar):
        return subst(e, {lval.id: new_value})
    elif isinstance(lval, syntax.EGetField):
        if isinstance(lval.e.type, syntax.THandle):
            assert lval.f == "val"
            # Because any two handles might alias, we need to rewrite all
            # reachable handles in `e`.
            return replace_get_value(e, lval.e, new_value)
        return _do_assignment(lval.e, _replace_field(lval.e, lval.f,
                                                     new_value), e)
    else:
        raise Exception("not an lvalue: {}".format(pprint(lval)))
Example #21
0
 def visit_ELambda(self, e):
     if e.arg in binders_by_type[e.arg.type]:
         return super().visit_ADT(e)
     fvs = free_vars(e.body)
     legal_repls = [ b for b in binders_by_type[e.arg.type] if b not in fvs ]
     if not legal_repls:
         if allow_add:
             print("Adding aux binder {} and returning {}".format(e.arg, pprint(ELambda(e.arg, e.body))), file=sys.stderr)
             binders_to_use.append(e.arg)
             binders_by_type[e.arg.type].append(e.arg)
             return ELambda(e.arg, self.visit(e.body))
         else:
             if throw:
                 print("No legal binder to use for {}".format(pprint(e)))
                 raise Exception(pprint(e))
             else:
                 return ELambda(e.arg, self.visit(e.body))
     b = legal_repls[0]
     return ELambda(b, self.visit(subst(e.body, { e.arg.id : b })))
Example #22
0
File: cxx.py Project: timwee/cozy
 def visit_ECall(self, e):
     args = [self.visit(a) for a in e.args]
     if e.func in self.funcs:
         f = self.funcs[e.func]
         return "({})".format(
             f.body_string.format(**{
                 arg: "({})".format(val)
                 for (arg, _), val in zip(f.args, args)
             }))
     elif e.func in self.queries:
         q = self.queries[e.func]
         body = subst(
             q.ret, {
                 q.args[i][0]: EEscape(args[i], (),
                                       ()).with_type(q.args[i][1])
                 for i in range(len(q.args))
             })
         return self.visit(body)
     else:
         raise Exception("unknown function {}".format(repr(e.func)))
Example #23
0
File: impls.py Project: uwplse/cozy
    def set_impl(self, q : Query, rep : [(EVar, Exp)], ret : Exp):
        """Update the implementation of a query.

        The query having the same name as `q` will have its implementation
        replaced by the given concrete representation and computation.

        This call may add additional "subqueries" to the implementation to
        maintain the new representation when each update operation is called.
        """
        with task("updating implementation", query=q.name):
            with task("finding duplicated state vars"):
                to_remove = set()
                for (v, e) in rep:
                    aeq = find_one(vv for (vv, ee) in self._concretization_functions if e.type == ee.type and self.state_solver.valid(EEq(e, ee)))
                    # aeq = find_one(vv for (vv, ee) in self._concretization_functions if e.type == ee.type and alpha_equivalent(e, ee))
                    if aeq is not None:
                        event("state var {} is equivalent to {}".format(v.id, aeq.id))
                        ret = subst(ret, { v.id : aeq })
                        to_remove.add(v)
                rep = [ x for x in rep if x[0] not in to_remove ]

            self._concretization_functions.extend(rep)
            self.query_impls[q.name] = rewrite_ret(q, lambda prev: ret, keep_assumptions=False)

            for op in self.op_specs:
                with task("incrementalizing query", query=q.name, op=op.name):
                    for new_member, projection in rep:
                        subqueries = []
                        state_update_stm = inc.mutate_in_place(
                            new_member,
                            projection,
                            op.body,
                            abstract_state=self.abstract_state,
                            assumptions=op.assumptions,
                            invariants=self.abstract_invariants,
                            subgoals_out=subqueries)
                        for sub_q in subqueries:
                            sub_q.docstring = "[{}] {}".format(op.name, sub_q.docstring)
                            state_update_stm = self._add_subquery(sub_q=sub_q, used_by=state_update_stm)
                        self.updates[(new_member, op.name)] = state_update_stm
Example #24
0
File: cxx.py Project: sanidhya/cozy
 def visit_ECall(self, e, indent=""):
     if e.args:
         setups, args = zip(*[self.visit(arg, indent) for arg in e.args])
     else:
         setups, args = ([], [])
     if e.func in self.funcs:
         f = self.funcs[e.func]
         return ("".join(setups), "({})".format(
             f.body_string.format(
                 **{arg: val
                    for (arg, _), val in zip(f.args, args)})))
     elif e.func in self.queries:
         q = self.queries[e.func]
         body = subst(
             q.ret, {
                 q.args[i][0]: EEscape(args[i], (),
                                       ()).with_type(q.args[i][1])
                 for i in range(len(q.args))
             })
         setup, res = self.visit(body, indent=indent)
         return ("".join(setups) + setup, res)
     else:
         raise Exception("unknown function {}".format(repr(e.func)))
Example #25
0
File: cxx.py Project: sanidhya/cozy
    def visit_Spec(self,
                   spec: Spec,
                   state_exps: {str: Exp},
                   sharing,
                   abstract_state=()):
        self.state_exps = state_exps
        self.funcs = {f.name: f for f in spec.extern_funcs}
        self.queries = {
            q.name: q
            for q in spec.methods if isinstance(q, Query)
        }
        self.vars = set(e.id for e in all_exps(spec) if isinstance(e, EVar))

        s = "#pragma once\n"
        s += "#include <algorithm>\n"
        s += "#include <vector>\n"
        s += "#include <unordered_set>\n"
        s += "#include <string>\n"
        if self.use_qhash:
            s += "#include <QHash>\n"
        else:
            s += "#include <unordered_map>\n"

        if spec.header:
            s += "\n" + spec.header.strip() + "\n"

        s += "{}\nclass {} {{\n".format(
            ("\n" + spec.docstring) if spec.docstring else "", spec.name)

        s += "public:\n"

        self.setup_types(spec, state_exps, sharing)
        for t, name in self.types.items():
            s += self.define_type(spec.name, t, name, INDENT, sharing)
        s += "protected:\n"
        for name, t in spec.statevars:
            self.statevar_name = name
            s += self.declare_field(name, t, indent=INDENT)
        s += "public:\n"

        # default constructor
        s += INDENT + "inline {name}() {{\n".format(name=spec.name)
        for name, t in spec.statevars:
            initial_value = state_exps[name]
            fvs = free_vars(initial_value)
            initial_value = subst(
                initial_value,
                {v.id: evaluation.construct_value(v.type)
                 for v in fvs})
            setup = self.construct_concrete(t, initial_value,
                                            EVar(name).with_type(t))
            s += self.visit(setup, INDENT + INDENT)
        s += INDENT + "}\n"

        # explicit constructor
        if abstract_state:
            s += INDENT + "inline {name}({args}) {{\n".format(
                name=spec.name,
                args=", ".join(self.visit(t, v) for (v, t) in abstract_state))
            for name, t in spec.statevars:
                initial_value = state_exps[name]
                setup = self.construct_concrete(t, initial_value,
                                                EVar(name).with_type(t))
                s += self.visit(setup, INDENT + INDENT)
            s += INDENT + "}\n"

        # disable copy constructor (TODO: support this in the future?)
        s += INDENT + "{name}(const {name}& other) = delete;\n".format(
            name=spec.name)

        # generate methods
        for op in spec.methods:
            s += self.visit(op, INDENT)
        s += "};\n\n"
        s += spec.footer
        if not s.endswith("\n"):
            s += "\n"
        return s
Example #26
0
    def build(self, cache, size):

        for e in cache.find(pool=RUNTIME_POOL, size=size - 1, type=INT):
            if not is_root(e):
                continue
            e2 = simplify_sum(e)
            if e != e2:
                yield self.check(e2, RUNTIME_POOL)

        # for e in cache.find(pool=RUNTIME_POOL, size=size-1):
        #     if isinstance(e, EMapGet) and isinstance(e.map, EMakeMap2):
        #         x = e.map.value.apply_to(e.key)
        #         x._tag = True
        #         yield self.check(x, RUNTIME_POOL)

        # [x] - ys
        for e in cache.find_collections(pool=RUNTIME_POOL, size=size - 1):
            if not is_root(e):
                continue
            if isinstance(e, EBinOp) and e.op == "-" and isinstance(
                    e.e1, ESingleton):
                x = e.e1.e
                y = e.e2
                x = ECond(
                    EBinOp(x, BOp.In, y).with_type(BOOL),
                    EEmptyList().with_type(e.type), e.e1).with_type(e.type)
                yield self.check(x, RUNTIME_POOL)
            elif isinstance(e, EUnaryOp) and e.op == UOp.Distinct:
                e = strip_EStateVar(e)
                m = EMakeMap2(e.e, mk_lambda(e.type.t, lambda x: T)).with_type(
                    TMap(e.type.t, BOOL))
                yield self.check(m, STATE_POOL)
                m = EStateVar(m).with_type(m.type)
                yield self.check(m, RUNTIME_POOL)
                x = EMapKeys(m).with_type(e.type)
                # x._tag = True
                yield self.check(x, RUNTIME_POOL)

        # # x in ys ----> (count x in ys) > 0
        # for e in cache.find(pool=RUNTIME_POOL, type=BOOL, size=size-1):
        #     if isinstance(e, EBinOp) and e.op == BOp.In:
        #         for b in self.binders:
        #             if b.type != e.e1.type:
        #                 continue
        #             x = EGt(
        #                 EUnaryOp(UOp.Length, EFilter(e.e2, ELambda(b, EEq(e.e1, b))).with_type(e.e2.type)).with_type(INT),
        #                 ZERO)
        #             x._tag = True
        #             yield self.check(x, RUNTIME_POOL)

        for e in cache.find(pool=RUNTIME_POOL, size=size - 1):
            if not is_root(e):
                continue
            if (isinstance(e, EArgMin) or isinstance(
                    e, EArgMax)) and isinstance(e.e, EBinOp) and e.e.op == "+":
                l = e.e.e1
                r = e.e.e2
                op = e.e.op
                f = lambda x: type(e)(x, e.f).with_type(e.type)
                ll = EStateVar(f(l.e)).with_type(e.type) if isinstance(
                    l, EStateVar) else f(l)
                rr = EStateVar(f(r.e)).with_type(e.type) if isinstance(
                    r, EStateVar) else f(r)
                x = ECond(
                    EUnaryOp(UOp.Exists, l).with_type(BOOL),
                    ECond(
                        EUnaryOp(UOp.Exists, r).with_type(BOOL),
                        f(
                            EBinOp(
                                ESingleton(ll).with_type(e.e.type), op,
                                ESingleton(rr).with_type(e.e.type)).with_type(
                                    e.e.type)), ll).with_type(e.type),
                    rr).with_type(e.type)
                # from cozy.solver import valid
                # assert valid(EEq(e, x), model_callback=print)
                x._tag = True
                yield self.check(x, RUNTIME_POOL)

        # is-last(x, l)
        for (sz1, sz2) in pick_to_sum(2, size - 1):
            for e1 in cache.find(pool=RUNTIME_POOL, size=sz1):
                if not is_root(e1):
                    continue
                for e2 in cache.find_collections(pool=STATE_POOL,
                                                 size=sz2,
                                                 of=e1.type):
                    if not is_root(e2):
                        continue
                    for b in self.binders:
                        if b.type != e1.type:
                            continue
                        m = EMakeMap2(
                            e2,
                            mk_lambda(
                                e2.type.t, lambda x: EUnaryOp(
                                    UOp.Length,
                                    EFilter(
                                        e2,
                                        mk_lambda(e2.type.t, lambda y: EEq(
                                            x, y))).with_type(e2.type)).
                                with_type(INT))).with_type(TMap(
                                    e2.type.t, INT))
                        # filt = EFilter(e2, ELambda(b, EEq(e1, b))).with_type(e2.type)
                        # x = EEq(
                        #     EUnaryOp(UOp.Length, filt).with_type(INT),
                        #     ONE)
                        x = EGt(
                            EMapGet(EStateVar(m).with_type(m.type),
                                    e1).with_type(INT), ONE)
                        # x._tag = True
                        yield self.check(x, RUNTIME_POOL)

        # histogram
        # for e in cache.find_collections(pool=STATE_POOL, size=size-1):
        #     m = EMakeMap2(e,
        #         mk_lambda(e.type.t, lambda x:
        #             EUnaryOp(UOp.Length, EFilter(e,
        #                 mk_lambda(e.type.t, lambda y: EEq(x, y))).with_type(e.type)).with_type(INT))).with_type(TMap(e.type.t, INT))
        #     m._tag = True
        #     yield self.check(m, STATE_POOL)

        # Fixup EFilter(\x -> ECond...)
        for e in cache.find_collections(pool=RUNTIME_POOL, size=size - 1):
            if not is_root(e):
                continue
            if isinstance(e, EFilter):
                for (_, x, r, _) in enumerate_fragments(e.p.body):
                    if isinstance(x, ECond):
                        lhs = EFilter(
                            e.e,
                            ELambda(e.p.arg, EAll([x.cond,
                                                   r(x.then_branch)
                                                   ]))).with_type(e.type)
                        rhs = EFilter(
                            e.e,
                            ELambda(e.p.arg,
                                    EAll([ENot(x.cond),
                                          r(x.else_branch)
                                          ]))).with_type(e.type)
                        union = EBinOp(lhs, "+", rhs).with_type(e.type)
                        # yield self.check(lhs.p.body, RUNTIME_POOL)
                        # yield self.check(rhs.p.body, RUNTIME_POOL)
                        yield self.check(lhs, RUNTIME_POOL)
                        yield self.check(rhs, RUNTIME_POOL)
                        yield self.check(union, RUNTIME_POOL)

        # Try instantiating bound expressions
        for pool in (STATE_POOL, RUNTIME_POOL):
            for (sz1, sz2) in pick_to_sum(2, size - 1):
                for e1 in cache.find(pool=pool, size=sz1):
                    if not is_root(e1):
                        continue
                    for v in free_vars(e1):
                        if pool == RUNTIME_POOL:
                            e1 = subst(
                                strip_EStateVar(e1), {
                                    sv.id: EStateVar(sv).with_type(sv.type)
                                    for sv in self.state_vars if sv != v
                                })
                        for e2 in cache.find(pool=pool, type=v.type, size=sz2):
                            yield self.check(subst(e1, {v.id: e2}), pool)

        for (sz1, sz2) in pick_to_sum(2, size - 1):
            for e in cache.find(pool=RUNTIME_POOL, size=sz1):
                if not is_root(e):
                    continue
                for x, pool in map_accelerate(e, self.state_vars, self.binders,
                                              self.args, cache, sz2):
                    yield self.check(x, pool)
                if isinstance(e, EFilter) and not any(v in self.binders
                                                      for v in free_vars(e)):
                    for x, pool in accelerate_filter(e.e, e.p, self.state_vars,
                                                     self.binders, self.args,
                                                     cache, sz2):
                        yield self.check(x, pool)

        for bag in cache.find_collections(pool=RUNTIME_POOL, size=size - 1):
            if not is_root(bag):
                continue
            for a in self.args:
                for v in self.state_vars:
                    if is_collection(v.type) and v.type == a.type:
                        v = EStateVar(v).with_type(v.type)
                        cond = EBinOp(a, BOp.In, v).with_type(BOOL)
                        yield self.check(
                            EFilter(bag, mk_lambda(bag.type.t,
                                                   lambda _: cond)).with_type(
                                                       bag.type), RUNTIME_POOL)
                        yield self.check(
                            EFilter(
                                bag,
                                mk_lambda(bag.type.t,
                                          lambda _: ENot(cond))).with_type(
                                              bag.type), RUNTIME_POOL)

            if isinstance(bag, EFilter):
                if any(v not in self.state_vars for v in free_vars(bag.e)):
                    continue

                # separate filter conds
                if isinstance(bag.p.body, EBinOp) and bag.p.body.op == BOp.And:
                    p1 = ELambda(bag.p.arg, bag.p.body.e1)
                    p2 = ELambda(bag.p.arg, bag.p.body.e2)
                    f1 = EFilter(bag.e, p1).with_type(bag.type)
                    f2 = EFilter(bag.e, p2).with_type(bag.type)
                    f3 = EFilter(f1, p2).with_type(bag.type)
                    f4 = EFilter(f2, p1).with_type(bag.type)
                    yield self.check(f1, RUNTIME_POOL)
                    yield self.check(f2, RUNTIME_POOL)
                    yield self.check(f3, RUNTIME_POOL)
                    yield self.check(f4, RUNTIME_POOL)

                # construct map lookups
                binder = bag.p.arg
                inf = infer_map_lookup(bag.p.body, binder,
                                       set(self.state_vars))
                if inf:
                    key_proj, key_lookup, remaining_filter = inf
                    bag_binder = find_one(
                        self.binders,
                        lambda b: b.type == key_proj.type and b != binder)
                    if bag_binder:
                        m = strip_EStateVar(
                            EMakeMap2(
                                EMap(bag.e,
                                     ELambda(binder, key_proj)).with_type(
                                         type(bag.type)(key_proj.type)),
                                ELambda(
                                    bag_binder,
                                    EFilter(
                                        bag.e,
                                        ELambda(binder,
                                                EEq(key_proj,
                                                    bag_binder))).with_type(
                                                        bag.type))).with_type(
                                                            TMap(
                                                                key_proj.type,
                                                                bag.type)))
                        assert not any(v in self.args for v in free_vars(m))
                        yield self.check(m, STATE_POOL)
                        m = EStateVar(m).with_type(m.type)
                        mg = EMapGet(m, key_lookup).with_type(bag.type)
                        yield self.check(mg, RUNTIME_POOL)
                        yield self.check(
                            EFilter(mg, ELambda(
                                binder, remaining_filter)).with_type(mg.type),
                            RUNTIME_POOL)

        # for e in cache.find(size=size-1):
        #     # F(xs +/- ys) ---> F(xs), F(ys)
        #     for z in break_plus_minus(e):
        #         if z != e:
        #             # print("broke {} --> {}".format(pprint(e), pprint(z)))
        #             yield z

        #     # try reordering operations
        #     for (_, e1, f) in enumerate_fragments(e):
        #         if e1.type == e.type and e1 != e:
        #             for (_, e2, g) in enumerate_fragments(e1):
        #                 if e2.type == e.type and e2 != e1:
        #                     # e == f(g(e2))
        #                     yield g(f(e2))

        yield from self.wrapped.build(cache, size)
Example #27
0
File: cxx.py Project: uwplse/cozy
    def visit_Spec(self, spec : Spec, state_exps : { str : Exp }, sharing, abstract_state=()):
        self.state_exps = state_exps
        self.funcs = { f.name: f for f in spec.extern_funcs }
        self.queries = { q.name: q for q in spec.methods if isinstance(q, Query) }
        self.vars = set(e.id for e in all_exps(spec) if isinstance(e, EVar))

        self.write("#pragma once\n")
        self.write("#include <algorithm>\n")
        self.write("#include <set>\n")
        self.write("#include <functional>\n")
        self.write("#include <vector>\n")
        self.write("#include <unordered_set>\n")
        self.write("#include <string>\n")
        if self.use_qhash:
            self.write("#include <QHash>\n")
        else:
            self.write("#include <unordered_map>\n")

        if spec.header:
            self.write("\n" + spec.header.strip() + "\n")

        self.write("{}\nclass {} {{\n".format(
            ("\n" + spec.docstring) if spec.docstring else "",
            spec.name))

        self.write("public:\n")

        print("Setting up auxiliary types...")
        self.setup_types(spec, state_exps, sharing)
        with self.indented():
            for t, name in self.types.items():
                self.define_type(spec.name, t, name, sharing)
                self.begin_statement()
                if isinstance(t, THandle):
                    # No overridden hash code! We use pointers instead.
                    continue
                self.write("struct _Hash", name, " ")
                with self.block():
                    self.write_stmt("typedef ", spec.name, "::", name, " argument_type;")
                    self.write_stmt("typedef std::size_t result_type;")
                    self.begin_statement()
                    self.write("result_type operator()(const argument_type& x) const noexcept ")
                    x = EVar("x").with_type(t)
                    if isinstance(t, TEnum):
                        fields = [EEnumToInt(x).with_type(INT)]
                    elif isinstance(t, TRecord):
                        fields = [EGetField(x, f).with_type(ft) for (f, ft) in t.fields]
                    elif isinstance(t, TTuple):
                        fields = [ETupleGet(x, n).with_type(tt) for (n, tt) in enumerate(t.ts)]
                    else:
                        raise NotImplementedError(t)
                    with self.block():
                        self.visit(self.compute_hash(fields))
                    self.end_statement()
                self.write(";")
                self.end_statement()

        print("Setting up member variables...")
        self.write("protected:\n")
        with self.indented():
            for name, t in spec.statevars:
                self.statevar_name = name
                self.declare_field(name, t)

        self.write("public:\n")
        with self.indented():
            print("Generating constructors...")

            # default constructor
            self.begin_statement()
            self.write("inline ", spec.name, "() ")
            with self.block():
                for name, t in spec.statevars:
                    initial_value = state_exps[name]
                    fvs = free_vars(initial_value)
                    initial_value = subst(initial_value, {v.id : evaluation.construct_value(v.type) for v in fvs})
                    stm = simplify_and_optimize(SAssign(EVar(name).with_type(t), initial_value))
                    self.visit(stm)
            self.end_statement()

            # explicit constructor
            if abstract_state:
                self.begin_statement()
                self.write("explicit inline ", spec.name, "(")
                self.visit_args(abstract_state)
                self.write(") ")
                with self.block():
                    for name, t in spec.statevars:
                        initial_value = state_exps[name]
                        self.visit(simplify_and_optimize(SAssign(EVar(name).with_type(t), initial_value)))
                self.end_statement()

            # disable copy constructor (TODO: support this in the future?)
            self.begin_statement()
            self.write(spec.name, "(const ", spec.name, "& other) = delete;")
            self.end_statement()

            # generate methods
            for op in spec.methods:
                print("Generating method {}...".format(op.name))
                self.visit(op)
        self.write("};\n")

        if spec.footer:
            self.write("\n", spec.footer)
            if not spec.footer.endswith("\n"):
                self.write("\n")
Example #28
0
    def visit_Spec(self,
                   spec: Spec,
                   state_exps: {str: Exp},
                   sharing,
                   abstract_state=()):
        self.state_exps = state_exps
        self.funcs = {f.name: f for f in spec.extern_funcs}
        self.queries = {
            q.name: q
            for q in spec.methods if isinstance(q, Query)
        }
        self.vars = set(e.id for e in all_exps(spec) if isinstance(e, EVar))

        self.write("#pragma once\n")
        self.write("#include <algorithm>\n")
        self.write("#include <set>\n")
        self.write("#include <functional>\n")
        self.write("#include <vector>\n")
        self.write("#include <unordered_set>\n")
        self.write("#include <string>\n")
        if self.use_qhash:
            self.write("#include <QHash>\n")
        else:
            self.write("#include <unordered_map>\n")

        if spec.header:
            self.write("\n" + spec.header.strip() + "\n")

        self.write("{}\nclass {} {{\n".format(
            ("\n" + spec.docstring) if spec.docstring else "", spec.name))

        self.write("public:\n")

        print("Setting up auxiliary types...")
        self.setup_types(spec, state_exps, sharing)
        with self.indented():
            for t, name in self.types.items():
                self.define_type(spec.name, t, name, sharing)
                self.begin_statement()
                if isinstance(t, THandle):
                    # No overridden hash code! We use pointers instead.
                    continue
                self.write("struct _Hash", name, " ")
                with self.block():
                    self.write_stmt("typedef ", spec.name, "::", name,
                                    " argument_type;")
                    self.write_stmt("typedef std::size_t result_type;")
                    self.begin_statement()
                    self.write(
                        "result_type operator()(const argument_type& x) const noexcept "
                    )
                    x = EVar("x").with_type(t)
                    if isinstance(t, TEnum):
                        fields = [EEnumToInt(x).with_type(INT)]
                    elif isinstance(t, TRecord):
                        fields = [
                            EGetField(x, f).with_type(ft)
                            for (f, ft) in t.fields
                        ]
                    elif isinstance(t, TTuple):
                        fields = [
                            ETupleGet(x, n).with_type(tt)
                            for (n, tt) in enumerate(t.ts)
                        ]
                    else:
                        raise NotImplementedError(t)
                    with self.block():
                        self.visit(self.compute_hash(fields))
                    self.end_statement()
                self.write(";")
                self.end_statement()

        print("Setting up member variables...")
        self.write("protected:\n")
        with self.indented():
            for name, t in spec.statevars:
                self.statevar_name = name
                self.declare_field(name, t)

        self.write("public:\n")
        with self.indented():
            print("Generating constructors...")

            # default constructor
            self.begin_statement()
            self.write("inline ", spec.name, "() ")
            with self.block():
                for name, t in spec.statevars:
                    initial_value = state_exps[name]
                    fvs = free_vars(initial_value)
                    initial_value = subst(initial_value, {
                        v.id: evaluation.construct_value(v.type)
                        for v in fvs
                    })
                    stm = simplify_and_optimize(
                        SAssign(EVar(name).with_type(t), initial_value))
                    self.visit(stm)
            self.end_statement()

            # explicit constructor
            if abstract_state:
                self.begin_statement()
                self.write("explicit inline ", spec.name, "(")
                self.visit_args(abstract_state)
                self.write(") ")
                with self.block():
                    for name, t in spec.statevars:
                        initial_value = state_exps[name]
                        self.visit(
                            simplify_and_optimize(
                                SAssign(
                                    EVar(name).with_type(t), initial_value)))
                self.end_statement()

            # disable copy constructor (TODO: support this in the future?)
            self.begin_statement()
            self.write(spec.name, "(const ", spec.name, "& other) = delete;")
            self.end_statement()

            # generate methods
            for op in spec.methods:
                print("Generating method {}...".format(op.name))
                self.visit(op)
        self.write("};\n")

        if spec.footer:
            self.write("\n", spec.footer)
            if not spec.footer.endswith("\n"):
                self.write("\n")
Example #29
0
    def visit_Spec(self, spec, state_exps, sharing, abstract_state=()):
        self.state_exps = state_exps
        self.funcs = { f.name: f for f in spec.extern_funcs }
        self.queries = { q.name: q for q in spec.methods if isinstance(q, Query) }
        self.vars = set(e.id for e in all_exps(spec) if isinstance(e, EVar))
        self.setup_types(spec, state_exps, sharing)

        if guava.value:
            self.write("import com.google.common.collect.TreeMultiset;\n")
            self.write("import com.google.common.collect.Iterators;\n")
        if spec.header:
            self.write(spec.header.strip() + "\n\n")

        if spec.docstring:
            self.write(spec.docstring + "\n")

        self.write("public class {} implements java.io.Serializable ".format(spec.name))
        with self.block():

            for name, t in spec.types:
                self.types[t] = name

            # member variables
            for name, t in spec.statevars:
                self.write("{}protected {};\n".format(INDENT, self.visit(t, name)))

            # constructor
            self.write(
                "{indent}public {name}() {{\n{indent2}clear();\n{indent}}}\n\n"
                .format(indent=INDENT, indent2=INDENT+INDENT, name=spec.name))

            # explicit constructor
            if abstract_state:
                self.begin_statement()
                self.write("public ", spec.name, "(")
                self.visit_args(abstract_state)
                self.write(") ")
                with self.block():
                    for name, t in spec.statevars:
                        initial_value = state_exps[name]
                        self.visit(simplify_and_optimize(SAssign(EVar(name).with_type(t), initial_value)))
                self.end_statement()

            # clear
            self.begin_statement()
            self.write("public void clear() ")
            with self.block():
                for name, t in spec.statevars:
                    initial_value = state_exps[name]
                    fvs = free_vars(initial_value)
                    initial_value = subst(initial_value,
                        {v.id : evaluation.construct_value(v.type) for v in fvs})
                    setup = simplify_and_optimize(SAssign(EVar(name).with_type(t), initial_value))
                    self.visit(setup)
            self.end_statement()

            # methods
            for op in spec.methods:
                self.visit(op)

            # generate auxiliary types
            for t, name in self.types.items():
                self.define_type(spec.name, t, name, sharing)

        self.write("\n")
        self.write(spec.footer)
        if not spec.footer.endswith("\n"):
            self.write("\n")
Example #30
0
def re_use(value : Exp, v : EVar, s : Stm) -> Stm:
    if efficiently_reuseable(value) or count_occurrences_of_free_var(s, v) <= 1:
        return subst(s, {v.id : value})
    return seq([SDecl(v, value), s])
Example #31
0
 def visit_ELet(self, e):
     value_exp = self.visit(e.e)
     fv = fresh_var(value_exp.type, e.body_function.arg.id)
     self.stms.append(SDecl(fv, value_exp))
     return self.visit(subst(e.body_function.body, { e.body_function.arg.id : fv }))
Example #32
0
File: core.py Project: timwee/cozy
def can_elim_vars(spec: Exp, assumptions: Exp, vs: [EVar]):
    spec = strip_EStateVar(spec)
    sub = {v.id: fresh_var(v.type) for v in vs}
    return valid(
        EImplies(EAll([assumptions, subst(assumptions, sub)]),
                 EEq(spec, subst(spec, sub))))
Example #33
0
 def for_each(self, iterable: Exp, body) -> str:
     """Body is function: exp -> stm"""
     if isinstance(iterable, EEmptyList):
         return ""
     elif isinstance(iterable, ESingleton):
         return self.visit(SScoped(body(iterable.e)))
     elif isinstance(iterable, ECond):
         v = self.fv(iterable.type.t, "v")
         new_body = body(v)
         assert isinstance(new_body, Stm)
         return self.visit(
             SIf(iterable.cond, SForEach(v, iterable.then_branch, new_body),
                 SForEach(v, iterable.else_branch, new_body)))
     elif isinstance(iterable, EMap):
         return self.for_each(iterable.e,
                              lambda v: body(iterable.f.apply_to(v)))
     elif isinstance(iterable, EUnaryOp) and iterable.op == UOp.Distinct:
         tmp = self.fv(TSet(iterable.type.t), "tmp")
         self.declare(tmp)
         self.visit(self.initialize_native_set(tmp))
         self.for_each(
             iterable.e,
             lambda x: SIf(ENot(EBinOp(x, BOp.In, tmp).with_type(BOOL)),
                           seq([body(x), SCall(tmp, "add", [x])]), SNoOp()))
     elif isinstance(iterable, EFilter):
         return self.for_each(
             iterable.e,
             lambda x: SIf(iterable.p.apply_to(x), body(x), SNoOp()))
     elif isinstance(iterable, EBinOp) and iterable.op == "+":
         self.for_each(iterable.e1, body)
         self.for_each(iterable.e2, body)
     elif isinstance(iterable, EBinOp) and iterable.op == "-":
         t = TList(iterable.type.t)
         e = self.visit(EBinOp(iterable.e1, "-", iterable.e2).with_type(t))
         return self.for_each(EEscape(e, (), ()).with_type(t), body)
     elif isinstance(iterable, EFlatMap):
         v = self.fv(iterable.type.t)
         new_body = body(v)
         assert isinstance(new_body, Stm)
         return self.for_each(iterable.e,
                              body=lambda bag: SForEach(
                                  v, iterable.f.apply_to(bag), new_body))
     elif isinstance(iterable, EListSlice):
         s = self.fv(INT, "start")
         e = self.fv(INT, "end")
         l = self.visit(iterable.e)
         self.declare(s, iterable.start)
         self.declare(e, iterable.end)
         return self.visit(
             SWhile(
                 ELt(s, e),
                 SSeq(
                     body(
                         EEscape("{l}[{i}]", ("l", "i"),
                                 (iterable.e, s)).with_type(
                                     iterable.type.t)),
                     SAssign(s,
                             EBinOp(s, "+", ONE).with_type(INT)))))
     elif isinstance(iterable, ECall) and iterable.func in self.queries:
         q = self.queries[iterable.func]
         return self.for_each(
             subst(q.ret,
                   {a: v
                    for ((a, t), v) in zip(q.args, iterable.args)}), body)
     elif isinstance(iterable, ELet):
         return self.for_each(iterable.f.apply_to(iterable.e), body)
     else:
         assert is_collection(iterable.type), repr(iterable)
         x = self.fv(iterable.type.t, "x")
         return self.for_each_native(x, iterable, body(x))
Example #34
0
 def apply_to(self, arg):
     from cozy.syntax_tools import subst
     return subst(self.body, {self.arg.id: arg})
Example #35
0
File: cxx.py Project: sanidhya/cozy
 def for_each(self, iterable: Exp, body, indent="") -> str:
     """Body is function: exp -> stm"""
     while isinstance(iterable, EDropFront) or isinstance(
             iterable, EDropBack):
         iterable = iterable.e
     if isinstance(iterable, EEmptyList):
         return ""
     elif isinstance(iterable, ESingleton):
         return self.visit(SScoped(body(iterable.e)), indent=indent)
     elif isinstance(iterable, ECond):
         v = self.fv(iterable.type.t, "v")
         new_body = body(v)
         assert isinstance(new_body, Stm)
         return self.visit(SIf(iterable.cond,
                               SForEach(v, iterable.then_branch, new_body),
                               SForEach(v, iterable.else_branch, new_body)),
                           indent=indent)
     elif isinstance(iterable, EMap):
         return self.for_each(iterable.e,
                              lambda v: body(iterable.f.apply_to(v)),
                              indent=indent)
     elif isinstance(iterable, EUnaryOp) and iterable.op == UOp.Distinct:
         tmp = self.fv(library.TNativeSet(iterable.type.t), "tmp")
         return "".join((
             "{indent}{decl};\n".format(indent=indent,
                                        decl=self.visit(tmp.type, tmp.id)),
             self.visit(self.initialize_native_set(tmp), indent),
             # TODO: could get better performance out of single "find or insert" primitive
             self.for_each(
                 iterable.e, lambda x: SIf(
                     ENot(EBinOp(x, BOp.In, tmp).with_type(BOOL)),
                     seq([body(x), SCall(tmp, "add", [x])]), SNoOp()),
                 indent)))
     elif isinstance(iterable, EFilter):
         return self.for_each(
             iterable.e,
             lambda x: SIf(iterable.p.apply_to(x), body(x), SNoOp()),
             indent=indent)
     elif isinstance(iterable, EBinOp) and iterable.op == "+":
         return self.for_each(iterable.e1, body,
                              indent=indent) + self.for_each(
                                  iterable.e2, body, indent=indent)
     elif isinstance(iterable, EBinOp) and iterable.op == "-":
         t = library.TNativeList(iterable.type.t)
         setup, e = self.visit(
             EBinOp(iterable.e1, "-", iterable.e2).with_type(t), indent)
         return setup + self.for_each(
             EEscape(e, (), ()).with_type(t), body, indent)
     elif isinstance(iterable, EFlatMap):
         from cozy.syntax_tools import shallow_copy
         v = self.fv(iterable.type.t)
         new_body = body(v)
         assert isinstance(new_body, Stm)
         return self.for_each(iterable.e,
                              indent=indent,
                              body=lambda bag: SForEach(
                                  v, iterable.f.apply_to(bag), new_body))
     elif isinstance(iterable, ECall) and iterable.func in self.queries:
         q = self.queries[iterable.func]
         return self.for_each(subst(
             q.ret, {a: v
                     for ((a, t), v) in zip(q.args, iterable.args)}),
                              body,
                              indent=indent)
     elif isinstance(iterable, ELet):
         return self.for_each(iterable.f.apply_to(iterable.e),
                              body,
                              indent=indent)
     else:
         x = self.fv(iterable.type.t, "x")
         if type(iterable.type) in (TBag, library.TNativeList, TSet,
                                    library.TNativeSet, TList):
             return self.for_each_native(x, iterable, body(x), indent)
         return self.visit(iterable.type.for_each(x, iterable, body(x)),
                           indent=indent)
Example #36
0
File: misc.py Project: uwplse/cozy
def pull_temps(s : Stm, decls_out : [SDecl], exp_is_bad) -> Stm:
    """Remove "bad" expressions from `s`.

    This procedure returns a statement new_s that replaces every expression in
    `s` where `exp_is_bad` returns True with a fresh variable.  After running,
    `decls_out` contains definitions for the fresh variables so that the whole
    statement

        decls_out; new_s

    should return the same result as `s`.
    """

    def pull(e : Exp) -> Exp:
        """Pull an expression into a temporary.

        Creates a fresh variable for `e`, writes a declaration into `decls_out`,
        and returns the fresh variable.
        """
        if exp_is_bad(e):
            v = fresh_var(e.type)
            decls_out.append(SDecl(v, e))
            return v
        return e

    if isinstance(s, SNoOp):
        return s
    if isinstance(s, SSeq):
        s1 = pull_temps(s.s1, decls_out, exp_is_bad)
        s2 = pull_temps(s.s2, decls_out, exp_is_bad)
        return SSeq(s1, s2)
    if isinstance(s, SDecl):
        return SDecl(s.var, pull(s.val))
    if isinstance(s, SIf):
        cond = pull(s.cond)
        s1 = pull_temps(s.then_branch, decls_out, exp_is_bad)
        s2 = pull_temps(s.else_branch, decls_out, exp_is_bad)
        return SIf(cond, s1, s2)
    if isinstance(s, SForEach):
        bag = pull(s.iter)
        d_tmp = []
        body = pull_temps(s.body, d_tmp, exp_is_bad)
        to_fix, ok = partition(d_tmp, lambda d: s.loop_var in free_vars(d.val))
        decls_out.extend(ok)
        for d in to_fix:
            v = d.var
            mt = TMap(s.loop_var.type, v.type)
            m = EMakeMap2(bag, ELambda(s.loop_var, d.val)).with_type(mt)
            mv = fresh_var(m.type)
            md = SDecl(mv, m)
            decls_out.append(md)
            body = subst(body, { v.id : EMapGet(mv, s.loop_var).with_type(v.type) })
        return SForEach(s.loop_var, bag, body)
    if isinstance(s, SAssign):
        return SAssign(s.lhs, pull(s.rhs))
    if isinstance(s, SCall):
        return SCall(s.target, s.func, tuple(pull(arg) for arg in s.args))
    if isinstance(s, SMapDel):
        return SMapDel(s.map, pull(s.key))
    if isinstance(s, SMapPut):
        return SMapPut(s.map, pull(s.key), pull(s.value))
    if isinstance(s, SMapUpdate):
        key = pull(s.key)
        d_tmp = []
        change = pull_temps(s.change, d_tmp, exp_is_bad)
        for d in d_tmp:
            if s.val_var in free_vars(d.val):
                decls_out.append(SDecl(d.var, subst(d.val, { s.val_var.id : EMapGet(s.map, key).with_type(s.val_var.type) })))
            else:
                decls_out.append(d)
        return SMapUpdate(s.map, key, s.val_var, change)
    raise NotImplementedError(s)