我们从Python开源项目中,提取了以下45个代码示例,用于说明如何使用ast.BoolOp()。
def __init__(self, expr, context): self.expr = expr self.context = context self.expr_table = { LLLnode: self.get_expr, ast.Num: self.number, ast.Str: self.string, ast.NameConstant: self.constants, ast.Name: self.variables, ast.Attribute: self.attribute, ast.Subscript: self.subscript, ast.BinOp: self.arithmetic, ast.Compare: self.compare, ast.BoolOp: self.boolean_operations, ast.UnaryOp: self.unary_operations, ast.Call: self.call, ast.List: self.list_literals, ast.Dict: self.struct_literals, ast.Tuple: self.tuple_literals, } expr_type = self.expr.__class__ if expr_type in self.expr_table: self.lll_node = self.expr_table[expr_type]() else: raise Exception("Unsupported operator: %r" % ast.dump(self.expr))
def eval_expr(expr): """ Eval and expression inside a #define using a suppart of python grammar """ def _eval(node): if isinstance(node, ast.Num): return node.n elif isinstance(node, ast.BinOp): return OPERATORS[type(node.op)](_eval(node.left), _eval(node.right)) elif isinstance(node, ast.UnaryOp): return OPERATORS[type(node.op)](_eval(node.operand)) elif isinstance(node, ast.BoolOp): values = [_eval(x) for x in node.values] return OPERATORS[type(node.op)](**values) else: raise TypeError(node) return _eval(ast.parse(expr, mode='eval').body)
def safe_eval_gpr(expr, conf_genes): """Internal function to evaluate a gene-protein rule in an injection-safe manner (hopefully). """ if isinstance(expr, Expression): return safe_eval_gpr(expr.body, conf_genes) elif isinstance(expr, Name): fgid = format_gid(expr.id) if fgid not in conf_genes: return 0 return conf_genes[fgid] elif isinstance(expr, BoolOp): op = expr.op if isinstance(op, Or): return max(safe_eval_gpr(i, conf_genes) for i in expr.values) elif isinstance(op, And): return min(safe_eval_gpr(i, conf_genes) for i in expr.values) else: raise TypeError("unsupported operation " + op.__class__.__name__) elif expr is None: return 0 else: raise TypeError("unsupported operation " + repr(expr))
def simplify_multicomp(a): if type(a) == ast.Compare and len(a.ops) > 1: # Only do one comparator at a time. If we don't do this, things get messy! comps = [a.left] + a.comparators values = [ ] # Compare each of the pairs for i in range(len(a.ops)): if i > 0: # Label all nodes as middle parts so we can recognize them later assignPropertyToAll(comps[i], "multiCompMiddle") values.append(ast.Compare(comps[i], [a.ops[i]], [deepcopy(comps[i+1])], multiCompPart=True)) # Combine comparisons with and operators boolOp = ast.And(multiCompOp=True) boolopVal = ast.BoolOp(boolOp, values, multiComp=True, global_id=a.global_id) return boolopVal return a
def visit_Compare(self, node, **kwargs): ops = node.ops comps = node.comparators # base case: we have something like a CMP b if len(comps) == 1: op = self.translate_In(ops[0]) binop = ast.BinOp(op=op, left=node.left, right=comps[0]) return self.visit(binop) # recursive case: we have a chained comparison, a CMP b CMP c, etc. left = node.left values = [] for op, comp in zip(ops, comps): new_node = self.visit(ast.Compare(comparators=[comp], left=left, ops=[self.translate_In(op)])) left = comp values.append(new_node) return self.visit(ast.BoolOp(op=ast.And(), values=values))
def normalize_compare(node): """Rewrites a compare expression to a `and` expression 1 < 2 < 3 > 0 1 < 2 and 2 < 3 and 3 > 0""" and_values = [] left = node.left for (op, val) in zip(node.ops, node.comparators): comp = ast.Compare(ops=[op], left=left, comparators=[val], lineno=node.lineno, col_offset=node.col_offset) and_values.append(comp) left = val return ast.BoolOp(op=ast.And(), values=and_values, lineno=node.lineno, col_offset=node.col_offset)
def translate_pat_Tuple(self, ctx, pat, scrutinee_trans): scrutinee_trans_copy = astx.copy_node(scrutinee_trans) elts = pat.elts idx = self.idx conditions = [] binding_translations = _util.odict() for n, (elt, ty) in enumerate(zip(elts, idx.itervalues())): elt_scrutinee_trans = astx.make_Subscript_Num_Index( scrutinee_trans_copy, n) elt_condition, elt_binding_translations = ctx.translate_pat( elt, elt_scrutinee_trans) conditions.append(elt_condition) binding_translations.update(elt_binding_translations) condition = ast.BoolOp( op=ast.And(), values=conditions) return (condition, binding_translations)
def translate_pat_Dict(self, ctx, pat, scrutinee_trans): scrutinee_trans_copy = astx.copy_node(scrutinee_trans) keys, values = pat.keys, pat.values idx = self.idx conditions = [] binding_translations = _util.odict() for key, value in zip(keys, values): label = key.label n = _util.odict_idx_of(idx, label) elt_scrutinee_trans = astx.make_Subscript_Num_Index( scrutinee_trans_copy, n) elt_condition, elt_binding_translations = ctx.translate_pat( value, elt_scrutinee_trans) conditions.append(elt_condition) binding_translations.update(elt_binding_translations) condition = ast.BoolOp( op=ast.And(), values=conditions) return (condition, binding_translations)
def translate_pat_Call_constructor(self, ctx, pat, scrutinee_trans): lbl = pat.func.id tag_loc = ast.Subscript( value=scrutinee_trans, slice=ast.Index(value=ast.Num(n=0))) lbl_condition = ast.Compare( left=tag_loc, ops=[ast.Eq()], comparators=[ast.Str(s=lbl)]) arg = pat.args[0] arg_scrutinee = ast.Subscript( value=scrutinee_trans, slice=ast.Index(value=ast.Num(n=1))) arg_condition, binding_translations = ctx.translate_pat(arg, arg_scrutinee) condition = ast.BoolOp( op=ast.And(), values=[lbl_condition, arg_condition]) return condition, binding_translations
def visit_Name(self, name): # Display the repr of the name if it's a local variable or # _should_repr_global_name() thinks it's acceptable. locs = ast_Call(self.builtin("locals"), [], []) inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs]) dorepr = self.helper("should_repr_global_name", name) test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) return name, self.explanation_param(expr)
def visit_Compare(self, comp): self.push_format_context() left_res, left_expl = self.visit(comp.left) if isinstance(comp.left, (_ast.Compare, _ast.BoolOp)): left_expl = "({0})".format(left_expl) res_variables = [self.variable() for i in range(len(comp.ops))] load_names = [ast.Name(v, ast.Load()) for v in res_variables] store_names = [ast.Name(v, ast.Store()) for v in res_variables] it = zip(range(len(comp.ops)), comp.ops, comp.comparators) expls = [] syms = [] results = [left_res] for i, op, next_operand in it: next_res, next_expl = self.visit(next_operand) if isinstance(next_operand, (_ast.Compare, _ast.BoolOp)): next_expl = "({0})".format(next_expl) results.append(next_res) sym = binop_map[op.__class__] syms.append(ast.Str(sym)) expl = "%s %s %s" % (left_expl, sym, next_expl) expls.append(ast.Str(expl)) res_expr = ast.Compare(left_res, [op], [next_res]) self.statements.append(ast.Assign([store_names[i]], res_expr)) left_res, left_expl = next_res, next_expl # Use pytest.assertion.util._reprcompare if that's available. expl_call = self.helper("call_reprcompare", ast.Tuple(syms, ast.Load()), ast.Tuple(load_names, ast.Load()), ast.Tuple(expls, ast.Load()), ast.Tuple(results, ast.Load())) if len(comp.ops) > 1: res = ast.BoolOp(ast.And(), load_names) else: res = load_names[0] return res, self.explanation_param(self.pop_format_context(expl_call))
def visit_If(self, node): node = self.generic_visit(node) if (node.orelse and len(node.orelse) == 1 and isinstance(node.orelse[0], ast.Pass) ): node.orelse = [] if (len(node.body) == 1 and isinstance(node.body[0], ast.Pass) ): if node.orelse: node_test = ast.UnaryOp(op=ast.Not(), operand=node.test) if (len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If) ): node_test = ast.BoolOp\ ( op = ast.And() , values = [node_test, node.orelse[0].test] ) node.test = ast.copy_location(node_test, node.orelse[0].test) node.body = node.orelse[0].body node.orelse = node.orelse[0].orelse else: node.test = ast.copy_location(node_test, node.test) node.body = node.orelse node.orelse = [] else: node = None return node
def movedLineAfterSpecialFunction(cv, startingTree, startingPath, orig): """Sometimes, with Move Vectors, items that got combined are no longer combined. Fix this by moving up the tree.""" if isinstance(cv, MoveVector): cvCopy = cv.deepcopy() origSpot = deepcopy(cvCopy.traverseTree(cv.start)) if len(origSpot) <= cv.oldSubtree or len(origSpot) <= cv.newSubtree: cvCopy.path = startingPath[1:] parentSpot = deepcopy(cvCopy.traverseTree(startingTree)) if type(parentSpot) == ast.BoolOp: # Change this to a ChangeVector at the parent's level newSpot = deepcopy(parentSpot) newSpot.values.insert(cv.newSubtree, newSpot.values[cv.oldSubtree]) newSpot.values.pop(cv.oldSubtree + (0 if cv.oldSubtree < cv.newSubtree else 1)) # adjust for length change cv = ChangeVector(cv.path[2:], parentSpot, newSpot, cv.start) cv.wasMoveVector = True return cv elif cv.path[1][0] == 'body': # If we're in a set of statements lineToMove = parentSpot.body[cv.oldSubtree] # First, just delete this line if hasattr(lineToMove, "global_id"): path = generatePathToId(orig, lineToMove.global_id) else: log("Individualize\tmovedLineAfterSpecialFunction\tWhere is the global id? " + printFunction(lineToMove), "bug") firstEdit = DeleteVector(path, lineToMove, None, start=orig) # Then, add the line back in, but in the correct position newPath = [cv.newSubtree] + cv.path[1:] secondEdit = AddVector(newPath, None, lineToMove, start=cv.start) return [firstEdit, secondEdit] else: log("Individualize\tmapEdit\tMissing option in Move Vector special case: " + str(type(parentSpot)), "bug") return cv
def cleanupBoolOps(a): """When possible, combine adjacent boolean expressions""" """Note- we are assuming that all ops are the first op (as is done in the simplify function)""" if not isinstance(a, ast.AST): return a if type(a) == ast.BoolOp: allTypesWork = True for i in range(len(a.values)): a.values[i] = cleanupBoolOps(a.values[i]) if eventualType(a.values[i]) != bool or hasattr(a.values[i], "multiComp"): allTypesWork = False # We can't reduce if the types aren't all booleans if not allTypesWork: return a i = 0 while i < len(a.values) - 1: current = a.values[i] next = a.values[i+1] # (a and b and c and d) or (a and e and d) == a and ((b and c) or e) and d if type(current) == type(next) == ast.BoolOp: if type(current.op) == type(next.op): minlength = min(len(current.values), len(next.values)) # shortest length # First, check for all identical values from the front j = 0 while j < minlength: if compareASTs(current.values[j], next.values[j], checkEquality=True) != 0: break j += 1 # Same values in both, so get rid of the latter line if j == len(current.values) == len(next.values): a.values.pop(i+1) continue i += 1 ### If reduced to one item, just return that item return a.values[0] if (len(a.values) == 1) else a return applyToChildren(a, cleanupBoolOps)
def _safe_eval(node, default): """ Safely evaluate the Boolean expression under the given AST node. Substitute `default` for all sub-expressions that cannot be evaluated (because variables or functions are undefined). We could use eval() to evaluate more sub-expressions. However, this function is not safe for arbitrary Python code. Even after overwriting the "__builtins__" dictionary, the original dictionary can be restored (https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html). """ if isinstance(node, ast.BoolOp): results = [_safe_eval(value, default) for value in node.values] if isinstance(node.op, ast.And): return all(results) else: return any(results) elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not): return not _safe_eval(node.operand, not default) else: try: return ast.literal_eval(node) except ValueError: return default
def test_boolop(self): b = ast.BoolOp(ast.And(), []) self.expr(b, "less than 2 values") b = ast.BoolOp(ast.And(), [ast.Num(3)]) self.expr(b, "less than 2 values") b = ast.BoolOp(ast.And(), [ast.Num(4), None]) self.expr(b, "None disallowed") b = ast.BoolOp(ast.And(), [ast.Num(4), ast.Name("x", ast.Store())]) self.expr(b, "must have Load context")
def rewrite_expr_z3(r, is_py_ast=True): # Rewrites py_ast expression to a str expression that could be used in z3 # Return (z3_expr_str, z3_varnames) z3_expr_str = (py_ast.dump_ast(r) if is_py_ast else r).strip() z3_expr_str = z3_expr_str.replace('.', '_').replace('[', '_').replace(']', '_') rp = py_ast.get_ast(z3_expr_str).body[0].value for node in py_ast.find_all(rp, ast.UnaryOp): if isinstance(node.op, ast.Not): if rp == node: rp = py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value else: py_ast.replace_node(rp, node, py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value) for node in py_ast.find_all(rp, ast.BoolOp): if isinstance(node.op, ast.And): if rp == node: rp = py_ast.get_ast('z3.And(' + py_ast.dump_ast(node.values[0]) + ',' + py_ast.dump_ast(node.values[1]) + ')') else: py_ast.replace_node(rp, node, py_ast.get_ast('z3.And(' + py_ast.dump_ast(node.values[0]) + ',' + py_ast.dump_ast(node.values[1]) + ')')) elif isinstance(node.op, ast.Or): if rp == node: rp = py_ast.get_ast('z3.Or(' + py_ast.dump_ast(node.values[0]) + ',' + py_ast.dump_ast(node.values[1]) + ')') else: py_ast.replace_node(rp, node, py_ast.get_ast('z3.Or(' + py_ast.dump_ast(node.values[0]) + ',' + py_ast.dump_ast(node.values[1]) + ')')) z3_expr_str = py_ast.dump_ast(rp) z3_vars = set() for node in py_ast.find_all(rp, ast.Name): z3_vars.add(node.id) return (z3_expr_str, z3_vars)
def BoolOp(op, values): if len(values) != 2: raise ValueError("Can only support two comparisons") left, right = values if op is operator.and_: return left.align(right, join='inner')[0] elif op is operator.or_: return left.align(right, join='outer')[0] else: raise ValueError("Unknown operator")
def whereeval(str_, get=None): """Evaluate a set operation string, where each Name is fetched""" if get is None: import redbiom config = redbiom.get_config() get = redbiom._requests.make_get(config) # Load is subject to indirection to simplify testing globals()['Load'] = make_Load(get) formed = ast.parse(str_, mode='eval') node_types = (ast.Compare, ast.In, ast.NotIn, ast.BoolOp, ast.And, ast.Name, ast.Or, ast.Eq, ast.Lt, ast.LtE, ast.Gt, ast.GtE, ast.NotEq, ast.Str, ast.Num, ast.Load, ast.Expression, ast.Tuple, ast.Is, ast.IsNot) for node in ast.walk(formed): if not isinstance(node, node_types): raise TypeError("Unsupported node type: %s" % ast.dump(node)) result = eval(ast.dump(formed)) # clean up global Load del Load return result
def __init__(self, operators=None, functions=None, names=None): """ Create the evaluator instance. Set up valid operators (+,-, etc) functions (add, random, get_val, whatever) and names. """ if not operators: operators = DEFAULT_OPERATORS if not functions: functions = DEFAULT_FUNCTIONS if not names: names = DEFAULT_NAMES self.operators = operators self.functions = functions self.names = names self.nodes = { ast.Num: self._eval_num, ast.Str: self._eval_str, ast.Name: self._eval_name, ast.UnaryOp: self._eval_unaryop, ast.BinOp: self._eval_binop, ast.BoolOp: self._eval_boolop, ast.Compare: self._eval_compare, ast.IfExp: self._eval_ifexp, ast.Call: self._eval_call, ast.keyword: self._eval_keyword, ast.Subscript: self._eval_subscript, ast.Attribute: self._eval_attribute, ast.Index: self._eval_index, ast.Slice: self._eval_slice, } # py3k stuff: if hasattr(ast, 'NameConstant'): self.nodes[ast.NameConstant] = self._eval_nameconstant elif isinstance(self.names, dict) and "None" not in self.names: self.names["None"] = None
def visit_Compare(self, comp): self.push_format_context() left_res, left_expl = self.visit(comp.left) res_variables = [self.variable() for i in range(len(comp.ops))] load_names = [ast.Name(v, ast.Load()) for v in res_variables] store_names = [ast.Name(v, ast.Store()) for v in res_variables] it = zip(range(len(comp.ops)), comp.ops, comp.comparators) expls = [] syms = [] results = [left_res] for i, op, next_operand in it: next_res, next_expl = self.visit(next_operand) results.append(next_res) sym = binop_map[op.__class__] syms.append(ast.Str(sym)) expl = "%s %s %s" % (left_expl, sym, next_expl) expls.append(ast.Str(expl)) res_expr = ast.Compare(left_res, [op], [next_res]) self.statements.append(ast.Assign([store_names[i]], res_expr)) left_res, left_expl = next_res, next_expl # Use pytest.assertion.util._reprcompare if that's available. expl_call = self.helper("call_reprcompare", ast.Tuple(syms, ast.Load()), ast.Tuple(load_names, ast.Load()), ast.Tuple(expls, ast.Load()), ast.Tuple(results, ast.Load())) if len(comp.ops) > 1: res = ast.BoolOp(ast.And(), load_names) else: res = load_names[0] return res, self.explanation_param(self.pop_format_context(expl_call))
def pythonast(self, args, tonative=False): return ast.BoolOp(ast.And(), args)
def pythonast(self, args, tonative=False): return ast.BoolOp(ast.Or(), args)
def ast(self): """Python AST of this predicate (construct transitively for all indirect children as well). :return: AST of describing all children predicates """ return ast.BoolOp(ast.And(), [ast.Expr(value=x.ast()) for x in self._children])
def ast(self): """Python AST of this predicate (construct transitively for all indirect children as well). :return: AST of describing all children predicates """ return ast.BoolOp(ast.Or(), [ast.Expr(value=x.ast()) for x in self._children])
def peval_boolop(state, ctx, op, values): assert type(op) in (ast.And, ast.Or) new_values = [] for value in values: state, new_value = _peval_expression(state, value, ctx) # Short circuit if is_known_value(new_value): success, bool_value = try_call(bool, args=(new_value.value,)) short_circuit_applicable = ( success and ( (type(op) == ast.And and not bool_value) or (type(op) == ast.Or and bool_value))) if short_circuit_applicable: return state, new_value # Just skip it, it won't change the BoolOp result. else: new_values.append(new_value) if len(new_values) == 0: return state, KnownValue(type(op) == ast.And) elif len(new_values) == 1: return state, new_values[0] else: return state, ast.BoolOp(op=op, values=new_values)
def _peval_comprehension_ifs(state, ifs, ctx): if len(ifs) > 0: joint_ifs = ast.BoolOp(op=ast.And(), values=ifs) state, joint_ifs_result = _peval_expression(state, joint_ifs, ctx) if is_known_value(joint_ifs_result): return state, joint_ifs_result else: return state, joint_ifs_result.values else: return state, KnownValue(value=True)
def translate_pat_Call_constructor(self, ctx, pat, scrutinee_trans): scrutinee_trans_copy = astx.copy_node(scrutinee_trans) args, keywords = pat.args, pat.keywords idx = self.idx conditions = [] binding_translations = _util.odict() for i, arg in enumerate(args): n = _util.odict_idx_of(idx, i) elt_scrutinee_trans = astx.make_Subscript_Num_Index( scrutinee_trans_copy, n) elt_condition, elt_binding_translations = ctx.translate_pat( arg, elt_scrutinee_trans) conditions.append(elt_condition) binding_translations.update(elt_binding_translations) for keyword in keywords: n = _util.odict_idx_of(idx, keyword.arg) elt_scrutinee_trans = astx.make_Subscript_Num_Index( scrutinee_trans_copy, n) elt_condition, elt_binding_translations = ctx.translate_pat( keyword.value, elt_scrutinee_trans) conditions.append(elt_condition) binding_translations.update(elt_binding_translations) condition = ast.BoolOp( op=ast.And(), values=conditions) return (condition, binding_translations)
def areDisjoint(a, b): """Are the sets of values that satisfy these two boolean constraints disjoint?""" # The easiest way to be disjoint is to have comparisons that cover different areas if type(a) == type(b) == ast.Compare: aop = a.ops[0] bop = b.ops[0] aLeft = a.left aRight = a.comparators[0] bLeft = b.left bRight = b.comparators[0] alblComp = compareASTs(aLeft, bLeft, checkEquality=True) albrComp = compareASTs(aLeft, bRight, checkEquality=True) arblComp = compareASTs(aRight, bLeft, checkEquality=True) arbrComp = compareASTs(aRight, bRight, checkEquality=True) altype = type(aLeft) in [ast.Num, ast.Str] artype = type(aRight) in [ast.Num, ast.Str] bltype = type(bLeft) in [ast.Num, ast.Str] brtype = type(bRight) in [ast.Num, ast.Str] if (type(aop) == ast.Eq and type(bop) == ast.NotEq) or \ (type(bop) == ast.Eq and type(aop) == ast.NotEq): # x == y, x != y if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0): return True elif type(aop) == type(bop) == ast.Eq: if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0): return False # x = num1, x = num2 elif alblComp == 0 and artype and brtype: return True elif albrComp == 0 and artype and bltype: return True elif arblComp == 0 and altype and brtype: return True elif arbrComp == 0 and altype and bltype: return True elif (type(aop) == ast.Lt and type(bop) == ast.GtE) or \ (type(aop) == ast.Gt and type(bop) == ast.LtE) or \ (type(aop) == ast.LtE and type(bop) == ast.Gt) or \ (type(aop) == ast.GtE and type(bop) == ast.Lt) or \ (type(aop) == ast.Is and type(bop) == ast.IsNot) or \ (type(aop) == ast.IsNot and type(bop) == ast.Is) or \ (type(aop) == ast.In and type(bop) == ast.NotIn) or \ (type(aop) == ast.NotIn and type(bop) == ast.In): if alblComp == 0 and arbrComp == 0: return True elif (type(aop) == ast.Lt and type(bop) == ast.LtE) or \ (type(aop) == ast.Gt and type(bop) == ast.GtE) or \ (type(aop) == ast.LtE and type(bop) == ast.Lt) or \ (type(aop) == ast.GtE and type(bop) == ast.Gt): if albrComp == 0 and arblComp == 0: return True elif type(a) == type(b) == ast.BoolOp: return False # for now- TODO: when is this not true? elif type(a) == ast.UnaryOp and type(a.op) == ast.Not: if compareASTs(a.operand, b, checkEquality=True) == 0: return True elif type(b) == ast.UnaryOp and type(b.op) == ast.Not: if compareASTs(b.operand, a, checkEquality=True) == 0: return True return False
def deMorganize(a): """Apply De Morgan's law throughout the code in order to canonicalize""" if not isinstance(a, ast.AST): return a # We only care about statements beginning with not if type(a) == ast.UnaryOp and type(a.op) == ast.Not: oper = a.operand top = type(oper) # not (blah and gah) == (not blah or not gah) if top == ast.BoolOp: oper.op = negate(oper.op) for i in range(len(oper.values)): oper.values[i] = deMorganize(negate(oper.values[i])) oper.negated = not oper.negated if hasattr(oper, "negated") else True transferMetaData(a, oper) return oper # not a < b == a >= b elif top == ast.Compare: oper.left = deMorganize(oper.left) oper.ops = [negate(oper.ops[0])] oper.comparators = [deMorganize(oper.comparators[0])] oper.negated = not oper.negated if hasattr(oper, "negated") else True transferMetaData(a, oper) return oper # not not blah == blah elif top == ast.UnaryOp and type(oper.op) == ast.Not: oper.operand = deMorganize(oper.operand) if eventualType(oper.operand) != bool: return a oper.operand.negated = not oper.operand.negated if hasattr(oper.operand, "negated") else True return oper.operand elif top == ast.NameConstant: if oper.value in [True, False]: oper = negate(oper) transferMetaData(a, oper) return oper elif oper.value == None: tmp = ast.NameConstant(True) transferMetaData(a, tmp) tmp.negated = True return tmp else: log("Unknown NameConstant: " + str(oper.value), "bug") return applyToChildren(a, deMorganize) ##### CLEANUP FUNCTIONS #####
def negate(op): """Return the negation of the provided operator""" if op == None: return None top = type(op) neg = not op.negated if hasattr(op, "negated") else True if top == ast.And: newOp = ast.Or() elif top == ast.Or: newOp = ast.And() elif top == ast.Eq: newOp = ast.NotEq() elif top == ast.NotEq: newOp = ast.Eq() elif top == ast.Lt: newOp = ast.GtE() elif top == ast.GtE: newOp = ast.Lt() elif top == ast.Gt: newOp = ast.LtE() elif top == ast.LtE: newOp = ast.Gt() elif top == ast.Is: newOp = ast.IsNot() elif top == ast.IsNot: newOp = ast.Is() elif top == ast.In: newOp = ast.NotIn() elif top == ast.NotIn: newOp = ast.In() elif top == ast.NameConstant and op.value in [True, False]: op.value = not op.value op.negated = neg return op elif top == ast.Compare: if len(op.ops) == 1: op.ops[0] = negate(op.ops[0]) op.negated = neg return op else: values = [] allOperands = [op.left] + op.comparators for i in range(len(op.ops)): values.append(ast.Compare(allOperands[i], [negate(op.ops[i])], [allOperands[i+1]], multiCompPart=True)) newOp = ast.BoolOp(ast.Or(multiCompOp=True), values, multiComp=True) elif top == ast.UnaryOp and type(op.op) == ast.Not and \ eventualType(op.operand) == bool: # this can mess things up type-wise return op.operand else: # this is a normal value, so put a not around it newOp = ast.UnaryOp(ast.Not(addedNot=True), op) transferMetaData(op, newOp) newOp.negated = neg return newOp
def rewrite_expr_z3_py_ast(r, is_py_ast=True): if verbose and False: print('rewrite_expr_z3_py_ast:', r) # Rewrites py_ast expression to a str expression that could be used in z3 # Return (z3_expr_str, z3_varnames) z3_expr_str = (py_ast.dump_ast(r) if is_py_ast else r).strip() z3_expr_str = z3_expr_str.replace('.', '_').replace('[', '_').replace(']', '_') rp = py_ast.get_ast(z3_expr_str).body[0].value nodes = py_ast.find_all(rp, ast.UnaryOp) while nodes != []: node = nodes[0] if isinstance(node.op, ast.Not): if rp == node: rp = py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value else: py_ast.replace_node(rp, node, py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value) nodes = py_ast.find_all(rp, ast.UnaryOp) else: nodes = nodes[1:] nodes = py_ast.find_all(rp, ast.BoolOp) while nodes != []: node = nodes[0] if isinstance(node.op, ast.And): rp_str = 'z3.And(' for value in node.values: rp_str += py_ast.dump_ast(value) + ', ' rp_str = rp_str.rstrip(', ') rp_str += ')' if rp == node: rp = py_ast.get_ast(rp_str).body[0].value else: py_ast.replace_node(rp, node, py_ast.get_ast(rp_str).body[0].value) elif isinstance(node.op, ast.Or): rp_str = 'z3.Or(' for value in node.values: rp_str += py_ast.dump_ast(value) + ', ' rp_str = rp_str.rstrip(', ') rp_str += ')' if rp == node: rp = py_ast.get_ast(rp_str).body[0].value else: py_ast.replace_node(rp, node, py_ast.get_ast(rp_str).body[0].value) nodes = py_ast.find_all(rp, ast.BoolOp) z3_expr_str = py_ast.dump_ast(rp) z3_vars = set() for node in py_ast.find_all(rp, ast.Name): z3_vars.add(node.id) if 'z3' in z3_vars: z3_vars.remove('z3') return (z3_expr_str, z3_vars)
def infer(node, context, solver, from_call=False): """Infer the type of a given AST node""" if isinstance(node, ast.Num): return infer_numeric(node, solver) elif isinstance(node, ast.Str): return solver.z3_types.string elif (sys.version_info[0] >= 3 and sys.version_info[1] >= 6 and (isinstance(node, ast.FormattedValue) or isinstance(node, ast.JoinedStr))): # Formatted strings were introduced in Python 3.6 return solver.z3_types.string elif isinstance(node, ast.Bytes): return solver.z3_types.bytes elif isinstance(node, ast.List): return infer_list(node, context, solver) elif isinstance(node, ast.Dict): return infer_dict(node, context, solver) elif isinstance(node, ast.Tuple): return infer_tuple(node, context, solver) elif isinstance(node, ast.NameConstant): return infer_name_constant(node, solver) elif isinstance(node, ast.Set): return infer_set(node, context, solver) elif isinstance(node, ast.BinOp): return infer_binary_operation(node, context, solver) elif isinstance(node, ast.BoolOp): return infer_boolean_operation(node, context, solver) elif isinstance(node, ast.UnaryOp): return infer_unary_operation(node, context, solver) elif isinstance(node, ast.IfExp): return infer_if_expression(node, context, solver) elif isinstance(node, ast.Subscript): return infer_subscript(node, context, solver) elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.Await): # Await and Async were introduced in Python 3.5 return infer(node.value, context, solver) elif isinstance(node, ast.Yield): return infer(node.value, context, solver) elif isinstance(node, ast.Compare): return infer_compare(node, context, solver) elif isinstance(node, ast.Name): return infer_name(node, context) elif isinstance(node, ast.ListComp): return infer_sequence_comprehension(node, solver.z3_types.list, context, solver) elif isinstance(node, ast.SetComp): return infer_sequence_comprehension(node, solver.z3_types.set, context, solver) elif isinstance(node, ast.DictComp): return infer_dict_comprehension(node, context, solver) elif isinstance(node, ast.Call): return infer_func_call(node, context, solver) elif isinstance(node, ast.Attribute): return infer_attribute(node, context, from_call, solver) elif isinstance(node, ast.Lambda): return _infer_lambda(node, context, solver) raise NotImplementedError("Inference for expression {} is not implemented yet.".format(type(node).__name__))
def peval_compare(state, ctx, node): if len(node.ops) == 1: return peval_single_compare(state, ctx, node.ops[0], node.left, node.comparators[0]) values = [] for value_node in [node.left] + node.comparators: state, value = _peval_expression(state, value_node, ctx) values.append(value) pair_values = [] lefts = [node.left] + node.comparators[:-1] rights = node.comparators for left, op, right in zip(lefts, node.ops, rights): state, pair_value = peval_single_compare(state, ctx, op, left, right) pair_values.append(pair_value) state, result = peval_boolop(state, ctx, ast.And(), pair_values) if is_known_value(result): return state, result if type(result) != ast.BoolOp: return state, result # Glueing non-evaluated comparisons back together. nodes = [result.values[0]] for value in result.values[1:]: last_node = nodes[-1] if (type(last_node) == ast.Compare and type(value) == ast.Compare and ast_equal(last_node.comparators[-1], value.left)): nodes[-1] = ast.Compare( left=last_node.left, ops=last_node.ops + value.ops, comparators=last_node.comparators + value.comparators) else: nodes.append(value) if len(nodes) == 1: return state, nodes[0] else: return state, ast.BoolOp(op=ast.And(), values=nodes)