See https://github.com/GNOME/glib/blob/master/gobject/gtype.h, line 1668 "The most general convenience macro for type implementations".
Such macros are only used in advanced GTK programming -- the gtksourceview test-completion.c used a similar one to define new gobject types. Some weeks ago I simple rebuild that used macro in an ordinary proc and got test_completion.nim running. But I thoungh before I release that example code I may try to test if a real macro may work also. Generally that macro would be only a constant multiline string with some inserted constants or vars (string interpolation). But it seems to be not that simple in Nim --it seems that Nim macros are more designed for very advanced tasks. My firsts simple tests already failed, so I created a github issue, but that is closed now, because it is not a bug. Yersterday I tried it again, with code like
# type_iface: The GType of the interface to add
# iface_init: The interface init function
proc g_implement_interface_str(type_iface, iface_init: string): string =
"""
var g_implement_interface_info = GInterfaceInfoObj(interface_init: cast[GInterfaceInitFunc]($2),
interface_finalize: nil,
interface_data: nil)
g_type_add_interface_static(g_define_type_id, $1, addr(g_implement_interface_info))
""" % [type_iface, iface_init]
# tn: The name of the new type, in Camel case.
# t: The name of the new type, in lowercase, with words separated by '_'.
# tp: The GType of the parent type.
# f: GTypeFlags to pass to g_type_register_static()
# c: Custom code that gets inserted in the *_get_type() function.
macro g_define_type_extended(tn, t, tp, f, c: string): stmt =
var s = """
proc $2_init(self: $1)
proc $2_class_init(klass: $1Class)
var $2_parent_class: gpointer = nil
proc $2_class_intern_init(klass: gpointer) =
$2_parent_class = g_type_class_peek_parent (klass);
$2t_class_init(cast[$1Class](klass))
proc $2_get_type(): GType =
var g_define_type_id_volatile {.global.}: gsize = 0
if g_once_init_enter(g_define_type_id_volatile):
var g_define_type_id: GType = g_type_register_static_simple($3,
g_intern_static_string("$1"),
sizeof($1ClassObj),
cast[GClassInitFunc]($2_class_intern_init),
sizeof($1Obj),
cast[GInstanceInitFunc]($2_init),
cast[GTypeFlags]($4));
$5
g_once_init_leave(g_define_type_id_volatile, g_define_type_id)
g_define_type_id_volatile
""" % [tn.strVal, t.strVal, tp.strVal, f.strVal, c]
result = parseStmt(s)
proc test_provider_iface_init(iface: gtksource.CompletionProviderIface)
g_define_type_extended("TestProvider", "test_provider", "g_object_get_type()", "0",
g_implement_interface_str("completion_provider_get_type()", "test_provider_iface_init"))
The difficulty is, that in C nested macros are used -- one macro is called with other macro as parameter. So I wrote a proc providing a string for the Nim macro. My feeling is, that I may do it completely wrong.
Compiler tells me: test_completion.nim(165, 49) Error: type mismatch: got (NimNode) but expected 'string'
I am not able to use string literals and the string returned by a proc at the same time for macro parameters.
[EDIT]
Maybe I should not use a macro at all, but a template?
I remembered from the manual this statement: "A template is a hygienic macro and so opens a new scope." But reading the template section again more carefully, I have the feeling that I can use templates also to declare module global variables and procs -- using inject. Maybe I should try that.
[EDIT 2]
But I have the feeling that templates are not really good at generating larger blocks of source code.
After a bit of thinking I have the feeling that one problem may be the fact, that one string parameter of my macro comes from a proc, so it is not already known at compile time. How to solve: Use a template instead of proc generating that string. Or may I apply the static keyword in a smart way?
[EDIT 3]
And wrong again. Nim is really smart in compile time evaluation. This works fine:
import strutils
proc t(s: string): string =
"abc$1xy" % s
const
b = t("hghhh")
echo b
But at least I just got it to compile with these modifications (and a few other fixes):
macro g_define_type_extended(tn, t, tp, f, c: static[string]): stmt = """ % [tn, t, tp, f, c]
Will see if it really works this way tomorrow.