def process_assignment(self, ref: z3.BoolRef) -> None: """ Create a RE constraint or a fresh equation for literal assignment. Assignment is `var = str_cons`. If there is no RE constraint for `var`, we create one of the form `var → RE(str_cons)`. Otherwise we introduce a fresh variable (`x`) and create a new equation `var = x`, and introduce a constraint `x → RE(str_cons)`. Parameters ---------- ref: z3.BoolRef of the form `var = string_const` Returns ------- None """ assert is_assignment(ref) var, const = (c.as_string() for c in ref.children()) const_re: RE = self.create_awali_re(const) if var not in self.constraints: self.constraints[var] = const_re else: # Introduce a fresh variable and a new equation new_var = self.fresh_variable() self.constraints[new_var] = const_re self.equations.append(StringEquation([var], [new_var]))
def parse_equation(self, ref: z3.BoolRef) -> StringEquation: left, right = ref.children() # TODO This restricts only to assignment-form of equations (like SSA-fragment) assert is_string_variable(left) assert right.sort_kind() == z3.Z3_SEQ_SORT res_left = [left.as_string()] def z3_concat_to_var_list(z3_ref: z3.SeqRef) -> Collection[str]: """ Convert concatenation of string variables into list of vars. Parameters ---------- z3_ref Returns ------- List of variables from Z3_ref """ if is_string_variable(z3_ref): return [z3_ref.as_string()] children = [ z3_concat_to_var_list(child) for child in z3_ref.children() ] return itertools.chain(*children) res_right = z3_concat_to_var_list(right) return StringEquation(res_left, list(res_right))
def is_assignment(ref: z3.BoolRef) -> bool: """ Detect assignment. Assignment is an equation of the form `var = str_const`. Parameters ---------- ref: z3 reference Returns ------- True if `ref` is an assignment. """ if ref.decl().kind() != z3.Z3_OP_EQ: return False left, right = ref.children() return is_string_variable(left) and is_string_constant(right)
def parse_re_constraint(self, ref: z3.BoolRef) -> REConstraints: """ Translate one regular constraint into REConstraints dict. The reference should point to a Z3_OP_SEQ_IN_RE operator. Parameters ---------- ref: z3.BoolRef to a in_re operator to translate Returns ------- REConstraint Mapping `var -> RE` """ assert is_inre(ref) left, right = ref.children() assert is_string_variable(left) and left.as_string() in self.variables return {left.as_string(): self.z3_re_to_awali(right)}
def mk_eq(e1, e2): # type: (ExprRef, ExprRef) -> ExprRef """Return a z3 expression equivalent to e1 == e2""" return BoolRef(Z3_mk_eq(e1.ctx_ref(), e1.as_ast(), e2.as_ast()), e1.ctx)
def _ge_no_coerce(self, left, right): # TODO: add assertions for noncoerce return BoolRef(Z3_mk_ge(left.ctx_ref(), left.as_ast(), right.as_ast()), left.ctx)
def eq_no_coerce(left, right): #TODO add assertion for coercion-free return BoolRef(Z3_mk_eq(left.ctx_ref(), left.as_ast(), right.as_ast()), left.ctx)
def fast_ne(a: ExprRef, b: ExprRef): """Equivalent of z3 __ne__.""" z3args = (Ast * 2)() z3args[0], z3args[1] = a.as_ast(), b.as_ast() return BoolRef(Z3_mk_distinct(CTX.ref(), 2, z3args), CTX)
def fast_eq(a: ExprRef, b: ExprRef): """Equivalent of z3 __eq__.""" return BoolRef(Z3_mk_eq(CTX.ref(), a.as_ast(), b.as_ast()), CTX)
def fast_and(*args: BoolRef): """Equivalent of z3 And.""" z3args = (Ast * len(args))() for i, a in enumerate(args): z3args[i] = a.as_ast() return BoolRef(Z3_mk_and(CTX.ref(), len(z3args), z3args), CTX)