From 727bb018050de3af2107802d626ba3a5d594bcff Mon Sep 17 00:00:00 2001 From: Johan Bilien Date: Tue, 21 Oct 2008 17:04:11 +0000 Subject: [PATCH] =?UTF-8?q?Bug=20557241=20=E2=80=93=20"throws"=20flag=20fo?= =?UTF-8?q?r=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2008-10-21 Johan Bilien Bug 557241 – "throws" flag for functions * tests/scanner/drawable-1.0-expected.gir, tests/scanner/drawable-injected-1.0-expected.gir, tests/scanner/drawable.[ch]: add simple test for throwing function (has GError ** as last argument) * giscanner/ast.py: add a 'throws' flag to Function * giscanner/glibtransformer.py: if a function's last paramerter is a GError, set the 'throws' flag and remove that parameter * giscanner/girwriter.py: write out the 'throws' attribute * giscanner/girparser.py: support parsing the 'throws' attribute * tests/repository/gitestthrows.c: add a simple test to check the throws flag in a typelib and invoke the function * girepository/ginfo.c, girepository/girnode.[ch], girepository/girnode.h, girepository/girparser.c, girepository/girepository.h: Add and parse the GI_FUNCTION_THROWS flag * girepository/ginvoke.c: if a function throws, add a GError as last arguments, and propagate the error to the invoker. svn path=/trunk/; revision=773 --- ginfo.c | 3 +++ ginvoke.c | 27 ++++++++++++++++++++++++++- girepository.h | 3 ++- girnode.c | 2 +- girnode.h | 1 + girparser.c | 9 ++++++++- gtypelib.h | 4 ++-- 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/ginfo.c b/ginfo.c index c165ade0a..fc265ad19 100644 --- a/ginfo.c +++ b/ginfo.c @@ -492,6 +492,9 @@ g_function_info_get_flags (GIFunctionInfo *info) if (blob->wraps_vfunc) flags = flags | GI_FUNCTION_WRAPS_VFUNC; + if (blob->throws) + flags = flags | GI_FUNCTION_THROWS; + return flags; } diff --git a/ginvoke.c b/ginvoke.c index d5182dbf7..2626a956d 100644 --- a/ginvoke.c +++ b/ginvoke.c @@ -159,9 +159,11 @@ g_function_info_invoke (GIFunctionInfo *info, GITypeInfo *tinfo; GIArgInfo *ainfo; gboolean is_method; + gboolean throws; gint n_args, n_invoke_args, in_pos, out_pos, i; gpointer *args; gboolean success = FALSE; + GError *local_error; symbol = g_function_info_get_symbol (info); @@ -178,6 +180,7 @@ g_function_info_invoke (GIFunctionInfo *info, is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0 && (g_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0; + throws = g_function_info_get_flags (info) & GI_FUNCTION_THROWS; tinfo = g_callable_info_get_return_type ((GICallableInfo *)info); rtype = get_ffi_type (tinfo); @@ -202,6 +205,11 @@ g_function_info_invoke (GIFunctionInfo *info, } else n_invoke_args = n_args; + + if (throws) + /* Add an argument for the GError */ + n_invoke_args ++; + atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args); args = g_alloca (sizeof (gpointer) * n_invoke_args); @@ -279,6 +287,15 @@ g_function_info_invoke (GIFunctionInfo *info, } g_base_info_unref ((GIBaseInfo *)ainfo); } + + local_error = NULL; + if (throws) + { + gpointer address = &local_error; + args[n_invoke_args - 1] = &address; + atypes[n_invoke_args - 1] = &ffi_type_pointer; + } + if (in_pos < n_in_args) { g_set_error (error, @@ -301,7 +318,15 @@ g_function_info_invoke (GIFunctionInfo *info, ffi_call (&cif, func, return_value, args); - success = TRUE; + if (local_error) + { + g_propagate_error (error, local_error); + success = FALSE; + } + else + { + success = TRUE; + } out: return success; } diff --git a/girepository.h b/girepository.h index 2e6c5c8d5..1ab326b7a 100644 --- a/girepository.h +++ b/girepository.h @@ -190,7 +190,8 @@ typedef enum GI_FUNCTION_IS_CONSTRUCTOR = 1 << 1, GI_FUNCTION_IS_GETTER = 1 << 2, GI_FUNCTION_IS_SETTER = 1 << 3, - GI_FUNCTION_WRAPS_VFUNC = 1 << 4 + GI_FUNCTION_WRAPS_VFUNC = 1 << 4, + GI_FUNCTION_THROWS = 1 << 5 } GIFunctionInfoFlags; const gchar * g_function_info_get_symbol (GIFunctionInfo *info); diff --git a/girnode.c b/girnode.c index ee1af3b37..e6fc799d9 100644 --- a/girnode.c +++ b/girnode.c @@ -1477,7 +1477,7 @@ g_ir_node_build_typelib (GIrNode *node, blob->getter = function->is_getter; blob->constructor = function->is_constructor; blob->wraps_vfunc = function->wraps_vfunc; - blob->reserved = 0; + blob->throws = function->throws; blob->index = 0; blob->name = write_string (node->name, strings, data, offset2); blob->symbol = write_string (function->symbol, strings, data, offset2); diff --git a/girnode.h b/girnode.h index 905bf90a1..0ef95df72 100644 --- a/girnode.h +++ b/girnode.h @@ -92,6 +92,7 @@ struct _GIrNodeFunction gboolean is_getter; gboolean is_constructor; gboolean wraps_vfunc; + gboolean throws; gchar *symbol; diff --git a/girparser.c b/girparser.c index 539d68d2e..fb5b68bee 100644 --- a/girparser.c +++ b/girparser.c @@ -527,6 +527,7 @@ start_function (GMarkupParseContext *context, const gchar *name; const gchar *symbol; const gchar *deprecated; + const gchar *throws; GIrNodeFunction *function; gboolean found = FALSE; @@ -557,6 +558,7 @@ start_function (GMarkupParseContext *context, name = find_attribute ("name", attribute_names, attribute_values); symbol = find_attribute ("c:identifier", attribute_names, attribute_values); deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + throws = find_attribute ("throws", attribute_names, attribute_values); if (name == NULL) { @@ -598,7 +600,12 @@ start_function (GMarkupParseContext *context, if (strcmp (element_name, "callback") == 0) ((GIrNode *)function)->type = G_IR_NODE_CALLBACK; } - + + if (throws && strcmp (throws, "1") == 0) + function->throws = TRUE; + else + function->throws = FALSE; + if (ctx->current_node == NULL) { ctx->current_module->entries = diff --git a/gtypelib.h b/gtypelib.h index 443d34b6c..8bb877779 100644 --- a/gtypelib.h +++ b/gtypelib.h @@ -166,11 +166,11 @@ typedef struct guint16 blob_type; /* 1 */ guint16 deprecated : 1; - guint16 setter : 1; + guint16 setter : 1; guint16 getter : 1; guint16 constructor : 1; guint16 wraps_vfunc : 1; - guint16 reserved : 1; + guint16 throws : 1; guint16 index :10; guint32 name;