def visit_Compare(self, node): if self._language in {"dart", "kotlin", "nim", "python"}: return node if isinstance(node.ops[0], ast.In): left = node.left right = node.comparators[0] left_type = get_id(get_inferred_type(left)) right_type = get_id(get_inferred_type(right)) if left_type == "str" and right_type == "str": if self._language == "julia": ret = ast.parse("findfirst(a, b) != Nothing").body[0].value ret.left.args[0] = left ret.left.args[1] = right elif self._language == "go": # To be rewritten to strings.Contains via plugins ret = ast.parse("StringsContains(a, b)").body[0].value ret.args[0] = right ret.args[1] = left elif self._language == "cpp": ret = ast.parse("a.find(b) != string.npos").body[0].value ret.left.func.value = right ret.left.args[0] = left else: # rust and c++23 ret = ast.parse("a.contains(b)").body[0].value ret.func.value = right ret.args[0] = left ret.lineno = node.lineno ast.fix_missing_locations(ret) return ret return node
def visit_BinOp(self, node): self.generic_visit(node) if isinstance(node.op, ast.Div): left_type = get_id(get_inferred_type(node.left)) right_type = get_id(get_inferred_type(node.right)) if set([left_type, right_type]) == {"int"}: # This attribute should technically be on node.op # But python seems to use the same AST node for other # division operations? node.use_integer_div = True return node
def get_inferred_rust_type(node): if hasattr(node, "rust_annotation"): return node.rust_annotation if isinstance(node, ast.Name): if not hasattr(node, "scopes"): return None definition = node.scopes.find(get_id(node)) # Prevent infinite recursion if definition != node: return get_inferred_rust_type(definition) python_type = get_inferred_type(node) ret = map_type(get_id(python_type)) node.rust_annotation = ret return ret
def get_inferred_kotlin_type(node): if isinstance(node, ast.Call): fname = get_id(node.func) if fname in {"max", "min", "floor"}: return "float64" if isinstance(node, ast.Name): if not hasattr(node, "scopes"): return None definition = node.scopes.find(get_id(node)) # Prevent infinite recursion if definition != node: return get_inferred_kotlin_type(definition) if hasattr(node, "kotlin_annotation"): return node.kotlin_annotation python_type = get_inferred_type(node) return map_type(get_id(python_type))
def visit_Assign(self, node): target = node.targets[0] # Assumes all targets have same annotation if isinstance(target, ast.Subscript): return node annotation = getattr(target, "annotation", False) if not annotation: return node if isinstance(annotation, ast.ClassDef): annotation = ast.Name(id=get_id(annotation)) col_offset = getattr(node, "col_offset", None) assigns = [] for assign_target in node.targets: definition = node.scopes.parent_scopes.find(get_id(assign_target)) if definition is None: definition = node.scopes.find(get_id(assign_target)) if definition is not assign_target: previous_type = get_inferred_type(definition) if get_id(previous_type) == get_id(annotation): if len(node.targets) == 1: return node else: new_node = ast.Assign( targets=[assign_target], value=node.value, lineno=node.lineno, col_offset=col_offset, ) assigns.append(new_node) continue new_node = ast.AnnAssign( target=assign_target, value=node.value, lineno=node.lineno, col_offset=col_offset, simple=True, annotation=annotation, ) assigns.append(new_node) if len(assigns) == 1: return assigns[0] return create_ast_block(body=assigns, at_node=node)