gimp/tools/gcg/marshall.c

333 lines
7.3 KiB
C

#include "gcg.h"
#include "output.h"
#include "marshall.h"
static GHashTable* sigtype_hash;
typedef enum {
MARSHALL_INT,
MARSHALL_DOUBLE,
MARSHALL_POINTER,
MARSHALL_VOID,
MARSHALL_LONG
} MarshallType;
struct _SignalType {
Id package;
Id module;
MarshallType rettype;
GSList* argtypes;
};
MarshallType marshalling_type(Type* t){
if(!t)
return MARSHALL_VOID;
if(t->indirection)
return MARSHALL_POINTER;
if(!t->prim)
return MARSHALL_VOID;
switch(t->prim->kind){
case TYPE_INT:
case TYPE_FLAGS:
case TYPE_ENUM:
return MARSHALL_INT;
case TYPE_LONG:
return MARSHALL_LONG;
case TYPE_DOUBLE:
return MARSHALL_DOUBLE;
case TYPE_NONE:
return MARSHALL_VOID;
default:
g_assert_not_reached();
return MARSHALL_VOID;
}
}
/* Yes, this is hyperbly kludgetical */
SignalType* sig_type(Method* m){
SignalType *t=g_new(SignalType, 1), *s;
GSList* p=m->params, *a=NULL;
PNode* g;
gchar* f;
t->package = DEF(MEMBER(m)->my_class)->type->module->package->name;
t->module = DEF(MEMBER(m)->my_class)->type->module->name;
t->rettype = marshalling_type(&m->ret_type);
if(!sigtype_hash)
sigtype_hash = g_hash_table_new(g_str_hash, g_str_equal);
while(p){
Param* param=p->data;
MarshallType* t=g_new(MarshallType, 1);
*t=marshalling_type(&param->type);
a=g_slist_prepend(a, t);
p=p->next;
}
a=g_slist_reverse(a);
t->argtypes=a;
g = p_signal_demarshaller_name(t);
f = p_to_str(g, NULL);
p_unref(g);
s = g_hash_table_lookup(sigtype_hash, f);
if(!s){
g_hash_table_insert(sigtype_hash, f, t);
return t;
}
else{
sig_type_free(t);
g_free(f);
return s;
}
}
void sig_type_free(SignalType* t){
GSList* l=t->argtypes;
while(l){
g_free(l->data);
l=l->next;
}
g_slist_free(t->argtypes);
g_free(t);
}
typedef enum{
GTKNAME,
ENCODING,
CTYPE
} MMap;
PNode* p_gtype_name(MarshallType t, MMap map){
static const struct GTypeName{
MarshallType type;
Id gtkname;
Id encoding;
Id ctype;
}names[]={
{MARSHALL_POINTER, "POINTER", "P", "gpointer"},
{MARSHALL_INT, "INT", "I", "gint"},
{MARSHALL_DOUBLE, "DOUBLE", "D", "gdouble"},
{MARSHALL_LONG, "LONG", "L", "glong"},
{MARSHALL_VOID, "NONE", "0", "void"},
};
gint i;
for(i=0;i<(gint)(sizeof(names)/sizeof(names[0]));i++)
if(names[i].type==t){
Id id;
switch(map){
case GTKNAME:
id = names[i].gtkname;
break;
case ENCODING:
id = names[i].encoding;
break;
case CTYPE:
id = names[i].ctype;
break;
}
return p_str(id);
}
g_assert_not_reached();
return NULL;
}
PNode* p_gtabbr(gpointer p){
MarshallType* t=p;
return p_gtype_name(*t, ENCODING);
}
PNode* p_gtktype(Type* t){
if(t->indirection==0){
if(!t->prim)
return p_str("GTK_TYPE_NONE");
switch(t->prim->kind){
case TYPE_INT:
return p_str("GTK_TYPE_INT");
case TYPE_DOUBLE:
return p_str("GTK_TYPE_DOUBLE");
case TYPE_ENUM:
case TYPE_FLAGS:
return p_macro_name(t->prim, "TYPE", NULL);
case TYPE_CHAR:
return p_str("GTK_TYPE_CHAR");
case TYPE_FOREIGN:
g_error("Cannot marshall foreign type %s.%s!",
t->prim->module->package->name,
t->prim->name);
return NULL;
default:
g_error("Cannot marshall type by value: %s.%s",
t->prim->module->package->name,
t->prim->name);
return NULL;
}
}else if(t->indirection==1
&& t->prim
&& (t->prim->kind==TYPE_BOXED
|| t->prim->kind==TYPE_OBJECT))
return p_macro_name(t->prim, "TYPE", NULL);
else
return p_str("GTK_TYPE_POINTER");
}
PNode* p_signal_func_name(SignalType* t, PNode* basename){
#if 1
return p_fmt("_~_~_~_~~",
p_c_ident(t->package),
p_c_ident(t->module),
basename,
p_gtype_name(t->rettype, ENCODING),
p_for(t->argtypes, p_gtabbr, p_nil));
#else
return p_fmt("_~_~_~~",
p_c_ident(t->package),
basename,
p_gtype_name(t->rettype, ENCODING),
p_for(t->argtypes, p_gtabbr, p_nil));
#endif
}
PNode* p_signal_marshaller_name(SignalType* t){
return p_signal_func_name(t, p_str("marshall"));
}
PNode* p_signal_demarshaller_name(SignalType* t){
return p_signal_func_name(t, p_str("demarshall"));
}
PNode* p_handler_type(SignalType* t){
#if 1
return p_fmt("_~~Handler_~~",
p_str(t->package),
p_str(t->module),
p_gtype_name(t->rettype, ENCODING),
p_for(t->argtypes, p_gtabbr, p_nil));
#else
return p_fmt("_~Handler_~~",
p_str(t->package),
p_gtype_name(t->rettype, ENCODING),
p_for(t->argtypes, p_gtabbr, p_nil));
#endif
}
PNode* p_signal_id(Method* s){
PrimType* t=DEF(MEMBER(s)->my_class)->type;
return p_fmt("_~_~_signal_~",
p_c_ident(t->module->package->name),
p_c_ident(t->name),
p_c_ident(MEMBER(s)->name));
}
typedef struct{
PNode* args;
gint idx;
}ArgMarshData;
PNode* p_arg_marsh(gpointer p, gpointer d){
Param* par=p;
gint* idx=d;
(*idx)++;
return p_fmt(/* "\targs[~].type=~;\n" unnecessary... */
"\tGTK_VALUE_~(args[~]) = ~;\n",
/* p_prf("%d", *idx),
p_gtktype(&par->type), */
p_gtype_name(marshalling_type(&par->type), GTKNAME),
p_prf("%d", *idx),
p_c_ident(par->name));
}
PNode* p_sig_marshalling(Method* m){
gint idx=-1;
gint nargs = g_slist_length(m->params);
gboolean ret = marshalling_type(&m->ret_type)!=MARSHALL_VOID;
return p_fmt("\t{\n"
"~"
"~"
"~"
"~"
"\tgtk_signal_emitv((GtkObject*)~, ~, ~);\n"
"~"
"\t}\n",
nargs > 0
? p_fmt("\tGtkArg args[~];\n",
p_prf("%d", nargs+ret))
: p_nil,
ret
?p_fmt("\t~ retval;\n",
p_type(&m->ret_type))
:p_nil,
p_for(m->params, p_arg_marsh, &idx),
ret
/* cannot use retloc here, ansi forbids casted lvalues */
?p_fmt("\tGTK_VALUE_POINTER(args[~]) = &retval;\n",
p_prf("%d", nargs))
:p_nil,
p_c_ident(DEF(MEMBER(m)->my_class)->type->name),
p_signal_id(m),
nargs > 0
? p_str("args")
: p_str("NULL"),
ret
?p_str("\treturn retval;\n")
:p_nil);
}
PNode* p_arg_demarsh(gpointer p, gpointer d){
MarshallType* t=p;
gint* data=d;
(*data)++;
return p_fmt("\t\tGTK_VALUE_~(args[~]),\n",
p_gtype_name(*t, FALSE),
p_prf("%d", *data));
}
PNode* p_sig_arg_ctype(MarshallType* t){
return p_fmt(", ~", p_gtype_name(*t, CTYPE));
}
PNode* p_sigdemarsh_decl(SignalType* t){
#if 1
return p_fmt("static void ~ (GtkObject*, GtkSignalFunc, "
"gpointer, GtkArg*);\n"
"typedef ~ (*~)(GtkObject*~, gpointer);\n",
p_signal_demarshaller_name(t),
p_gtype_name(t->rettype, CTYPE),
p_handler_type(t),
p_for(t->argtypes, p_sig_arg_ctype, p_nil));
#else
return p_fmt("extern void ~ (GtkObject*, GtkSignalFunc, "
"gpointer, GtkArg*);\n",
p_signal_demarshaller_name(t));
#endif
}
PNode* p_demarshaller(SignalType* t){
gint idx=-1;
return p_fmt("static void ~ (\n"
"\tGtkObject* object,\n"
"\tGtkSignalFunc func,\n"
"\tgpointer user_data,\n"
"\tGtkArg* args){\n"
"\t(void)args;\n"
"~~"
"}\n",
p_signal_demarshaller_name(t),
(t->rettype==TYPE_NONE)
? p_fmt("\t*(GTK_RETLOC_~(args[~])) =\n",
p_gtype_name(t->rettype, FALSE),
p_prf("%d", g_slist_length(t->argtypes)))
: p_nil,
p_fmt("\t~(object,\n"
"~"
"\tuser_data);\n",
p_cast(p_handler_type(t), p_str("func")),
p_for(t->argtypes, p_arg_demarsh, &idx)));
}