└── py_java_compiler.py /py_java_compiler.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import ast 4 | import inspect 5 | from typing import List, IO 6 | 7 | 8 | class JavaGenerator(ast.NodeVisitor): 9 | def __init__(self, stream: IO): 10 | self.stream = stream 11 | 12 | def out(self, text: str): 13 | self.stream.write(str(text)) 14 | 15 | def indent(self, node: ast.AST): 16 | self.out(" " * node.col_offset) 17 | 18 | def visit(self, node): 19 | getattr(self, "visit_"+node.__class__.__name__)(node) 20 | 21 | def visit_Module(self, node: ast.Module): 22 | for stmt in node.body: 23 | self.visit(stmt) 24 | 25 | def visit_ClassDef(self, node: ast.ClassDef): 26 | self.out(f"public class {node.name} {{\n") 27 | for stmt in node.body: 28 | self.visit(stmt) 29 | self.out("\n") 30 | self.out("}\n") 31 | 32 | @staticmethod 33 | def ann(name): 34 | typ_dict = { 35 | "int": "Integer", 36 | "str": "String" 37 | } 38 | return typ_dict[name] 39 | 40 | def visit_Expr(self, node: ast.Expr): 41 | self.indent(node) 42 | self.visit(node.value) 43 | self.out(";\n") 44 | 45 | def visit_If(self, node: ast.If): 46 | self.indent(node) 47 | self.out("if (") 48 | self.visit(node.test) 49 | self.out(") {\n") 50 | for stmt in node.body: 51 | self.visit(stmt) 52 | self.indent(node) 53 | self.out("}") 54 | if hasattr(node, "orelse"): 55 | self.out(" else {\n") 56 | for stmt in node.orelse: 57 | self.visit(stmt) 58 | self.indent(node) 59 | self.out("}") 60 | self.out("\n") 61 | 62 | def visit_FunctionDef(self, node: ast.FunctionDef): 63 | if node.name == "__init__": 64 | # TODO: Maybe search __annotations__ for the instance vars instead? 65 | instance_vars = [self.ann(arg.annotation.id) + " " + arg.arg for arg in node.args.args if arg.arg != "self"] 66 | for var in instance_vars: 67 | self.indent(node) 68 | self.out(var) 69 | self.out(";\n") 70 | 71 | self.out("\n") 72 | self.indent(node) 73 | self.out("public ") 74 | cls_name = next(arg.annotation.id for arg in node.args.args if arg.arg == "self") 75 | self.out(cls_name) 76 | self.out("(") 77 | self.out(", ".join(self.ann(arg.annotation.id)+" "+arg.arg for arg in node.args.args if arg.arg != "self")) 78 | self.out(") {\n") 79 | 80 | for stmt in node.body: 81 | self.visit(stmt) 82 | self.indent(node) 83 | self.out("}\n") 84 | else: 85 | self.indent(node) 86 | 87 | if any((dec.id == "staticmethod" if isinstance(dec, ast.Name) else False) for dec in node.decorator_list): 88 | self.out("public static ") 89 | else: 90 | self.out("public ") 91 | self.visit(node.returns) 92 | # self.out(self.ann(node.returns.id)) 93 | self.out(" ") 94 | self.out(node.name) 95 | 96 | self.out("(") 97 | sep = "" 98 | for arg in node.args.args: 99 | if arg.arg == "self": 100 | continue 101 | elif isinstance(arg.annotation, ast.Subscript): 102 | self.out(sep) 103 | if isinstance(arg.annotation.value, ast.Name) and arg.annotation.value.id == "List": 104 | if isinstance(arg.annotation.slice, ast.Index): 105 | self.out(self.ann(arg.annotation.slice.value.id)) 106 | self.out("[]") 107 | else: 108 | raise NotImplementedError() 109 | else: 110 | # print(arg.annotation.value.value) 111 | raise NotImplementedError() 112 | elif isinstance(arg.annotation, ast.Name): 113 | self.out(sep) 114 | self.out(self.ann(arg.annotation.id)) 115 | else: 116 | raise NotImplementedError() 117 | self.out(" ") 118 | self.out(arg.arg) 119 | sep = ", " 120 | self.out(") {\n") 121 | 122 | for stmt in node.body: 123 | self.visit(stmt) 124 | 125 | # print(node.col_offset) 126 | self.indent(node) 127 | self.out("}\n") 128 | 129 | def visit_BinOp(self, node: ast.BinOp): 130 | if isinstance(node.op, ast.Mult): 131 | self.out("(") 132 | self.visit(node.left) 133 | self.out(" * ") 134 | self.visit(node.right) 135 | self.out(")") 136 | elif isinstance(node.op, ast.Pow): 137 | self.out("Math.pow(") 138 | self.visit(node.left) 139 | self.out(", ") 140 | self.visit(node.right) 141 | self.out(")") 142 | elif isinstance(node.op, ast.Add): 143 | self.out("(") 144 | self.visit(node.left) 145 | self.out(" + ") 146 | self.visit(node.right) 147 | self.out(")") 148 | elif isinstance(node.op, ast.Sub): 149 | self.out("(") 150 | self.visit(node.left) 151 | self.out(" - ") 152 | self.visit(node.right) 153 | self.out(")") 154 | else: 155 | raise NotImplementedError(node.op) 156 | 157 | def visit_Compare(self, node: ast.Compare): 158 | if isinstance(node.ops[0], ast.Gt): 159 | self.out("(") 160 | self.visit(node.left) 161 | self.out(" > ") 162 | self.visit(node.comparators[0]) 163 | self.out(")") 164 | elif isinstance(node.ops[0], ast.Lt): 165 | self.out("(") 166 | self.visit(node.left) 167 | self.out(" < ") 168 | self.visit(node.comparators[0]) 169 | self.out(")") 170 | else: 171 | raise NotImplementedError(node.op) 172 | 173 | def visit_NameConstant(self, node: ast.NameConstant): 174 | if node.value is True: 175 | self.out("true") 176 | elif node.value is False: 177 | self.out("false") 178 | elif node.value is None: 179 | self.out("void") 180 | else: 181 | raise NotImplementedError() 182 | 183 | def visit_Name(self, node: ast.Name): 184 | if isinstance(node.ctx, ast.Load): 185 | name = node.id 186 | if name == "int": 187 | self.out("Integer") 188 | else: 189 | self.out(node.id) 190 | else: 191 | raise NotImplementedError() 192 | 193 | def visit_Attribute(self, node: ast.Attribute): 194 | if isinstance(node.ctx, ast.Load): 195 | if isinstance(node.value, ast.Name) and node.value.id == "self": 196 | self.out("this.") 197 | else: 198 | self.out(node.value) 199 | self.out(".") 200 | self.out(node.attr) 201 | else: 202 | raise NotImplementedError() 203 | 204 | def visit_Return(self, node: ast.Return): 205 | self.indent(node) 206 | self.out("return ") 207 | self.visit(node.value) 208 | self.out(";\n") 209 | 210 | def visit_Assign(self, node: ast.Assign): 211 | self.indent(node) 212 | 213 | target = node.targets[0] 214 | 215 | if isinstance(target, ast.Name): 216 | self.out(target.id) 217 | elif isinstance(target, ast.Attribute): 218 | if isinstance(target.value, ast.Name) and target.value.id == "self": 219 | self.out("this.") 220 | else: 221 | # self.visit(target.value) 222 | self.out(target.value) 223 | self.out(".") 224 | self.out(target.attr) 225 | else: 226 | raise NotImplementedError() 227 | 228 | self.out(" = ") 229 | 230 | self.visit(node.value) 231 | self.out(";\n") 232 | 233 | def visit_AnnAssign(self, node: ast.AnnAssign): 234 | self.indent(node) 235 | 236 | if isinstance(node.target, ast.Name): 237 | self.out(self.ann(node.annotation.id) + " " + node.target.id) 238 | elif isinstance(node.target, ast.Attribute): 239 | self.out(self.ann(node.annotation.id)) 240 | self.out(" ") 241 | if isinstance(node.target.value, ast.Name) and node.target.value.id == "self": 242 | pass 243 | else: 244 | self.out(node.target.value) 245 | self.out(".") 246 | self.out(node.target.attr) 247 | else: 248 | raise NotImplementedError() 249 | 250 | self.out(" = ") 251 | 252 | self.visit(node.value) 253 | self.out(";\n") 254 | 255 | def visit_Call(self, node: ast.Call): 256 | if isinstance(node.func, ast.Name) and node.func.id == "int": 257 | self.out("(int) (") 258 | self.visit(node.args[0]) 259 | self.out(")") 260 | else: 261 | self.visit(node.func) 262 | self.out("(") 263 | 264 | sep = "" 265 | for arg in node.args: 266 | self.out(sep) 267 | self.visit(arg) 268 | sep = ", " 269 | self.out(")") 270 | 271 | def visit_Num(self, node: ast.Num): 272 | self.out(node.n) 273 | 274 | 275 | def generate_java(func): 276 | code = ast.parse(inspect.getsource(func)) 277 | with open("out.java", "w") as file: 278 | JavaGenerator(file).visit(code) 279 | 280 | 281 | class Main: 282 | def __init__(self: Main, name: int): 283 | self.name = name 284 | 285 | @staticmethod 286 | def main(self, args: List[str]) -> None: 287 | print(self.fibo(15)) 288 | 289 | @staticmethod 290 | def fibo(self, n: int) -> int: 291 | if n < 2: 292 | return n 293 | else: 294 | return self.fibo(n-1) + self.fibo(n-2) 295 | 296 | 297 | generate_java(Main) 298 | --------------------------------------------------------------------------------