options gen2 options indenting = 4 options no_unused_block_arguments = false options no_unused_function_arguments = false options strict_smart_pointers = true module interfaces shared private require daslib/ast_boost require daslib/templates_boost require daslib/defer require daslib/generic_return require strings require ast [structure_macro(name="interface")] class InterfaceMacro : AstStructureAnnotation { //! implements 'interface' macro, which verifies if class is an interface (no own variables) def override finish(var st : StructurePtr; var group : ModuleGroup; args : AnnotationArgumentList; var errors : das_string) : bool { for (fld in st.fields) { if (fld.name == "__rtti") { continue } if (!fld._type.isFunction) { errors := "interface can only define functions. {fld.name} is not a function\n{errors}" return false } } return true } } [structure_macro(name="implements")] class ImplementsMacro : AstStructureAnnotation { //! implements 'implements' macro, adds get`{Interface} method as well as interface bindings and implementation. def override apply(var st : StructurePtr; var group : ModuleGroup; args : AnnotationArgumentList; var errors : das_string) : bool { if (length(args) != 1) { errors := "implements macro takes exactly one argument" return false } var iface_name : string if (args[0].basicType == Type.tBool) { iface_name = string(args[0].name) } elif (args[0].basicType == Type.tString && args[0].name == "name") { iface_name = string(args[0].sValue) } else { errors := "expecting [implements(InteraceName)] or [implements(name=InteraceName)]" return false } // base interface class var parent <- compiling_program() |> find_unique_structure(iface_name) if (parent == null) { errors := "{iface_name} not found" return false } // all names let iface_var_name = "_interface_{iface_name}" let iface_class_name = "_implementation_{st.name}_{iface_name}" let iface_get_name = "get`{iface_name}" let iface_get_name_func = "{st.name}`{iface_get_name}" // make class for the interface, remove 'interface' annotation var inscope cls <- make_class(iface_class_name, parent, st._module) cls.flags |= StructureFlags.privateStructure var iface_index = -1 for (ann, ii in cls.annotations, count()) { if (ann.annotation.name == "interface") { iface_index = ii break } } if (iface_index == -1) { errors := "can only implement interfaces, {iface_name} is not an [interface]" return false } cls.annotations |> erase(iface_index) // add {st}::_interface_{Foo} : Foo? var inscope iface_ptr <- qmacro_type(type<$t(parent)?>) st |> add_structure_field(iface_var_name, clone_type(iface_ptr), default) // add function {st}::get`{Foo} : Foo? var inscope fn_get_i <- qmacro_method(iface_get_name_func, st) <| $(var self : $t(st)) : $t(iface_ptr) { if (self.$f(iface_var_name) == null) { self.$f(iface_var_name) = new <$t(cls)>(unsafe(addr(self))) } return self.$f(iface_var_name) } add_function(st._module, fn_get_i) // add {cls}::_self : {ST}? var inscope st_ptr <- qmacro_type(type<$t(st)?>) let fi = cls |> add_structure_field("_self", clone_type(st_ptr), default) cls.fields[fi].annotation |> add_annotation_argument("do_not_delete", true) cls.fields[fi].flags |= FieldDeclarationFlags.doNotDelete | FieldDeclarationFlags.privateField // add {cls} ( var s : {ST}? ) var inscope ctor <- qmacro_function("{iface_class_name}`{iface_class_name}") <| $(s : $t(st_ptr)) { _self = s } var inscope ctor_fun <- make_class_constructor(cls, ctor) modify_to_class_member(cls, ctor, false, false) add_function(st._module, ctor) add_function(st._module, ctor_fun) // add get`{Foo} : Foo? st |> add_structure_field( iface_get_name, qmacro_type(type>), qmacro(@@$i(iface_get_name_func)) ) // now, for the methods let skipl = length(iface_name) + 1 for (fld in st.fields) { if (string(fld.name) |> starts_with("{iface_name}`")) { let method_name = string(fld.name) |> slice(skipl) var found = false for (cm in cls.fields) { if (cm.name == method_name) { found = true let fmethod_name = "{iface_class_name}`{method_name}" cm.init := null unsafe { cm.init <- qmacro(cast<$t(cm._type)>(@@$i(fmethod_name))) } var inscope fmethod_args : array var inscope fcall_args : array for (n, t in cm._type.argNames, cm._type.argTypes) { if (n != "self") { fcall_args |> emplace_new <| qmacro($i(n)) fmethod_args |> emplace_new <| new Variable(name := n, _type <- clone_type(t)) } } var inscope fmethod <- qmacro_method(fmethod_name, cls) <| $(self : $t(cls); $a(fmethod_args)) : $t(cm._type.firstType) { generic_return(invoke(self._self.$f(fld.name), *self._self, $a(fcall_args))) } add_function(st._module, fmethod) break } } if (!found) { errors := "unknown interface method {method_name} in {iface_class_name}" return false } } } add_structure(st._module, cls) return true } }