def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) # HACK to determine if main function name is visited if self.visit(node.test) == '__name__ == "__main__"': buf = ["proc main():"] buf.extend([self.visit(child) for child in node.body]) buf.append("") return "\n".join(buf) body = "\n".join([ self.indent(self.visit(child), level=node.level + 1) for child in node.body ]) orelse = "\n".join([ self.indent(self.visit(child), level=node.level + 1) for child in node.orelse ]) test = self.visit(node.test) if node.orelse: orelse = f"else:\n{orelse}" else: orelse = "" return f"if {test}:\n{body}\n{orelse}"
def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) # HACK to determine if main function name is visited if self.visit(node.test) == '__name__ == "__main__"': buf = ["function main()"] buf.extend([self.visit(child) for child in node.body]) buf.append("") return "\n".join(buf) + "end\n" buf = [] cond = self.visit(node.test) buf.append(f"if {cond}") buf.extend([self.visit(child) for child in node.body]) orelse = [self.visit(child) for child in node.orelse] if orelse: buf.append("else\n") buf.extend(orelse) buf.append("end") else: buf.append("end") return "\n".join(buf)
def visit_BinOp(self, node): self.generic_visit(node) if isinstance(node.left, ast.Name): lvar = node.scopes.find(get_id(node.left)) else: lvar = node.left if isinstance(node.right, ast.Name): rvar = node.scopes.find(get_id(node.right)) else: rvar = node.right left = lvar.annotation if lvar and hasattr(lvar, "annotation") else None right = rvar.annotation if rvar and hasattr(rvar, "annotation") else None if left is None and right is not None: node.annotation = right return node if right is None and left is not None: node.annotation = left return node if right is None and left is None: return node # Both operands are annotated. Now we have interesting cases left_id = get_id(left) right_id = get_id(right) if ( left_id in self.FIXED_WIDTH_INTS_NAME and right_id in self.FIXED_WIDTH_INTS_NAME ): ret = self._handle_overflow(node.op, left_id, right_id) node.annotation = ast.Name(id=ret) return node if left_id == right_id: # Exceptions: division operator if isinstance(node.op, ast.Div): if left_id == "int": node.annotation = ast.Name(id="float") return node node.annotation = copy.copy(left) return node else: if left_id in self.FIXED_WIDTH_INTS_NAME: left_id = "int" if right_id in self.FIXED_WIDTH_INTS_NAME: right_id = "int" if (left_id, right_id) in {("int", "float"), ("float", "int")}: node.annotation = ast.Name(id="float") return node raise Exception(f"type error: {left_id} {type(node.op)} {right_id}") return node
def visit_Assign(self, node): target = node.targets[0] if isinstance(target, ast.Tuple): elts = [self.visit(e) for e in target.elts] value = self.visit(node.value) return "let ({0}) = {1};".format(", ".join(elts), value) if isinstance(node.scopes[-1], ast.If): outer_if = node.scopes[-1] target_id = self.visit(target) if target_id in outer_if.common_vars: value = self.visit(node.value) return "{0} = {1};".format(target_id, value) if isinstance(target, ast.Subscript) or isinstance( target, ast.Attribute): target = self.visit(target) value = self.visit(node.value) if value == None: value = "None" return "{0} = {1};".format(target, value) definition = node.scopes.find(target.id) if isinstance(target, ast.Name) and defined_before(definition, node): target = self.visit(target) value = self.visit(node.value) return "{0} = {1};".format(target, value) elif isinstance(node.value, ast.List): elements = [self.visit(e) for e in node.value.elts] mut = "" if is_mutable(node.scopes, get_id(target)): mut = "mut " return "let {0}{1} = vec![{2}];".format(mut, self.visit(target), ", ".join(elements)) else: mut = "" if is_mutable(node.scopes, get_id(target)): mut = "mut " typename = "_" if hasattr(target, "annotation"): typename = get_id(target.annotation) if typename in self._type_map: typename = self._type_map[typename] target = self.visit(target) value = self.visit(node.value) if len(node.scopes) == 1: if isinstance( node.scopes[0], ast.Module ): # if assignment is module level it must be const return f"const {target}: {typename} = {value};" return f"let {mut}{target}: {typename} = {value};"
def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) # HACK to determine if main function name is visited if self.visit(node.test) == '__name__ == "__main__"': buf = ["fun main() {"] buf.extend([self.visit(child) for child in node.body]) buf.append("") return "}\n".join(buf) return super().visit_If(node)
def visit_Name(self, node): var = node.scopes.find(get_id(node)) if not var: # TODO why no scopes found for node id? return get_id(node) # TODO: code looks C++ specific. Move out if isinstance(var.assigned_from, ast.For): it = var.assigned_from.iter return "std::declval<typename decltype({0})::value_type>()".format( self.visit(it)) elif isinstance(var.assigned_from, ast.FunctionDef): return get_id(var) else: return self.visit(var.assigned_from.value)
def visit_AnnAssign(self, node: ast.AnnAssign) -> ast.AST: self.generic_visit(node) node.target.annotation = node.annotation if get_id(node.annotation) in self.FIXED_WIDTH_INTS_NAME: self.has_fixed_width_ints = True return node
def visit_ClassDef(self, node): extractor = DeclarationExtractor(KotlinTranspiler()) extractor.visit(node) declarations = extractor.get_declarations() fields = [] index = 0 for declaration, typename in declarations.items(): if typename == None: typename = "ST{0}".format(index) index += 1 mut = is_mutable(node.scopes, get_id(declaration)) mut = "var" if mut else "val" fields.append(f"{mut} {declaration}: {typename}") for b in node.body: if isinstance(b, ast.FunctionDef): b.self_type = node.name if node.is_dataclass: fields = ", ".join(fields) body = [self.visit(b) for b in node.body] body = "\n".join(body) return f"data class {node.name}({fields}) {{\n{body}\n}}\n" else: fields = "\n".join(fields) body = [self.visit(b) for b in node.body] body = "\n".join(body) return f"class {node.name} {{\n{fields}\n\n {body}\n}}\n"
def visit_arg(self, node): id = get_id(node) if id == "self": return (None, "self") typename = "T" if node.annotation: typename = self.visit(node.annotation) return (typename, id)
def visit_Return(self, node): self.generic_visit(node) new_type_str = ( get_id(node.value.annotation) if hasattr(node.value, "annotation") else None ) if new_type_str is None: return node for scope in node.scopes: type_str = None if isinstance(scope, ast.FunctionDef): type_str = get_id(scope.returns) if type_str is not None: if new_type_str != type_str: type_str = f"Union[{type_str},{new_type_str}]" scope.returns.id = type_str else: scope.returns = ast.Name(id=new_type_str) return node
def is_self_arg(name, scopes): for scope in scopes: for entry in scope.body: if isinstance(entry, ast.FunctionDef): if len(entry.args.args): first_arg = entry.args.args[0] if get_id(first_arg) == name and hasattr( entry, "self_type"): return True return False
def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) # TODO find out if this can be useful var_definitions = [] # for cv in node.common_vars: # definition = node.scopes.find(cv) # var_type = decltype(definition) # var_definitions.append("{0} {1};\n".format(var_type, cv)) # HACK to determine if main function name is visited if self.visit(node.test) == '__name__ == "__main__"': buf = ["fn main() {"] buf.extend([self.visit(child) for child in node.body]) buf.append("}") return "\n".join(buf) else: return "".join(var_definitions) + super( RustTranspiler, self).visit_If(node, use_parens=False)
def visit_UnaryOp(self, node): self.generic_visit(node) if isinstance(node.operand, ast.Name): operand = node.scopes.find(get_id(node.operand)) else: operand = node.operand if hasattr(operand, "annotation"): node.annotation = operand.annotation return node
def visit_Assign(self, node: ast.Assign) -> ast.AST: self.generic_visit(node) target = node.targets[0] if hasattr(node.value, "annotation"): target.annotation = node.value.annotation else: var = node.scopes.find(get_id(node.value)) if var and hasattr(var, "annotation"): target.annotation = copy.copy(var.annotation) return node
def is_list(node): """Check if a node was assigned as a list""" if isinstance(node, ast.List): return True elif isinstance(node, ast.Assign): return is_list(node.value) elif isinstance(node, ast.Name): var = node.scopes.find(get_id(node)) return (hasattr(var, "assigned_from") and not isinstance(var.assigned_from, ast.FunctionDef) and not isinstance(var.assigned_from, ast.For) and is_list(var.assigned_from.value)) else: return False
def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) var_definitions = [] for cv in node.common_vars: definition = node.scopes.find(cv) var_type = decltype(definition) var_definitions.append("{0} {1};\n".format(var_type, cv)) if self.visit(node.test) == '__name__ == std::string {"__main__"}': buf = [ "int main(int argc, char ** argv) {", "py14::sys::argv = " "std::vector<std::string>(argv, argv + argc);", ] buf.extend([self.visit(child) for child in node.body]) buf.append("}") return "\n".join(buf) else: return "".join(var_definitions) + super(CppTranspiler, self).visit_If(node)
def visit_If(self, node): body_vars = set([get_id(v) for v in node.scopes[-1].body_vars]) orelse_vars = set([get_id(v) for v in node.scopes[-1].orelse_vars]) node.common_vars = body_vars.intersection(orelse_vars) var_definitions = [] for cv in node.common_vars: definition = node.scopes.find(cv) typename = "var" if hasattr(cv, "annotation"): typename = get_id(cv.annotation) var_definitions.append((typename, cv)) decls = "\n".join( [f"{typename} {cv};" for typename, cv in var_definitions]) # HACK to determine if main function name is visited if self.visit(node.test) == '__name__ == "__main__"': buf = ["void main() {"] buf.extend([self.visit(child) for child in node.body]) buf.append("") return "\n".join(buf) + "}\n" return decls + "\n\n" + super().visit_If(node)
def visit_Attribute(self, node): attr = node.attr value_id = get_id(node.value) if is_builtin_import(value_id): return "py14::" + value_id + "::" + attr elif value_id == "math": if node.attr == "asin": return "std::asin" elif node.attr == "atan": return "std::atan" elif node.attr == "acos": return "std::acos" if is_list(node.value): if node.attr == "append": attr = "push_back" return value_id + "." + attr
def generate_template_fun(node, body): params = [] for idx, arg in enumerate(node.args.args): params.append(("T" + str(idx + 1), get_id(arg))) typenames = ["typename " + arg[0] for arg in params] template = "inline " if len(typenames) > 0: template = "template <{0}>\n".format(", ".join(typenames)) params = ["{0} {1}".format(arg[0], arg[1]) for arg in params] return_type = "auto" if is_void_function(node): return_type = "void" funcdef = "{0}{1} {2}({3})".format(template, return_type, node.name, ", ".join(params)) return funcdef + " {\n" + body + "\n}"
def visit_Assign(self, node): target = node.targets[0] if isinstance(target, ast.Tuple): elts = [self.visit(e) for e in target.elts] value = self.visit(node.value) return f"{elts} = {value};" if isinstance(node.scopes[-1], ast.If): outer_if = node.scopes[-1] target_id = self.visit(target) if target_id in outer_if.common_vars: value = self.visit(node.value) return f"{target_id} = {value};" if isinstance(target, ast.Subscript) or isinstance( target, ast.Attribute): target = self.visit(target) value = self.visit(node.value) if value == None: value = "None" return f"{target} = {value};" definition = node.scopes.find(target.id) if isinstance(target, ast.Name) and defined_before(definition, node): target = self.visit(target) value = self.visit(node.value) return f"{target} = {value};" elif isinstance(node.value, ast.List): elements = [self.visit(e) for e in node.value.elts] elements = ", ".join(elements) target = self.visit(target) return f"var {target} = [{elements}];" else: typename = "var" if hasattr(target, "annotation"): typename = get_id(target.annotation) if typename in self._type_map: typename = self._type_map[typename] target = self.visit(target) value = self.visit(node.value) return f"{typename} {target} = {value};"
def visit_Assign(self, node): target = node.targets[0] if isinstance(target, ast.Tuple): elts = [self.visit(e) for e in target.elts] value = self.visit(node.value) return "{0} = {1}".format(", ".join(elts), value) if isinstance(node.scopes[-1], ast.If): outer_if = node.scopes[-1] target_id = self.visit(target) if target_id in outer_if.common_vars: value = self.visit(node.value) return "{0} = {1}".format(target_id, value) if isinstance(target, ast.Subscript) or isinstance( target, ast.Attribute): target = self.visit(target) value = self.visit(node.value) if value == None: value = "None" return "{0} = {1}".format(target, value) definition = node.scopes.find(target.id) if isinstance(target, ast.Name) and defined_before(definition, node): target = self.visit(target) value = self.visit(node.value) return "{0} = {1}".format(target, value) elif isinstance(node.value, ast.List): elements = [self.visit(e) for e in node.value.elts] mut = "" if is_mutable(node.scopes, get_id(target)): mut = "mutable " return "{1} = [{2}]".format(mut, self.visit(target), ", ".join(elements)) else: target = self.visit(target) value = self.visit(node.value) return f"{target} = {value}"
def visit_Assign(self, node): target = node.targets[0] if isinstance(target, ast.Tuple): elts = [self.visit(e) for e in target.elts] value = self.visit(node.value) return "std::tie({0}) = {1};".format(", ".join(elts), value) if isinstance(node.scopes[-1], ast.If): outer_if = node.scopes[-1] if target.id in outer_if.common_vars: value = self.visit(node.value) return "{0} = {1};".format(target.id, value) if isinstance(target, ast.Subscript): target = self.visit(target) value = self.visit(node.value) return "{0} = {1};".format(target, value) definition = node.scopes.find(target.id) if isinstance(target, ast.Name) and defined_before(definition, node): target = self.visit(target) value = self.visit(node.value) return "{0} = {1};".format(target, value) elif isinstance(node.value, ast.List): elements = [self.visit(e) for e in node.value.elts] return "{0} {1} {{{2}}};".format(decltype(node), self.visit(target), ", ".join(elements)) else: typename = "auto" if hasattr(target, "annotation"): typename = get_id(target.annotation) if typename in self._type_map: typename = self._type_map[typename] target = self.visit(target) value = self.visit(node.value) return f"{typename} {target} = {value};"
def visit_AnnAssign(self, node): target = node.target self.increase_use_count(get_id(target)) self.generic_visit(node) return node
def visit_Call(self, node): if hasattr(node.func, "attr"): if node.func.attr == "append": self.increase_use_count(get_id(node.func.value)) self.generic_visit(node) return node
def find_definition(scope, var_attr="vars"): for var in getattr(scope, var_attr): if get_id(var) == lookup: return var