Esempio n. 1
0
    def new_empty(cls, cls_node: ast.Class, cls_type: cgen.ClassType):
        new_empty = cgen.Function("new_empty_" + cls_node.meta["c_name"], {}, cls_type, [
            cgen.Declare(cls_type, "obj", cgen.Call(cgen.GetVar("malloc"), [cgen.SizeOf(cls_type.struct)])),
            cgen.StrStmt(f"obj->meta.self = obj;\n"
                         f"obj->meta.up = obj;\n"
                         f"obj->meta.ref_count = 0;\n"
                         f"obj->meta.ref_ptr = &(obj->meta.ref_count);\n"
                         f"obj->meta.del = del_{cls_node.meta['c_name']};"),
            *(
                cgen.StrStmt(f"new_parent_{base.name}(&obj->parent_{base.name}, obj, obj);")
                for base in cls_type.bases
            ),

            *(
                cgen.ExprStmt(cls_type.set_name_expr(cgen.Deref(cgen.GetVar('obj')), attr, cls.default_of(attr_type)))
                for attr, attr_type in cls_type.all_attrs()
            ),

            *(
                cgen.ExprStmt(
                    cls_type.set_name_expr(cgen.Deref(cgen.GetVar("obj")), method_name, cgen.GetVar(method_c_name)))
                for method_name, method_c_name in cls_node.meta["all methods"].items()
            ),
            cgen.Return(cgen.GetVar('obj'))
        ])
        return new_empty
Esempio n. 2
0
    def visit_Class(self, node: ast.Class, is_main=False):
        # TODO refactor this?

        cls_type: cgen.ClassType = node.meta["type"]
        has_constructor = node.meta["has_constructor"]
        has_destructor = False  # TODO: node.meta["has destructor"]

        cls_struct = cgen.Struct(node.meta["c_name"], {
            'meta': cgen.StructType("BaseObject"),

            **{'parent_' + base.name: base.struct for base in cls_type.bases},

            **cls_type.attrs,
            **cls_type.methods,
        })
        cls_type.struct = cls_struct.struct_type

        new_empty = self.new_empty(node, cls_type)

        redirects = []
        for method_name, method_c_name in node.meta["inherited methods"].items():
            redirect = self.redirect(cls_type, method_name, method_c_name)
            redirects.append(redirect)

        new_parent = self.new_parent(node, cls_type)

        body_stmt_items = []
        for body_stmt in node.body:
            body_stmt_items += self.visit(body_stmt)

        if not has_constructor:
            new = cgen.Function("new_" + node.meta["c_name"], {}, cls_type, [
                cgen.StrStmt(f"{cls_type.with_name('obj')} = new_empty_{cls_type.name}();\n"
                             f"return obj;")
            ])
            cls_type.func_names["new"] = new.name
            body_stmt_items.append(new)

        if not has_destructor:
            del_ = cgen.Function("del_" + node.meta["c_name"], {"obj": cgen.VoidPtr}, cgen.Void, [
                cgen.StrStmt(f"{cls_type} self = obj;"),
                cgen.dec_refs(cgen.StrExpr(f"self->{attr}")
                              for attr, typ in cls_type.attrs.items() if cgen.is_cls(typ)),
                cgen.ExprStmt(cgen.Call(cgen.GetVar("free"), [cgen.GetVar("self")]))
            ])
            cls_type.func_names["del"] = del_.name
            body_stmt_items.append(del_)

        return [cls_struct, new_empty, new_parent] + redirects + body_stmt_items
Esempio n. 3
0
    def redirect(cls, cls_type: cgen.ClassType, name: str, func_name: str):
        redirect_type: cgen.FuncType = cls_type.get_name(name)

        assert isinstance(redirect_type, cgen.SingleFuncType)

        args = {'_self': cgen.VoidPtr, **{f"arg_{i}": arg_type for i, arg_type in enumerate(redirect_type.args[1:])}}

        passed = [cgen.Ref(cls_type.cast_for_name_expr(cgen.Deref(cgen.GetVar('self')), name))] + \
                 [cgen.GetVar(f"arg_{i}") for i, arg_type in enumerate(redirect_type.args[1:])]

        to_func = cgen.GetVar(cls_type.get_func_name(name))

        is_ret = not cgen.is_void(redirect_type.ret)
        redirect = cgen.Function(func_name, args, redirect_type.ret, [
            cgen.StrStmt(f"{cls_type} self = _self;"),
            (cgen.Return if is_ret else cgen.ExprStmt)(cgen.Call(to_func, passed))
        ]
                                 )
        return redirect
Esempio n. 4
0
    def visit_Constructor(self, node: ast.Constructor):
        body = []
        cls_type = node.meta["cls"]
        body.append(cgen.Declare(node.meta["cls"], "self", cgen.StrExpr(f"new_empty_{cls_type.name}()")))

        for stmt in node.body:
            body.append(self.visit(stmt))

        body.append(cgen.Return(cgen.GetVar("self")))

        return [cgen.Function(node.meta["c_name"], node.meta["args"], node.meta["cls"], body)]
Esempio n. 5
0
    def coerce_expr(cls, expr: cgen.Expression, from_type: cgen.Type, to_type: cgen.Type, node):
        if from_type is to_type:
            return expr

        if cgen.is_cls(from_type) and cgen.is_cls(to_type):
            # noinspection PyUnresolvedReferences
            return cgen.Ref(from_type.cast_expr(cgen.Deref(expr), to_type))
        else:
            if cgen.is_cls(to_type):
                if cgen.is_int(from_type):
                    as_object = cgen.Call(cgen.GetVar("_new_Integer"), [expr])
                    return cgen.Ref(cgen.Integer.cast_expr(cgen.Deref(as_object), to_type))
                else:
                    raise Exception(from_type, to_type)
            else:
                raise CompilingError(f"Cannot coerce {from_type} to {to_type}", node.line, node.pos)
Esempio n. 6
0
    def visit_Call(self, node: ast.Call):
        args = []
        if isinstance(node.callee, ast.GetAttr):
            obj = node.callee.obj
            args.append(cgen.StrExpr(f"{self.visit(obj)}->meta.self"))
            expected_args = node.meta["func"].args[1:]

            args += [self.coerce_node(arg_node, expected) for arg_node, expected in zip(node.args, expected_args)]

            return cgen.Call(self.visit(node.callee), args)
        else:
            poss_func_type: cgen.FuncType = node.callee.meta["ret"]
            passed = [arg.meta["ret"] for arg in node.args]
            func_type = poss_func_type.type_for(passed)

            func_name = func_type.c_name
            expected_args = func_type.args

            args += [self.coerce_node(arg_node, expected) for arg_node, expected in zip(node.args, expected_args)]

            return cgen.Call(cgen.GetVar(func_name), args)
Esempio n. 7
0
 def visit_GetVar(self, node: ast.GetVar):
     return cgen.GetVar(node.meta["c_name"])
Esempio n. 8
0
 def visit_New(self, node: ast.New):
     return cgen.Call(cgen.GetVar(node.meta["cls"].func_names["new"]), [self.visit(arg) for arg in node.args])
Esempio n. 9
0
 def visit_ReturnStmt(self, node: ast.ReturnStmt):
     to_delete: Dict[str, str] = node.meta["to delete"]
     dels = cgen.dec_refs(cgen.GetVar(c_name) for c_name in to_delete.values())
     return cgen.UnscopedBlock([dels, cgen.Return(self.visit(node.expr))])
Esempio n. 10
0
 def visit_Method(self, node: ast.Method):
     body = []
     body.append(cgen.Declare(node.meta["cls"], "self", cgen.Cast(cgen.GetVar("_self"), node.meta["cls"])))
     for stmt in node.body:
         body.append(self.visit(stmt))
     return [cgen.Function(node.meta["c_name"], node.meta["args"], node.meta["ret"], body)]