def rename_variables(astnode, env): if isinstance(astnode, ast.BoolOp): fn = 'z3.And' if isinstance(astnode.op, ast.And) else 'z3.Or' return ast.Call( ast.Name(fn, None), [rename_variables(i, env) for i in astnode.values], []) elif isinstance(astnode, ast.BinOp): return ast.BinOp( rename_variables(astnode.left, env), astnode.op, rename_variables(astnode.right, env)) elif isinstance(astnode, ast.UnaryOp): if isinstance(astnode.op, ast.Not): return ast.Call( ast.Name('z3.Not', None), [rename_variables(astnode.operand, env)], []) else: return ast.UnaryOp(astnode.op, rename_variables(astnode.operand, env)) elif isinstance(astnode, ast.Call): return ast.Call(astnode.func, [rename_variables(i, env) for i in astnode.args], astnode.keywords) elif isinstance(astnode, ast.Compare): return ast.Compare( rename_variables(astnode.left, env), astnode.ops, [rename_variables(i, env) for i in astnode.comparators]) elif isinstance(astnode, ast.Name): if astnode.id not in env: env[astnode.id] = 0 num = env[astnode.id] return ast.Name('_%s_%d' % (astnode.id, num), astnode.ctx) elif isinstance(astnode, ast.Return): return ast.Return(rename_variables(astnode.value, env)) else: return astnode
def visit_Num(self, node): should_parenthesize = isinstance(node.n, int) and node.n >= 0 and \ isinstance(self.get_parent_node(), ast.Attribute) should_parenthesize = should_parenthesize or ( isinstance(node.n, complex) and node.n.real == 0.0 and (node.n.imag < 0 or node.n.imag == -0.0)) # Always parenthesize in Python 2, because there "-(1)" and "-1" produce a different AST. if not should_parenthesize and (isinstance(node.n, complex) or node.n < 0 or sys.version_info < (3, 0)): parent_node = self.get_parent_node() should_parenthesize = isinstance(parent_node, ast.UnaryOp) and \ isinstance(parent_node.op, ast.USub) and \ hasattr(parent_node, 'lineno') with self.parenthesize_if(should_parenthesize): if isinstance(node.n, float) and abs(node.n) > sys.float_info.max: # otherwise we write inf, which won't be parsed back right # I don't know of any way to write nan with a literal self.write('1e1000' if node.n > 0 else '-1e1000') elif isinstance(node.n, (int, _long, float)) and node.n < 0: # needed for precedence to work correctly me = self.node_stack.pop() if isinstance(node.n, int): val = str(-node.n) else: val = repr(type(node.n)(-node.n)) # - of long may be int self.visit(ast.UnaryOp(op=ast.USub(), operand=ast.Name(id=val))) self.node_stack.append(me) else: self.write(repr(node.n))
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 prefix_vars(astnode, prefix): if isinstance(astnode, ast.BoolOp): return ast.BoolOp(astnode.op, [prefix_vars(i, prefix) for i in astnode.values], []) elif isinstance(astnode, ast.BinOp): return ast.BinOp( prefix_vars(astnode.left, prefix), astnode.op, prefix_vars(astnode.right, prefix)) elif isinstance(astnode, ast.UnaryOp): return ast.UnaryOp(astnode.op, prefix_vars(astnode.operand, prefix)) elif isinstance(astnode, ast.Call): return ast.Call(prefix_vars(astnode.func, prefix), [prefix_vars(i, prefix) for i in astnode.args], astnode.keywords) elif isinstance(astnode, ast.Compare): return ast.Compare( prefix_vars(astnode.left, prefix), astnode.ops, [prefix_vars(i, prefix) for i in astnode.comparators]) elif isinstance(astnode, ast.Name): if astnode.id in {'And', 'Or', 'Not'}: return ast.Name('z3.%s' % (astnode.id), astnode.ctx) else: return ast.Name('%s%s' % (prefix, astnode.id), astnode.ctx) elif isinstance(astnode, ast.Return): return ast.Return(prefix_vars(astnode.value, env)) else: return astnode
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 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 transform(node, tofloat=True): if isinstance(node, ast.AST): if isinstance(node, ast.Name) and isinstance( node.ctx, ast.Load) and node.id == "pi": out = ast.Num(3.141592653589793) # TMath::Pi() elif isinstance(node, ast.Num): out = ast.Num(float(node.n)) elif isinstance(node, ast.BinOp) and isinstance( node.op, (ast.Add, ast.Sub, ast.Mult, ast.Div)): out = ast.BinOp(transform(node.left), node.op, transform(node.right)) elif isinstance(node, ast.UnaryOp) and isinstance( node.op, ast.USub): out = ast.UnaryOp(node.op, transform(node.operand)) elif isinstance(node, ast.List) and isinstance( node.ctx, ast.Load) and len(node.elts) == 2: out = ast.List([ transform(node.elts[0]), transform(node.elts[1]) ], node.ctx) elif isinstance(node, ast.List) and isinstance( node.ctx, ast.Load) and len( node.elts) == 3 and isinstance( node.elts[2], ast.Num): out = ast.List([ transform(node.elts[0]), transform(node.elts[1]), node.elts[2] ], node.ctx) else: raise Exception(ast.dump(node)) out.lineno, out.col_offset = node.lineno, node.col_offset return out else: raise Exception(ast.dump(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.Name('True', ast.Load()) 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 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)): raise NotImplementedError elif isinstance(s, ast.Break): assert breakJump, "found break in unexpected scope" r += [breakJump] else: r += [s] return r
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 compile_unary_operator(self, expression): ops = {"not": ast.Not, "~": ast.Invert} operator = expression.pop(0) operand = expression.pop(0) return ast.UnaryOp(op=ops[operator](), operand=self.compile(operand), lineno=operator.start_line, col_offset=operator.start_column)
def visit_UnaryOp(self, node): 'Change ~x to - x - 1' if isinstance(node.op, ast.Invert): return ast.BinOp(ast.UnaryOp(ast.USub(), node.operand), ast.Add(), ast.Num(-1)) return self.generic_visit(node)
def visit_unaryop(self, node): # Converts 'not' into '~' which NumExpr supports if isinstance(node.op, ast.Not): return ast.UnaryOp(op=ast.Invert(), operand=self.visit(node.operand)) elif isinstance(node.op, ast.USub): return node raise NotImplementedError(type(node.op))
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 visit_UnaryOp(self, node: UnaryOp, *args, **kwargs) -> C.UnaryOp: op = self.visit(node.op, *args, **kwargs) operand = self.visit(node.operand, *args, **kwargs) return C.UnaryOp( op=op, operand=operand, )
def visit_Index(self, node: ast.Index) -> ast.AST: """Index visit e.g. ``i[0], i[0][1]``.""" self.generic_visit(node) log_header = f"visit_Index: {self.src_file}:" # Index Node has a value attribute that can be either Num node or UnaryOp node # depending on whether the value is positive or negative. n_value = node.value idx = None index_mutations = { "Index_NumZero": ast.Num(n=0), "Index_NumPos": ast.Num(n=1), "Index_NumNeg": ast.UnaryOp(op=ast.USub(), operand=ast.Num(n=1)), } node_span = NodeSpan(n_value) locidx_kwargs = { "ast_class": "Index", "lineno": node_span.lineno, "col_offset": node_span.col_offset, "end_lineno": node_span.end_lineno, "end_col_offset": node_span.end_col_offset, } # index is a non-negative number e.g. i[0], i[1] if isinstance(n_value, ast.Num): # positive integer case if n_value.n != 0: idx = LocIndex(op_type="Index_NumPos", **locidx_kwargs) # type: ignore self.locs.add(idx) # zero value case else: idx = LocIndex(op_type="Index_NumZero", **locidx_kwargs) # type: ignore self.locs.add(idx) # index is a negative number e.g. i[-1] if isinstance(n_value, ast.UnaryOp): idx = LocIndex(op_type="Index_NumNeg", **locidx_kwargs) # type: ignore self.locs.add(idx) if idx == self.target_idx and self.mutation and not self.readonly: LOGGER.debug("%s mutating idx: %s with %s", log_header, self.target_idx, self.mutation) mutation = index_mutations[self.mutation] # uses AST.fix_missing_locations since the values of ast.Num and ast.UnaryOp also need # lineno and col-offset values. This is a recursive fix. return ast.fix_missing_locations( ast.copy_location(ast.Index(value=mutation), node)) LOGGER.debug("%s (%s, %s): no mutations applied.", log_header, n_value.lineno, n_value.col_offset) return node
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 resolve_literal_binop(node, ctxt): left = _resolve_literal(node.left, ctxt) right = _resolve_literal(node.right, ctxt) lliteral = not isinstance(left, ast.AST) rliteral = not isinstance(right, ast.AST) if lliteral and rliteral: try: return _collapse_map[type(node.op)](left, right) except Exception: warnings.warn( "Binary op collapse failed. Collapsing skipped, but executing this function will likely fail." " Error was:\n{}".format(traceback.format_exc())) return node else: if lliteral or rliteral: for operand, other_operand in zip([left, right], [right, left]): if isinstance(operand, ast.AST): continue # Math deduction (symmetric) if (isinstance(node.op, ast.Add) and operand == 0): return other_operand if isinstance(node.op, ast.Mult): if operand == 0: return 0 if operand == 1: return other_operand if operand == -1: return ast.UnaryOp(ast.USub(), operand=other_operand) # Math deduction (asymmetric) if (isinstance(node.op, (ast.Div, ast.FloorDiv, ast.Pow, ast.Mod)) and left == 0): return 0 if (isinstance(node.op, (ast.Div, ast.Pow)) and right == 1): return left if (isinstance(node.op, ast.Sub) and left == 0): return ast.UnaryOp(op=ast.USub(), operand=right) if (isinstance(node.op, ast.Sub) and right == 0): return left # Get the best resolution of the left and right, as AST nodes left = resolve_literal(node.left, ctxt) right = resolve_literal(node.right, ctxt) return ast.BinOp(left=left, right=right, op=node.op)
def p_unary_expression_1(self, p): """ unary_expression : postfix_expression | unary_operator cast_expression """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.UnaryOp(p[1], p[2], coord=self._token_coord(p, 1))
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 p_unary_expr_minus_primary(t): #'''unary_expr : MINUS primary %prec UMINUS''' '''unary_expr : MINUS primary''' usub = ast.USub() usub.lineno = t.lineno(1) usub.col_offset = -1 # XXX t[0] = ast.UnaryOp(usub, t[2]) t[0].lineno = t.lineno(2) t[0].col_offset = -1 # XXX
def simplify(self): op, right = self.op, self.right if isinstance(right, NumExp) and not isinstance(op, str): # simplify and return NumExp a = self._init_expr(right.to_ast()) c = self._init_expr(ast.UnaryOp(op, a)) return NumExp(eval(compile(ast.Expression(c), "<string>", "eval"))) else: return self
def compile_maths_expression_sub(self, expression): if len(expression) > 2: return self.compile_maths_expression(expression) else: arg = expression[1] return ast.UnaryOp(op=ast.USub(), operand=self.compile(arg), lineno=arg.start_line, col_offset=arg.start_column)
def simplify(self): op, right = self.op, self.right if isinstance(right, NumExp) and not isinstance(op, str): # simplify and return NumExp a = self._init_expr(ast.Num(right.value)) c = self._init_expr(ast.UnaryOp(op, a)) return NumExp(eval(compile(ast.Expression(c), '<string>', 'eval'))) else: return self
def p_postfix_expr_nobf(self, p): """postfix_expr_nobf : left_hand_side_expr_nobf | left_hand_side_expr_nobf PLUSPLUS | left_hand_side_expr_nobf MINUSMINUS """ if len(p) == 2: p[0] = p[1] else: p[0] = ast.UnaryOp(op=p[2], value=p[1], postfix=True)
def factor_rewrite(mark: Tokenizer, factor, power): return power if power else ast.UnaryOp(**(loc @ mark), op={ '~': ast.Invert, '+': ast.UAdd, '-': ast.USub }[mark.value](), operand=factor)
def visit_Assert(self, assert_): """Return the AST statements to replace the ast.Assert instance. This re-writes 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 self.config is not None: fslocation = (self.module_path, assert_.lineno) self.config.warn('R1', 'assertion is always true, perhaps ' 'remove parentheses?', fslocation=fslocation) 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 if _MARK_ASSERTION_INTROSPECTION: explanation = 'dessert* ' + explanation template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation)) msg = self.pop_format_context(template) fmt = self.helper("format_explanation", msg, assertmsg) 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 create_factor_node(self, factor): base_node = self.to_node(factor.base) # When no parenthesis, exponentiations are read from right to left if len(factor.exponents) != 0: last_exponent_index = len(factor.exponents) - 1 right_node = self.to_node(factor.exponents[last_exponent_index]) for i in range(last_exponent_index - 1, -1, -1): right_node = ast.BinOp(self.to_node(factor.exponents[i]), ast.Pow(), right_node) base_node = ast.BinOp(base_node, ast.Pow(), right_node) if factor.sign in ['-', 'minus']: return ast.UnaryOp(ast.USub(), base_node) elif factor.sign in ['+', 'plus']: return ast.UnaryOp(ast.UAdd(), base_node) elif factor.sign is None: return base_node else: raise
def generate(self, element: Element, GC: GenerationContext): acode = element.code operand_element = acode[1] with GC.let(domain=ExDom): operand_code = GC.generate(operand_element) return expr_wrap(ast.UnaryOp(self.OP(), operand_code), GC)
def UnaryFunc(self, node, **kw): if isinstance(node.op, USub): return ast.UnaryOp(op=self(node.op), operand=self(node.arg), **_linearg) else: return ast.Call(func=self(node.op), args=[self(node.arg)], keywords=[], **_linearg)