def single_compare(self, node): rhs = node.comparators[0] if is_obj(node.left.type): node = self.single_compare_objects(node) elif node.left.type.is_pointer and rhs.type.is_pointer: # Coerce pointers to integer values before comparing node.left = nodes.CoercionNode(node.left, Py_uintptr_t) node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)] elif node.left.type.is_complex and rhs.type.is_complex: real1, imag1 = extract(node.left) real2, imag2 = extract(rhs) op = type(node.ops[0]) if op == ast.Eq: lhs = compare(real1, ast.Eq(), real2) rhs = compare(imag1, ast.Eq(), imag2) result = ast.BoolOp(ast.And(), [lhs, rhs]) elif op == ast.NotEq: lhs = compare(real1, ast.NotEq(), real2) rhs = compare(imag1, ast.NotEq(), imag2) result = ast.BoolOp(ast.Or(), [lhs, rhs]) else: raise NotImplementedError("ordered comparisons are not " "implemented for complex numbers") node = nodes.typednode(result, bool_) return node
def visit_Compare(self, node): # cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn print(" in MyTransformer.visit_Compare()") print(" node =", node) print(" op =", node.ops[0]) curr_op = node.ops[0] comp_negate = curr_op rand_num = random.randint(1, 10) if rand_num >= 7: print(" negating...") if isinstance(curr_op, ast.Eq): comp_negate = ast.NotEq() elif isinstance(curr_op, ast.NotEq): comp_negate = ast.Eq() elif isinstance(curr_op, ast.Lt): comp_negate = ast.GtE() elif isinstance(curr_op, ast.LtE): comp_negate = ast.Gt() elif isinstance(curr_op, ast.Gt): comp_negate = ast.LtE() elif isinstance(curr_op, ast.GtE): comp_negate = ast.Lt() elif isinstance(curr_op, ast.Is): comp_negate = ast.IsNot() elif isinstance(curr_op, ast.IsNot): comp_negate = ast.Is() elif isinstance(curr_op, ast.In): comp_negate = ast.NotIn() elif isinstance(curr_op, ast.NotIn): comp_negate = ast.In() else: comp_negate = ast.Eq() else: print(" mixing up...") if isinstance(curr_op, ast.Lt): comp_negate = ast.LtE() elif isinstance(curr_op, ast.LtE): comp_negate = ast.And() elif isinstance(curr_op, ast.Gt): comp_negate = ast.Or() elif isinstance(curr_op, ast.GtE): comp_negate = ast.Gt() elif isinstance(curr_op, ast.Is): comp_negate = ast.Gt() elif isinstance(curr_op, ast.IsNot): comp_negate = ast.Lt() elif isinstance(curr_op, ast.In): comp_negate = ast.In( ) #leave the same for for loops (for x in this) elif isinstance(curr_op, ast.NotIn): comp_negate = ast.Lt() else: comp_negate = ast.Eq() print(" new comparator =", comp_negate) # create negated node | Compare(expr left, cmpop* ops, expr* comparators) new_node = node new_node.ops = [comp_negate] ast.copy_location(new_node, node) ast.fix_missing_locations(new_node) return new_node
def stop_iteration(node): cmp_break = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.BREAK)]) cmp_return = ast.Compare(left=mk_name(self.flag_id), ops=[ast.Eq()], comparators=[mk_str(self.RETURN)]) test = ast.BoolOp(op=ast.Or(), values=[cmp_break, cmp_return]) break_stmt = ast.Break() ifstmt = ast.If(test=test, body=[break_stmt], orelse=[]) node.body.append(ifstmt)
def __eq__(self, other): if isinstance(other, Expr): comp = ast.Compare(left=self._expr, ops=[ast.Eq()], comparators=[other._expr]) return Expr(comp, istrue=self is other) elif other is not None: comp = ast.Compare(left=self._expr, ops=[ast.Eq()], comparators=[ast.Constant(value=other)]) return Expr(comp, istrue=False) else: return False
def __eq__(self, other): if isinstance(other, Expr): comp = ast.Compare(left=self._expr, ops=[ast.Eq()], comparators=[other._expr]) return Expr(comp) else: return False
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 create_command_results_assertion(arg: str, value: Union[ast_mod.Name, ast_mod.Constant]): """ Inputs: arg: CommandResults argument value: CommandResults argument value Returns: Single assertion as part of command results assertions """ comperator = None call = ast_mod.Attribute(value=ast_name('results'), attr=arg) ops = [ast_mod.Eq()] if hasattr(value, 'value'): # if so it is of type ast.Constant comperator = ast_mod.Constant(value=value.value) elif arg == 'raw_response': link = TestCase.get_links(value) if link: comperator = ast_name(f'mock_response_{link}') elif arg == 'outputs' or arg == 'readable_output': get_call = ast_mod.Call(func=ast_name('get'), args=[ast_mod.Constant(arg)], keywords=[]) comperator = ast_mod.Attribute(value=ast_name('mock_results'), attr=get_call, ctx=ast_mod.Load()) return TestCase.assertions_builder( call, ops, [comperator]) if comperator else None
def translateStmtCase(n): global i name = '_CaseExp_' + str(i) i += 1 e = ast.Assign([ast.NameConstant(name)], translateExpr(n.children[0])) cases = n.children[1] ifs = [e] for case in cases: assert case.type == 's-case-match' matches = case.children[0] caseStmt = case.children[1] q = ast.BoolOp(ast.Or(), [ ast.Compare(ast.NameConstant(name), [ast.Eq()], [translateExpr(m)]) for m in matches ]) ee = ast.If(q, translateStmtOrBlock(caseStmt), []) if len(ifs) > 1: z = ifs[1].orelse while len(z) > 0: z = z[0].orelse z.append(ee) else: ifs.append(ee) if n.children[2]: z = ifs[1].orelse while len(z) > 0: z = z[0].orelse z += translateStmtOrBlock(n.children[2]) return ifs
def setup(self): self.node = ast.Compare(left=ast.Name(id='x'), ops=[ast.Eq()], comparators=[ast.Num(n=4)], lineno=5, col_offset=23) self.modulename = 'somepackage.somemodule' self.label = '5.1'
def reflection_of_example(): ref = ast.Module( ast.FunctionDef( name="example", args=ast.arguments( args=[], vararg=None, kwarg=None, defaults=[] ), body=[ ast.Assign( targets=[ast.Name(id="f", ctx=ast.Store())], value=ast.Num(n=1), ), ast.If( test=ast.Compare( left=ast.Name(id="f", ctx=ast.Load()), ops=[ast.Eq()], comparators=[ast.Num(n=1)], ), body=[ ast.Print( dest=None, values=[ast.Str(s="body")], nl=True ) ], orelse=[], ), ], decorator_list=[], ) )
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 translate_pat_Num(self, ctx, pat, scrutinee_trans): scrutinee_trans_copy = astx.copy_node(scrutinee_trans) comparator = astx.copy_node(pat) condition = ast.Compare(left=scrutinee_trans_copy, ops=[ast.Eq()], comparators=[comparator]) return (condition, _util.odict())
def visit_primitive_assertion(self, assertion: pa.PrimitiveAssertion) -> None: """ Creates an assertion of form "assert var0 == value" or assert var0 is False, if the value is a bool. Args: assertion: the assertion that is visited. """ if isinstance(assertion.value, bool): self._nodes.append( self._create_constant_assert( assertion.source, ast.Is(), assertion.value ) ) elif isinstance(assertion.value, float): self._nodes.append( self._create_float_delta_assert(assertion.source, assertion.value) ) else: self._nodes.append( self._create_constant_assert( assertion.source, ast.Eq(), assertion.value ) )
def to_node(self): if len(self.operator) == 0: return self.left.to_node() else: right_nodes = [] comp_operator = [] for i in range(len(self.right)): right_nodes.append(self.right[i].to_node()) if self.operator[i] in ['<', 'is lower than']: comp_operator.append(ast.Lt()) elif self.operator[i] in ['<=', 'is lower or equal to']: comp_operator.append(ast.LtE()) elif self.operator[i] in ['>', 'is greater than']: comp_operator.append(ast.Gt()) elif self.operator[i] in ['>=', 'is greater or equal to']: comp_operator.append(ast.GtE()) elif self.operator[i] in ['==', 'is equal to']: comp_operator.append(ast.Eq()) elif self.operator[i] in ['!=', 'is different from', 'is not equal to']: comp_operator.append(ast.NotEq()) elif self.operator[i] == 'in': comp_operator.append(ast.In()) elif self.operator[i] == 'not in': comp_operator.append(ast.NotIn()) elif self.operator[i] == 'is': comp_operator.append(ast.Is()) elif self.operator[i] == 'is not': comp_operator.append(ast.IsNot()) else: raise Exception("Unrecognized argument in Comparison") return ast.Compare(left=self.left.to_node(), ops=comp_operator, comparators=right_nodes)
def visit_For(self, node): #in testing:) #add more convincing junk for loop(random choice of a few seemingly important code lines that dont do anything) fortarget = self.visit( ast.Name(id=''.join([ random.choice(string.ascii_letters) for i in range(random.randint(3, 8)) ]), ctx=ast.Load)) junkfor = [ ast.Assign(targets=[self.visit(node.target)], ctx=ast.Store(), value=self.visit( ast.Num(n=id(''.join([ random.choice(string.ascii_letters) for i in range(random.randint(3, 8)) ]))))), ast.If(test=ast.Compare(left=self.visit(node.target), ops=[ast.Eq()], comparators=[ ast.Call(func=ast.Name(id='id', ctx=ast.Load()), args=[fortarget], keywords=[], starargs=None, kwargs=None) ]), body=[ ast.Assign(targets=[self.visit(node.target)], ctx=ast.Store(), value=ast.BinOp(left=self.visit(node.target), op=ast.Sub(), right=self.visit( ast.Num(n=1)))), ast.Assign(targets=[fortarget], ctx=ast.Store(), value=ast.BinOp(left=self.visit(node.target), op=ast.Add(), right=self.visit( node.target))) ], orelse=[]) ] return ast.For( target=fortarget, iter=ast.Call( func=ast.Name(id='range', ctx=ast.Load()), args=[self.visit(ast.Num(n=random.randint(10, 100)))], keywords=[], starargs=None, kwargs=None), body=junkfor, orelse=[ ast.For(target=self.visit(node.target), iter=self.visit(node.iter), body=[self.visit(i) for i in node.body], orelse=[self.visit(i) for i in node.orelse]) ])
def to_single_assignment_predicates(path): env = {} new_path = [] for i, node in enumerate(path): ast_node = node.cfgnode.ast_node new_node = None if isinstance(ast_node, ast.AnnAssign) and ast_node.target.id in {'exit'}: new_node = None elif isinstance(ast_node, ast.AnnAssign) and ast_node.target.id in {'enter'}: args = [ ast.parse("%s == _%s_0" % (a.id, a.id)).body[0].value for a in ast_node.annotation.args ] new_node = ast.Call(ast.Name('z3.And', None), args, []) elif isinstance(ast_node, ast.AnnAssign) and ast_node.target.id in { '_if', '_while' }: new_node = rename_variables(ast_node.annotation, env) if node.order != 0: assert node.order == 1 new_node = ast.Call(ast.Name('z3.Not', None), [new_node], []) elif isinstance(ast_node, ast.AnnAssign): assigned = ast_node.target.id val = [rename_variables(ast_node.value, env)] env[assigned] = 0 if assigned not in env else env[assigned] + 1 target = ast.Name('_%s_%d' % (ast_node.target.id, env[assigned]), None) new_node = ast.Expr(ast.Compare(target, [ast.Eq()], val)) elif isinstance(ast_node, ast.Assign): assigned = ast_node.targets[0].id val = [rename_variables(ast_node.value, env)] env[assigned] = 0 if assigned not in env else env[assigned] + 1 target = ast.Name( '_%s_%d' % (ast_node.targets[0].id, env[assigned]), None) new_node = ast.Expr(ast.Compare(target, [ast.Eq()], val)) elif isinstance(ast_node, (ast.Return, ast.Pass)): new_node = None else: s = "NI %s %s" % (type(ast_node), ast_node.target.id) raise Exception(s) new_path.append(new_node) return new_path
def visit_With(self, node): context_expr = self.visit(node.context_expr) result = if_node = ast.copy_location(ast.If(), node) variable_domain = get_variable_domain(context_expr) for i_value in range(0, variable_domain): # Create the test (context_expr == i_value). eq_node = ast.copy_location(ast.Eq(), node) value_node = ast.copy_location(ast.Num(n=i_value), node) if_node.test = ast.copy_location(ast.Compare(context_expr, [eq_node], [value_node]), node) # Substitute the current value of the context # expression into the body of the with. If the with # binds a name, substitute uses of that # name. Otherwise, substitute uses of the context # expression. if node.optional_vars is not None: check_type(node.optional_vars, ast.Name) replacements = {node.optional_vars.id : i_value} if_node.body = eval_const_expressions(subs(node, **replacements)).body else: if isinstance(context_expr, ast.Name): replacements = {context_expr.id : i_value} if_node.body = eval_const_expressions(subs(node, **replacements)).body elif isinstance(context_expr, ast.Subscript): replacements = {subscript_to_tuple(context_expr) : ast.copy_location(ast.Num(n=i_value), node)} if_node.body = eval_const_expressions(sub_subscript(node, replacements)).body else: error.fatal_error('Unexpected expression in with.', context_expr) update_variable_domains(variable_domains, if_node.body) # Recursively process withs inside the body. This must # be performed separately for each body, because withs # inside the body may depend on the current value of # the context expression. self.generic_visit(if_node) # If this is not the last iteration of the loop, # generate a new if node and add it to the else block # of the current if. We will use the new if node in # the next iteration. if i_value < variable_domain-1: if_node.orelse = [ast.copy_location(ast.If(), node)] if_node = if_node.orelse[0] else: if_node.orelse = [] if variable_domain == 0: result = [] return result
def translate_pat_Num(self, ctx, pat, scrutinee_trans): scrutinee_trans_copy = astx.copy_node(scrutinee_trans) comparator = astx.copy_node(pat) n = pat.n if not isinstance(n, complex): comparator.n = complex(n) condition = ast.Compare(left=scrutinee_trans_copy, ops=[ast.Eq()], comparators=[comparator]) return (condition, _util.odict())
def translate_pat_Unary_Name_constructor(self, ctx, pat, scrutinee_trans): if isinstance(pat.op, ast.USub): s = "-Inf" else: s = "Inf" condition = ast.Compare( left=scrutinee_trans, ops=[ast.Eq()], comparators=[astx.builtin_call("float", [ast.Str(s=s)])]) return (condition, _util.odict())
def handle_goto_label(self, stmnt): assert isinstance(stmnt, GotoLabel) reset_ast = ast.Assign() reset_ast.targets = [ast.Name(id=self.gotoVarName, ctx=ast.Store())] reset_ast.value = ast.Name(id="None", ctx=ast.Load()) test_ast = ast.Compare() test_ast.ops = [ast.Eq()] test_ast.left = ast.Name(id=self.gotoVarName, ctx=ast.Store()) test_ast.comparators = [_ast_for_value(stmnt.label)] return [ast.If(test=test_ast, body=[reset_ast], orelse=[])]
def translate_pat_Name_constructor(cls, ctx, pat, scrutinee_trans): id = pat.id if id == "NaN": condition = astx.method_call(astx.import_expr('math'), 'isnan', [scrutinee_trans]) else: condition = ast.Compare( left=scrutinee_trans, ops=[ast.Eq()], comparators=[astx.builtin_call("float", [ast.Str(s=id)])]) return (condition, _util.odict())
def ast(self): if self.implicit_equality: return ast.Compare(left=self._field.ast(), ops=[ast.Eq()], comparators=[e.ast() for e in self.compare_to]) else: comparator = ast.List([e.ast() for e in self.compare_to], ast.Load()) return ast.Compare(left=self._field.ast(), ops=[ast.In()], comparators=[comparator])
def visit_If(self, node: ast.If): result = copy.deepcopy(node) cond = copy.deepcopy(node.test) if isinstance(cond, ast.Compare): if len(cond.ops) == 1: if isinstance(cond.ops[0], ast.Eq): cond.ops[0] = ast.NotEq() elif isinstance(cond.ops[0], ast.NotEq): cond.ops[0] = ast.Eq() result.test = cond return result
def test_compare(self): def f(a, b): return a == b expected = G(C(START_TICK, "a", 1, "left"), C(START_TICK, "b", 1, "right"), T(1, tasks.BinOpTask(ast.Eq()), {'quick': True}), C(1, "value", FINAL_TICK, "retval")) callee = translator.translate_function(f, "scheduler", False) utils.assert_graph_equal(expected, callee.graph)
def extract_constraints(self, path): predicates = [] for (idx, elt) in path: if isinstance(elt.ast_node, ast.AnnAssign): if elt.ast_node.target.id in {'_if', '_while'}: s = to_src(elt.ast_node.annotation) predicates.append(("%s" if idx == 0 else "z3.Not(%s)") % s) elif isinstance(elt.ast_node.annotation, ast.Call): assert elt.ast_node.annotation.func.id == self.fn_name else: node = elt.ast_node t = ast.Compare(node.target, [ast.Eq()], [node.value]) predicates.append(to_src(t)) elif isinstance(elt.ast_node, ast.Assign): node = elt.ast_node t = ast.Compare(node.targets[0], [ast.Eq()], [node.value]) predicates.append(to_src(t)) else: pass return predicates
def 比较(片段): 对照表 = { '>': ast.Gt(), '>=': ast.GtE(), '<': ast.Lt(), '<=': ast.LtE(), '==': ast.Eq(), '!=': ast.NotEq(), '===': ast.Is(), '!==': ast.IsNot() } return 语法树.比较(前项=片段[0], 操作符=对照表[片段[1].getstr()], 后项=片段[2], 片段=片段)
def visit_Compare(self, node): self.generic_visit(node) self.binop_count += 1 if (self.binop_count == self.count_of_node_to_mutate): new_node = copy.deepcopy(node) print('IN COMPARE') print('THIS IS THE PREVIOUS OP', node.ops) for (i, op) in enumerate(node.ops): if (isinstance(op, ast.Gt)): num = random.randint(0, 2) if num == 0: new_node.ops[i] = ast.GtE() if num == 1: new_node.ops[i] = ast.LtE() if num == 2: new_node.ops[i] = ast.Lt() if (isinstance(op, ast.GtE)): num = random.randint(0, 2) if num == 0: new_node.ops[i] = ast.Gt() if num == 1: new_node.ops[i] = ast.Lt() if num == 2: new_node.ops[i] = ast.LtE() if (isinstance(op, ast.Lt)): num = random.randint(0, 2) if num == 0: new_node.ops[i] = ast.LtE() if num == 1: new_node.ops[i] = ast.GtE() if num == 2: new_node.ops[i] = ast.Gt() if (isinstance(op, ast.LtE)): num = random.randint(0, 2) if num == 0: new_node.ops[i] = ast.Lt() if num == 1: new_node.ops[i] = ast.GtE() if num == 2: new_node.ops[i] = ast.Gt() if (isinstance(op, ast.Eq)): new_node.ops[i] = ast.NotEq() if (isinstance(op, ast.NotEq)): new_node.ops[i] = ast.Eq() if (isinstance(op, ast.Is)): new_node.ops[i] = ast.IsNot() if (isinstance(op, ast.IsNot)): new_node.ops[i] = ast.Is() print('THIS IS THE NEW OP', new_node.ops) print('I AM CREATING A NEW NODE HERE', self.binop_count) return new_node return node
def visit_Name(self, node): ops = [ast.Eq()] * len(self._filters) call = ast.Call(func=ast.Name(id='IF', ctx=ast.Load()), args=[ ast.Compare(left=ast.Num(1), ops=ops, comparators=self._filters), node, ast.Num(-2147483648) ], keywords=[], filterified=True) return call
def get_kernel_embed(): """A list of kernel embed nodes Returns: nodes (list): AST nodes which form the following code. ``` import os pid = os.fork() if os.fork() == 0: open(f'{os.environ["HOME"]}/.pynt', 'a').close() import IPython IPython.start_kernel(user_ns={**locals(), **globals(), **vars()}) os.waitpid(pid, 0) ``` This is a purely functional method which always return the same thing. """ return [ ast.Import(names=[ast.alias(name='os', asname=None),]), ast.Assign(targets=[ast.Name(id='pid', ctx=ast.Store()),], value=ast.Call(func=ast.Attribute(value=ast.Name(id='os', ctx=ast.Load()), attr='fork', ctx=ast.Load()), args=[], keywords=[])), ast.If( test=ast.Compare(left=ast.Name(id='pid', ctx=ast.Load()), ops=[ast.Eq(),], comparators=[ast.Num(n=0),]), body=[ ast.Expr(value=ast.Call(func=ast.Attribute(value=ast.Call(func=ast.Name(id='open', ctx=ast.Load()), args=[ ast.JoinedStr(values=[ ast.FormattedValue(value=ast.Subscript(value=ast.Attribute(value=ast.Name(id='os', ctx=ast.Load()), attr='environ', ctx=ast.Load()), slice=ast.Index(value=ast.Str(s='HOME')), ctx=ast.Load()), conversion=-1, format_spec=None), ast.Str(s='/.pynt'), ]), ast.Str(s='a'), ], keywords=[]), attr='close', ctx=ast.Load()), args=[], keywords=[])), ast.Import(names=[ ast.alias(name='IPython', asname=None), ]), ast.Expr(value=ast.Call(func=ast.Attribute(value=ast.Name(id='IPython', ctx=ast.Load()), attr='start_kernel', ctx=ast.Load()), args=[], keywords=[ ast.keyword(arg='user_ns', value=ast.Dict(keys=[ None, None, None, ], values=[ ast.Call(func=ast.Name(id='locals', ctx=ast.Load()), args=[], keywords=[]), ast.Call(func=ast.Name(id='globals', ctx=ast.Load()), args=[], keywords=[]), ast.Call(func=ast.Name(id='vars', ctx=ast.Load()), args=[], keywords=[]), ])), ])), ], orelse=[]), ast.Expr(value=ast.Call(func=ast.Attribute(value=ast.Name(id='os', ctx=ast.Load()), attr='waitpid', ctx=ast.Load()), args=[ ast.Name(id='pid', ctx=ast.Load()), ast.Num(n=0), ], keywords=[])), ]
def visit_BinOp(self, node): left = self.visit(node.left) right = self.visit(node.right) if self.in_pr_func: if isinstance(left, str): left = _make_filter_function(ast.Eq(), left, True) if isinstance(right, str): right = _make_filter_function(ast.Eq(), right, True) if isinstance(node.op, ast.BitAnd): return _and_filter_functions(left, right) elif isinstance(node.op, ast.BitOr): right_data = self.data_list(right) if len(right_data) == 0: return 0 left_data = right_data(left) return len(left_data) / len(right_data) if right == 0: return 0 if isinstance(node.op, ast.Div): return left / right