def preprocess_boolean(expr, inv): if type(expr) is ast.BoolOp: if type(expr.op) is ast.And or type(expr.op) is ast.Or: new_vs = [] pos_child = None for v in expr.values: nv, is_inv = preprocess_boolean(v, inv) new_vs.append(nv) pos_child = pos_child if is_inv else nv pos_child = pos_child or new_vs[0] if (type(expr.op) is ast.And and inv) or (type(expr.op) is ast.Or and not inv): return ast.BoolOp(ast.Or(), new_vs), False new_vs.remove(pos_child) new_vs2 = [] for v in new_vs: nv, _ = preprocess_boolean(v, True) new_vs2.append(nv) expr = ast.BoolOp(ast.And(), new_vs2) expr.pos_child = pos_child return expr, False else: raise Babeception( str(type(expr.op)) + ' is not supported in boolean!') elif type(expr) is ast.UnaryOp: if type(expr.op) is ast.Not: return preprocess_boolean(expr.operand, False) if inv else preprocess_boolean( expr.operand, True) else: raise Babeception( str(type(expr.op)) + ' is not supported in boolean!') elif type(expr) is ast.Compare: if type(expr.ops[0]) is ast.NotEq or type( expr.ops[0]) is ast.Lt or type(expr.ops[0]) is ast.Gt: return preprocess_child(expr, inv) elif type(expr.ops[0]) is ast.Eq: return preprocess_boolean( ast.UnaryOp( ast.Not(), ast.Compare(expr.left, [ast.NotEq()], expr.comparators)), inv) elif type(expr.ops[0]) is ast.LtE: return preprocess_boolean( ast.UnaryOp( ast.Not(), ast.Compare(expr.left, [ast.Gt()], expr.comparators)), inv) elif type(expr.ops[0]) is ast.GtE: return preprocess_boolean( ast.UnaryOp( ast.Not(), ast.Compare(expr.left, [ast.Lt()], expr.comparators)), inv) else: raise Babeception( str(type(expr.ops[0])) + ' is not supported in boolean!') elif type(expr) is ast.Call or type(expr) is ast.Name: return preprocess_child(expr, inv) else: raise Babeception(str(type(expr)) + ' is not supported in boolean!')
def test_UnaryOp(self): self.verify(ast.UnaryOp(ast.Invert(), ast.Num(42)), '~42') self.verify(ast.UnaryOp(ast.Not(), ast.Num(42)), 'not 42') self.verify(ast.UnaryOp(ast.UAdd(), ast.Num(42)), '+42') self.verify(ast.UnaryOp(ast.USub(), ast.Num(42)), '-42') precedence = ast.UnaryOp( ast.Not(), ast.BoolOp(ast.Or(), [ast.Num(n=1), ast.Num(2)])) self.verify(precedence, 'not (1 or 2)')
def flatten(self, body, breakJump=None): """ :type body: list[ast.AST] :param breakJump: if we find some ast.Break in a while-loop, add this jump :rtype: list[ast.AST] """ r = [] for s in body: if isinstance(s, ast.If): a = ast.UnaryOp() a.op = ast.Not() a.operand = s.test goto_final_stmnt = self.make_jump() if s.orelse: goto_orelse_stmnt = self.make_jump() r += [ast.If(test=a, body=[goto_orelse_stmnt], orelse=[])] else: goto_orelse_stmnt = None r += [ast.If(test=a, body=[goto_final_stmnt], orelse=[])] r += self.flatten(s.body, breakJump=breakJump) if s.orelse: r += [goto_final_stmnt] r += [GotoLabel(goto_orelse_stmnt.label)] r += self.flatten(s.orelse, breakJump=breakJump) r += [GotoLabel(goto_final_stmnt.label)] elif isinstance(s, ast.While): if s.orelse: raise NotImplementedError goto_repeat_stmnt = self.make_jump() r += [GotoLabel(goto_repeat_stmnt.label)] a = ast.UnaryOp() a.op = ast.Not() a.operand = s.test goto_final_stmnt = self.make_jump() r += [ast.If(test=a, body=[goto_final_stmnt], orelse=[])] r += self.flatten(s.body, breakJump=goto_final_stmnt) r += [goto_repeat_stmnt] r += [GotoLabel(goto_final_stmnt.label)] elif isinstance(s, ast.For): raise NotImplementedError elif isinstance(s, (ast.TryExcept, ast.TryFinally) if PY2 else ast.Try): raise NotImplementedError elif isinstance(s, ast.Break): assert breakJump, "found break in unexpected scope" r += [breakJump] else: r += [s] return r
def invert(node): inverse = { ast.Eq: ast.NotEq, ast.NotEq: ast.Eq, ast.Lt: ast.GtE, ast.LtE: ast.Gt, ast.Gt: ast.LtE, ast.GtE: ast.Lt, ast.Is: ast.IsNot, ast.IsNot: ast.Is, ast.In: ast.NotIn, ast.NotIn: ast.In } if type(node) == ast.Compare: op = type(node.ops[0]) inverse_node = ast.Compare(left=node.left, ops=[inverse[op]()], comparators=node.comparators) elif type(node) == ast.NameConstant and node.value in [True, False]: inverse_node = ast.NameConstant(value=not node.value) else: inverse_node = ast.UnaryOp(op=ast.Not(), operand=node) return inverse_node
def pre_If(self): if hasattr(self.cur_node, 'custom_id') \ and self.cur_node.custom_id == self.target \ and SplitAndConditional.is_applicable(self.cur_node): self.applied = True parent_list = self.parent and_left = self.cur_node.test.values[0] and_right = self.cur_node.test.values[1] body_list = self.cur_node.body orelse_list = self.cur_node.orelse new_upper_if = ast.If() new_lower_if = ast.If() new_else_if = ast.If() new_upper_if.test = and_left new_upper_if.body = [new_lower_if] new_upper_if.orelse = [] new_lower_if.test = and_right new_lower_if.body = body_list new_lower_if.orelse = [] if len(orelse_list) > 0: new_else_if.test = ast.UnaryOp(ast.Not(), self.cur_node.test) new_else_if.body = orelse_list new_else_if.orelse = [] index = parent_list.index(self.cur_node) parent_list[index:index + 1] = [new_upper_if, new_else_if] else: self.replace(new_upper_if)
def __parseRuleNode(node): tag = node.tagName if tag == 'Or': return __parseBoolOp(node, ast.Or()) elif tag == 'And': return __parseBoolOp(node, ast.And()) elif tag == 'Not': expr = __parseBoolOp(node, ast.Or()) return ast.UnaryOp(ast.Not(), expr) if expr else None elif tag == 'All': return ast.Name('True', ast.Load()) elif tag == 'Category': category = _get_node_text(node) return ast.Compare(left=ast.Str(category), ops=[ast.In()], comparators=[ ast.Attribute(value=ast.Name(id='menuentry', ctx=ast.Load()), attr='Categories', ctx=ast.Load()) ]) elif tag == 'Filename': filename = _get_node_text(node) return ast.Compare(left=ast.Str(filename), ops=[ast.Eq()], comparators=[ ast.Attribute(value=ast.Name(id='menuentry', ctx=ast.Load()), attr='DesktopFileID', ctx=ast.Load()) ])
def to_node(self): value = self.value operator = self.operator if operator == 'not': return ast.UnaryOp(ast.Not(), value.to_node()) else: return value.to_node()
def visit_Assert(self, assert_): """Return the AST statements to replace the ast.Assert instance. This rewrites the test of an assertion to provide intermediate values and replace it with an if statement which raises an assertion error with a detailed explanation in case the expression is false. """ if isinstance(assert_.test, ast.Tuple) and len(assert_.test.elts) >= 1: from _pytest.warning_types import PytestWarning import warnings warnings.warn_explicit( PytestWarning( "assertion is always true, perhaps remove parentheses?"), category=None, filename=str(self.module_path), lineno=assert_.lineno, ) self.statements = [] self.variables = [] self.variable_counter = itertools.count() self.stack = [] self.on_failure = [] self.push_format_context() # Rewrite assert into a bunch of statements. top_condition, explanation = self.visit(assert_.test) # Create failure message. body = self.on_failure negation = ast.UnaryOp(ast.Not(), top_condition) self.statements.append(ast.If(negation, body, [])) if assert_.msg: assertmsg = self.helper("format_assertmsg", assert_.msg) explanation = "\n>assert " + explanation else: assertmsg = ast.Str("") explanation = "assert " + explanation template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation)) msg = self.pop_format_context(template) fmt = self.helper("format_explanation", msg) err_name = ast.Name("AssertionError", ast.Load()) exc = ast_Call(err_name, [fmt], []) if sys.version_info[0] >= 3: raise_ = ast.Raise(exc, None) else: raise_ = ast.Raise(exc, None, None) body.append(raise_) # Clear temporary variables by setting them to None. if self.variables: variables = [ ast.Name(name, ast.Store()) for name in self.variables ] clear = ast.Assign(variables, _NameConstant(None)) self.statements.append(clear) # Fix line numbers. for stmt in self.statements: set_location(stmt, assert_.lineno, assert_.col_offset) return self.statements
def visit_BoolOp(self, boolop: ast.BoolOp) -> VisitExprReturnT: """ Due to short-circuiting, desugars boolop into nested if-statements before being flattened. For example, this expression:: x = v1 and v2 and v3 gets desugared into:: x = v1 if x: # if_test (`x` for `and`, `not x` for `or`) x = v2 if x: x = v3 This statement block then gets flattened. The strategy is similar for the `or` operation. """ result_id = self.next_symbol_id() result_node = load(result_id) if_test: ast.expr if isinstance(boolop.op, ast.And): if_test = result_node elif isinstance(boolop.op, ast.Or): if_test = ast.UnaryOp(op=ast.Not(), operand=result_node) else: assert False, f"BoolOp operation not recognized: {boolop}" body: List[ast.stmt] = [assign(result_id, boolop.values[-1])] for value in reversed(boolop.values[:-1]): # Iteratively wrap body in if-statements. body = [ast.If(test=if_test, body=body, orelse=[])] body.insert(0, assign(result_id, value)) return load(result_id), self.visit_stmt_list(body)
def test_visit_UnaryOp(self, get_logger_mock): node = MagicMock() node.operand = "operand" node.op = ast.Not() analyzer = ExpressionAnalyzer() self.assertIsNone(analyzer.visit_UnaryOp(node)) self.assertEqual(analyzer.parts, ["not", " ", "operand"]) node.op = ast.Invert() analyzer = ExpressionAnalyzer() self.assertIsNone(analyzer.visit_UnaryOp(node)) self.assertEqual(analyzer.parts, ["~", "operand"]) node.op = ast.UAdd() analyzer = ExpressionAnalyzer() self.assertIsNone(analyzer.visit_UnaryOp(node)) self.assertEqual(analyzer.parts, ["+", "operand"]) node.op = ast.USub() analyzer = ExpressionAnalyzer() self.assertIsNone(analyzer.visit_UnaryOp(node)) self.assertEqual(analyzer.parts, ["-", "operand"]) node.op = ast.Import() analyzer = ExpressionAnalyzer() self.assertIsNone(analyzer.visit_UnaryOp(node)) self.assertEqual(analyzer.parts, ["...", "operand"]) get_logger_mock().warning.assert_called_once_with(ANY)
def visit_BinOp(self, node): if isinstance(node.op, ast.NotIn): return ast.copy_location( ast.UnaryOp(ast.Not(), ast.BinOp(node.left, ast.In(), node.right)), node) return node
def mutate(cls, node): if node not in config.visited_nodes: if config.parent_dict[node].__class__ in [ ast.If, ast.While, ast.IfExp, ast.Assert ]: if node.__class__ is ast.UnaryOp: config.mutated = True original_node = deepcopy(node) parent = config.parent_dict[node] del config.parent_dict[node] node = node.operand config.parent_dict[node] = parent config.node_pairs[node] = original_node config.current_mutated_node = node elif node.__class__ is ast.BoolOp: config.mutated = True original_node = deepcopy(node) parent = config.parent_dict[node] del config.parent_dict[node] unary_op_node = ast.UnaryOp() unary_op_node.op = ast.Not() unary_op_node.operand = node node = unary_op_node config.parent_dict[node] = parent config.node_pairs[node] = original_node config.current_mutated_node = node return node
def create_logical_factor_node(self, logical_factor): if logical_factor.sign in ['!', 'not']: return ast.UnaryOp(ast.Not(), self.to_node(logical_factor.operand)) elif logical_factor.sign is None: return self.to_node(logical_factor.operand) else: raise
def negate_expr(node): """ Negates an AST expression by adding a `Not` AST node in front of it. """ # Negation support for SymPy expressions if isinstance(node, sympy.Basic): return sympy.Not(node) # Support for numerical constants if isinstance(node, numbers.Number): return str(not node) # Negation support for strings (most likely dace.Data.Scalar names) if isinstance(node, str): return "not ({})".format(node) from dace.properties import CodeBlock # Avoid import loop if isinstance(node, CodeBlock): node = node.code if hasattr(node, "__len__"): if len(node) > 1: raise ValueError("negate_expr only expects " "single expressions, got: {}".format(node)) expr = node[0] else: expr = node if isinstance(expr, ast.Expr): expr = expr.value newexpr = ast.Expr(value=ast.UnaryOp(op=ast.Not(), operand=expr)) newexpr = ast.copy_location(newexpr, expr) return ast.fix_missing_locations(newexpr)
def visit_BoolOp(self, boolop): res_var = self.variable() expl_list = self.assign(ast.List([], ast.Load())) app = ast.Attribute(expl_list, "append", ast.Load()) is_or = int(isinstance(boolop.op, ast.Or)) body = save = self.statements fail_save = self.on_failure levels = len(boolop.values) - 1 self.push_format_context() # Process each operand, short-circuting if needed. for i, v in enumerate(boolop.values): if i: fail_inner = [] # cond is set in a prior loop iteration below self.on_failure.append(ast.If(cond, fail_inner, [])) # noqa self.on_failure = fail_inner self.push_format_context() res, expl = self.visit(v) body.append(ast.Assign([ast.Name(res_var, ast.Store())], res)) expl_format = self.pop_format_context(ast.Str(expl)) call = ast_Call(app, [expl_format], []) self.on_failure.append(ast.Expr(call)) if i < levels: cond = res if is_or: cond = ast.UnaryOp(ast.Not(), cond) inner = [] self.statements.append(ast.If(cond, inner, [])) self.statements = body = inner self.statements = save self.on_failure = fail_save expl_template = self.helper("format_boolop", expl_list, ast.Num(is_or)) expl = self.pop_format_context(expl_template) return ast.Name(res_var, ast.Load()), self.explanation_param(expl)
def invert(node): """ Invert the operation in an ast node object (get its negation). Args: node: An ast node object. Returns: An ast node object containing the inverse (negation) of the input node. """ inverse = {ast.Eq: ast.NotEq, ast.NotEq: ast.Eq, ast.Lt: ast.GtE, ast.LtE: ast.Gt, ast.Gt: ast.LtE, ast.GtE: ast.Lt, ast.Is: ast.IsNot, ast.IsNot: ast.Is, ast.In: ast.NotIn, ast.NotIn: ast.In} if type(node) == ast.Compare: op = type(node.ops[0]) inverse_node = ast.Compare(left=node.left, ops=[inverse[op]()], comparators=node.comparators) elif type(node) == ast.NameConstant and node.value in [True, False]: inverse_node = ast.NameConstant(value=not node.value) else: inverse_node = ast.UnaryOp(op=ast.Not(), operand=node) return inverse_node
def invert( node): # to get the opposite condition so that we can get the exitcase inverse = { ast.Eq: ast.NotEq, ast.NotEq: ast.Eq, ast.Lt: ast.GtE, ast.LtE: ast.Gt, ast.Gt: ast.LtE, ast.GtE: ast.Lt, ast.Is: ast.IsNot, ast.IsNot: ast.Is, ast.In: ast.NotIn, ast.NotIn: ast.In } if type(node) == ast.Compare: op = type(node.ops[0]) inverse_node = ast.Compare(left=node.left, ops=[inverse[op]()], comparators=node.comparators) elif type(node) == ast.BinOp and type(node.op) in inverse: op = type(node.op) inverse_node = ast.BinOp(node.left, inverse[op](), node.right) elif type(node) == ast.NameConstant and node.value in [True, False]: inverse_node = ast.NameConstant(value=not node.value) else: inverse_node = ast.UnaryOp(op=ast.Not(), operand=node) return inverse_node
def parse_rule_node(self, node): tag = node.tag if tag == 'Or': return self.parse_bool_op(node, ast.Or()) elif tag == 'And': return self.parse_bool_op(node, ast.And()) elif tag == 'Not': expr = self.parse_bool_op(node, ast.Or()) return ast.UnaryOp(ast.Not(), expr) if expr else None elif tag == 'All': return _ast_const('True') elif tag == 'Category': category = node.text return ast.Compare(left=ast.Str(category), ops=[ast.In()], comparators=[ ast.Attribute(value=ast.Name( id='menuentry', ctx=ast.Load()), attr='Categories', ctx=ast.Load()) ]) elif tag == 'Filename': filename = node.text return ast.Compare(left=ast.Str(filename), ops=[ast.Eq()], comparators=[ ast.Attribute(value=ast.Name( id='menuentry', ctx=ast.Load()), attr='DesktopFileID', ctx=ast.Load()) ])
def invert_ast_node(node): if type(node) == ast.UnaryOp: return node.operand else: new_node = ast.UnaryOp() new_node.op = ast.Not() new_node.operand = node return new_node
def visit_UnaryOp(self, unaryop_node): if isinstance(unaryop_node.op, ast.Not): format_string = "Asserted not {} but found it to be truthy" name = '@contexts_assertion_var' statements = [self.assign(name, unaryop_node.operand)] msg = self.format(format_string, [self.repr(self.load(name))]) statements.append(ast.Assert(ast.UnaryOp(ast.Not(), self.load(name)), msg)) return statements
def pre_If(self): if hasattr(self.cur_node, 'custom_id') \ and self.cur_node.custom_id == self.target \ and MergeNestedIfStatement.is_applicable(self.cur_node): self.applied = True parent_list = self.parent cur_index = self.parent.index(self.cur_node) first_if = self.cur_node first_test = first_if.test first_body = first_if.body first_else = first_if.orelse second_if = [ node for node in first_body if isinstance(node, ast.If) ][0] second_index = first_body.index(second_if) second_test = second_if.test second_body = second_if.body second_else = second_if.orelse results = list() if first_body[:second_index]: results.append( ast.If(first_test, first_body[:second_index], [])) if second_body: a_and_b = ast.BoolOp(ast.And(), [first_test, second_test]) if_a_and_b = ast.If(a_and_b, second_body, []) results.append(if_a_and_b) if second_else: a_and_not_b = ast.BoolOp( ast.And(), [first_test, ast.UnaryOp(ast.Not(), second_test)]) if_a_and_not_b = ast.If(a_and_not_b, second_else, []) if_a_and_b.orelse = [if_a_and_not_b] if first_body[second_index + 1:]: results.append( ast.If(first_test, first_body[second_index + 1:], first_else)) elif first_else: results.append( ast.If(ast.UnaryOp(ast.Not(), first_test), first_else, [])) self.parent[cur_index:cur_index + 1] = results
def mutate(self, node, _): """ Add the 'not' keyword. Note: this will negate the entire if condition. """ if hasattr(node, 'test'): node.test = ast.UnaryOp(op=ast.Not(), operand=node.test) return node
def UnaryopInvert(self, node: Type[ast.AST]) -> Type[ast.AST]: if type(node.op) == ast.UAdd: return ast.UnaryOp(op=ast.USub(), operand=node.operand) elif type(node.op) == ast.USub: return ast.UnaryOp(op=ast.UAdd(), operand=node.operand) elif type(node.op) == ast.Invert: return ast.UnaryOp(op=ast.Not(), operand=node) else: return node.operand
def unary_action(s, loc, tokens): op_char, operand = tokens[0], tokens[1] if op_char == '+': return operand elif op_char == '-': return ast.UnaryOp(op=ast.USub(), operand=operand) elif op_char == '~': return ast.UnaryOp(op=ast.Invert(), operand=operand) else: # not return ast.UnaryOp(op=ast.Not(), operand=operand)
def visit_UnaryOper(self, node: UnaryOper, *args, **kwargs) -> C.unaryop: if node == UnaryOper.Invert: return C.Invert elif node == UnaryOper.Not: return C.Not() elif node == UnaryOper.UAdd: return C.UAdd elif node == UnaryOper.USub: return C.USub else: raise Exception(f'unknown UnaryOper {node!r}')
def CmpOp_NotIn(self, left, comparator): self.visit( ast.UnaryOp( ast.Not(), ast.Compare( left, [ast.In()], [comparator] ) ) )
def visit_IfExp(self, node: ast.IfExp) -> None: """Add ``If`` condition to guard.""" # Visit then branch. self.current_guard.append(node.test) self.visit(node.body) self.current_guard.pop() # Visit else branch. condition = ast.UnaryOp(ast.Not(), node.test) self.current_guard.append(condition) self.visit(node.orelse) self.current_guard.pop()
def not_expr(s: Scanner) -> ast.expr: if s.accept(TokenType.NOT): return ast.UnaryOp(ast.Not(), not_expr(s)) if s.accept(TokenType.LPAREN): ret = expr(s) s.accept(TokenType.RPAREN, reject=True) return ret ident = s.accept(TokenType.IDENT) if ident: return ast.Name(IDENT_PREFIX + ident.value, ast.Load()) s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT))
def make_not(cursor_trail, tree): selected_node = core_logic.get_node_at_cursor(cursor_trail, tree) expr = selected_node if isinstance(selected_node, ast.expr) else make_expression() if isinstance(expr, ast.UnaryOp) and isinstance(expr.op, ast.Not): # Having not not x doesn't really make sense # So let's just remove the not in this case return expr.operand return ast.UnaryOp(op=ast.Not(), operand=expr)
def negate_expr(node): """ Negates an AST expression by adding a `Not` AST node in front of it. """ if hasattr(node, "__len__"): if len(node) > 1: raise ValueError("negate_expr only expects " "single expressions, got: {}".format(node)) expr = node[0] else: expr = node newexpr = ast.Expr(value=ast.UnaryOp(op=ast.Not(), operand=expr)) newexpr = ast.copy_location(newexpr, expr) return ast.fix_missing_locations(newexpr)