def visit_BinOp(self, node): if node.op.__class__ in self.operators: sympy_class = self.operators[node.op.__class__] right = self.visit(node.right) if isinstance(node.op, ast.Sub): right = ast.UnaryOp(op=ast.USub(), operand=right) elif isinstance(node.op, ast.Div): right = ast.Call( func=ast.Name(id='Pow', ctx=ast.Load()), args=[right, ast.UnaryOp(op=ast.USub(), operand=ast.Num(1))], keywords=[ast.keyword(arg='evaluate', value=ast.Name(id='False', ctx=ast.Load()))], starargs=None, kwargs=None ) new_node = ast.Call( func=ast.Name(id=sympy_class, ctx=ast.Load()), args=[self.visit(node.left), right], keywords=[ast.keyword(arg='evaluate', value=ast.Name(id='False', ctx=ast.Load()))], starargs=None, kwargs=None ) if sympy_class in ('Add', 'Mul'): # Denest Add or Mul as appropriate new_node.args = self.flatten(new_node.args, sympy_class) return new_node return node
def test_BinOp(self): for node, op in self.operators.items(): self.verify(ast.BinOp(ast.Num(2), node(), ast.Num(3)), '2{}3'.format(op)) # 1 + 2 * 3 = BinOp(2 + BinOp(2 * 3)) mult = ast.BinOp(ast.Num(2), ast.Mult(), ast.Num(3)) expr = ast.BinOp(ast.Num(1), ast.Add(), mult) self.verify(expr, '1+2*3') # (1 + 2) * 3 = BinOp(BinOp(1 + 2) * 3) add = ast.BinOp(ast.Num(1), ast.Add(), ast.Num(2)) expr = ast.BinOp(add, ast.Mult(), ast.Num(3)) self.verify(expr, '(1+2)*3') # 2 * 3 + 1 = BinOp(BinOp(2 * 3) + 1) expr = ast.BinOp(mult, ast.Add(), ast.Num(1)) self.verify(expr, '2*3+1') # 3 * (1 + 2) = BinOp(3 * BinOp(1 + 2)) expr = ast.BinOp(ast.Num(3), ast.Mult(), add) self.verify(expr, '3*(1+2)') # 3 - (1 + 2) = BinOp(3 - (BinOp1 + 2)) expr = ast.BinOp(ast.Num(3), ast.Sub(), add) self.verify(expr, '3-(1+2)') # Deal with Pow's "special" precedence compared to unary operators. self.verify(ast.BinOp(ast.Num(-1), ast.Pow(), ast.Num(2)), '(-1)**2') self.verify( ast.UnaryOp(ast.USub(), ast.BinOp(ast.Num(1), ast.Pow(), ast.Num(2))), '-1**2') self.verify( ast.BinOp(ast.Num(1), ast.Pow(), ast.UnaryOp(ast.USub(), ast.Num(2))), '1**(-2)')
def to_node(n) -> ast.AST: if isinstance(n, int): return ast.Num(n) if n >= 0 else ast.UnaryOp( ast.USub(), ast.Num(abs(n))) elif isinstance(n, float): return ast.Num(n) if math.copysign(1.0, n) > 0.0 else ast.UnaryOp( ast.USub(), ast.Num(abs(n))) elif isinstance(n, complex): node = ast.parse(str(n), mode='eval') return node.body raise ValueError(n)
def test_docexample(self): # used to fail on ironpython for various reason node = ast.UnaryOp(ast.USub(), ast.Num(5, lineno=0, col_offset=0), lineno=0, col_offset=0) # the same with zero argument constructors node = ast.UnaryOp() node.op = ast.USub() node.operand = ast.Num() node.operand.n = 5 node.operand.lineno = 0 node.operand.col_offset = 0 node.lineno = 0 node.col_offset = 0
def visitUnary_expression(self, ctx: PlSqlParser.Unary_expressionContext): ret = self.visitChildren(ctx) value = ret[0] sign = ctx.children[0].getText() if sign == "-": return ast.UnaryOp(op=ast.USub(), operand=value) return ret
def p_factor(p): '''factor : "+" factor | "-" factor | "~" factor | power''' if len(p) == 2: p[0] = p[1] else: item = p.get_item(1) if p[1] == "+": p[0] = ast.UnaryOp(op=ast.UAdd(), operand=p[2], lineno=item.lineno, col_offset=item.lexpos) elif p[1] == "-": p[0] = ast.UnaryOp(op=ast.USub(), operand=p[2], lineno=item.lineno, col_offset=item.lexpos) elif p[1] == "~": p[0] = ast.UnaryOp(op=ast.Invert(), operand=p[2], lineno=item.lineno, col_offset=item.lexpos) return
def compile_subtract(p): if len(p) == 2: return ast.UnaryOp(ast.USub(), build_ast(p[1])) elif len(p) == 3: return ast.BinOp(build_ast(p[1]), ast.Sub(), build_ast(p[2])) else: return ast.BinOp(compile_subtract(p[:-1]), ast.Sub(), build_ast(p[-1]))
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)) if not should_parenthesize: 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 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 write_number(self, number): should_parenthesize = isinstance(number, int) and number >= 0 and \ isinstance(self.get_parent_node(), ast.Attribute) should_parenthesize = should_parenthesize or ( isinstance(number, complex) and number.real == 0.0 and (number.imag < 0 or number.imag == -0.0)) # Always parenthesize in Python 2, because there "-(1)" and "-1" produce a different AST. if not should_parenthesize and (isinstance(number, complex) or number < 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(number, float) and abs(number) > 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 number > 0 else '-1e1000') elif isinstance(number, (int, _long, float)) and number < 0: # needed for precedence to work correctly me = self.node_stack.pop() if isinstance(number, int): val = str(-number) else: val = repr(type(number)(-number)) # - 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(number))
def factor(self): """factor: (PLUS | MINUS) factor | INTEGER | LPAREN expr RPAREN | proccall_statement | variable""" print("BEGIN factor") token = self.current_token node = None if token.token_type == TokenType.PLUS: self.eat(TokenType.PLUS) node = ast.UnaryOp(ast.UAdd(), self.factor()) elif token.token_type == TokenType.MINUS: self.eat(TokenType.MINUS) node = ast.UnaryOp(ast.USub(), self.factor()) elif token.token_type == TokenType.INTEGER: self.eat(TokenType.INTEGER) node = ast.Num(token.value) elif token.token_type == TokenType.LPAR: self.eat(TokenType.LPAR) node = self.expr() self.eat(TokenType.RPAR) elif token.token_type == TokenType.ID and self.lexer.current_char == "(": node = self.proccall_statement() else: node = self.variable() print("END factor") return node
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_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 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 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 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 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 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 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 create_exponentiation_exponent_node(self, exponent): node = self.to_node(exponent.operand) if exponent.sign in ['-', 'minus']: return ast.UnaryOp(ast.USub(), node) elif exponent.sign in ['+', 'plus']: return ast.UnaryOp(ast.UAdd(), node) elif exponent.sign is None: return node else: raise
def __init__(self, base_node): BaseMutator.__init__(self, base_node) self.original_unary_op = base_node.op if type(base_node.op) in [ast.UAdd, ast.USub]: if type(base_node.op) is ast.UAdd: self.mutations.append({"op": ast.USub()}) if type(base_node.op) is ast.USub: self.mutations.append({"op": ast.UAdd()})
def test_bad_ast_no_call(tmp_path): 'Pass a really bogus ast to the executor' # Get the ast to play with q = query_as_ast() a = ast.UnaryOp(op=ast.USub(), operand=q.query_ast) exe = atlas_xaod_executor() with pytest.raises(ValueError) as e: exe.write_cpp_files(exe.apply_ast_transformations(a), tmp_path) assert 'func_adl ast' in str(e.value)
def to_node(self): value = self.value operator = self.operator if operator in ('+', 'plus'): return ast.UnaryOp(ast.UAdd(), value.to_node()) elif operator in ('-', 'minus'): return ast.UnaryOp(ast.USub(), value.to_node()) elif operator == '~': return ast.UnaryOp(ast.Invert(), value.to_node()) else: return value.to_node()
def make_usub(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.USub): # Having - - x doesn't really make sense # So let's just remove the minus in this case return expr.operand return ast.UnaryOp(op=ast.USub(), operand=expr)
def test_withUnaryOp(self): 'Test with UnaryOp involved' tests = [("5 + (-(6 + 2)) + 3", ast.BoolOp(ast.Add(), [ast.Num(5), ast.UnaryOp(ast.USub(), ast.BinOp(ast.Num(6), ast.Add(), ast.Num(2))), ast.Num(3)]))] for teststring, ref_ast in tests: test_ast = ast.parse(teststring, mode="eval").body test_ast = asttools.LevelOperators(ast.Add).visit(test_ast) self.assertTrue(asttools.Comparator().visit(test_ast, ref_ast))
def p_complex_number(self, p): """ complex_number : number | MINUS number | number PLUS number | number MINUS number | MINUS number PLUS number | MINUS number MINUS number """ ops = {"+": ast.Add(), "-": ast.Sub()} build_complex = False loc = self.get_line_cols(p, 1) match list(p): case [_, x]: p[0] = x case [_, "-", x]: p[0] = ast.UnaryOp(op=ast.USub(), operand=x, **loc) case [_, left, ("+" | "-") as op_char, right]: build_complex = True negate_left_side = False case [_, "-", left, ("+" | "-") as op_char, right]: build_complex = True negate_left_side = True case _: raise AssertionError() if build_complex: # TODO raise syntax error instead (see reason in p_literal_expr_number_or_string_literal_list) assert isinstance( right.value, complex ), "right part of complex literal must be imaginary" if negate_left_side: left = ast.UnaryOp(op=ast.USub(), operand=left, **loc) p[0] = ast.BinOp(left=left, op=ops[op_char], right=right, **loc)
def p_expr_unaryop(self, p): '''expr : MINUS expr %prec UNARYOP | TILDE expr %prec UNARYOP | NOT expr %prec UNARYOP ''' op = None if p[1] == '-': op = ast.USub() elif p[1] == '~': op = ast.Invert() elif p[1] == 'not': op = ast.Not() p[0] = ast.UnaryOp(op=op, operand=p[2])
def branch_dist(test): if isinstance(test.ops[0], ast.Eq): return 0, ast.Call(func=ast.Name(id='abs'), args=[ ast.BinOp(left=test.left, op=ast.Sub(), right=test.comparators[0]) ], keywords=[], starags=None, kwargs=None) elif isinstance(test.ops[0], ast.NotEq): return 1, ast.UnaryOp(op=ast.USub(), operand=ast.Call( func=ast.Name(id='abs'), args=[ ast.BinOp(left=test.left, op=ast.Sub(), right=test.comparators[0]) ], keywords=[], starags=None, kwargs=None)) elif isinstance(test.ops[0], ast.Lt): return 1, ast.BinOp(left=test.left, op=ast.Sub(), right=test.comparators[0]) elif isinstance(test.ops[0], ast.LtE): return 0, ast.BinOp(left=test.left, op=ast.Sub(), right=test.comparators[0]) elif isinstance(test.ops[0], ast.Gt): return 1, ast.BinOp(left=test.comparators[0], op=ast.Sub(), right=test.left) elif isinstance(test.ops[0], ast.GtE): return 0, ast.BinOp(left=test.comparators[0], op=ast.Sub(), right=test.left)
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 if len(acode) == 2: arg = acode[1] with GC.let(domain=ExDom): arg_code = GC.generate(arg) return expr_wrap(ast.UnaryOp(op=ast.USub(), operand=arg_code), GC) else: assert len(acode) == 3 left_element, right_element = acode[1], acode[2] with GC.let(domain=ExDom): left_code = GC.generate(left_element) right_code = GC.generate(right_element) return expr_wrap(ast.BinOp(left_code, ast.Sub(), right_code), GC)