[template-glib] scope: add resolver to handle missing symbols
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [template-glib] scope: add resolver to handle missing symbols
- Date: Sat, 14 May 2016 10:32:47 +0000 (UTC)
commit 20cf4a1f546b75f348483bfcd3fdf4ef837e5bb6
Author: Christian Hergert <chergert redhat com>
Date: Sat May 14 13:09:47 2016 +0300
scope: add resolver to handle missing symbols
If we fail to locate a symbol, allow a resolver to generate the symbol.
If successful, it will cache the symbol result in the top-most scope.
We might want to cache the symbol in the scope that generated it, but
it is not yet clear to me if that is the right idea. So I'll be a bit
conservative and stash it in the scope closest to access.
src/main.c | 20 ++++++++++++++
src/tmpl-scope.c | 77 ++++++++++++++++++++++++++++++++++++++++++------------
src/tmpl-scope.h | 29 +++++++++++++-------
3 files changed, 99 insertions(+), 27 deletions(-)
---
diff --git a/src/main.c b/src/main.c
index 76de746..d1cae25 100644
--- a/src/main.c
+++ b/src/main.c
@@ -21,6 +21,24 @@
#include <stdlib.h>
#include <tmpl-glib.h>
+static gboolean
+method_missing (TmplScope *scope,
+ const gchar *name,
+ TmplSymbol **symbol,
+ gpointer user_data)
+{
+ g_autofree gchar *str = g_strdup_printf ("missing symbol: %s", name);
+
+ g_assert (scope != NULL);
+ g_assert (name != NULL);
+ g_assert (symbol != NULL);
+
+ *symbol = tmpl_symbol_new ();
+ tmpl_symbol_assign_string (*symbol, str);
+
+ return TRUE;
+}
+
gint
main (gint argc,
gchar *argv[])
@@ -47,6 +65,8 @@ main (gint argc,
file = g_file_new_for_commandline_arg (argv [1]);
scope = tmpl_scope_new ();
+ tmpl_scope_set_resolver (scope, method_missing, NULL, NULL);
+
if (!tmpl_template_parse_file (tmpl, file, NULL, &error))
{
g_printerr ("ERROR: %s\n", error->message);
diff --git a/src/tmpl-scope.c b/src/tmpl-scope.c
index f1c892a..a4a0792 100644
--- a/src/tmpl-scope.c
+++ b/src/tmpl-scope.c
@@ -21,9 +21,12 @@
struct _TmplScope
{
- volatile gint ref_count;
- TmplScope *parent;
- GHashTable *symbols;
+ volatile gint ref_count;
+ TmplScope *parent;
+ GHashTable *symbols;
+ TmplScopeResolver resolver;
+ gpointer resolver_data;
+ GDestroyNotify resolver_destroy;
};
G_DEFINE_BOXED_TYPE (TmplScope, tmpl_scope, tmpl_scope_ref, tmpl_scope_unref)
@@ -47,6 +50,10 @@ tmpl_scope_unref (TmplScope *self)
if (g_atomic_int_dec_and_test (&self->ref_count))
{
+ if (self->resolver_destroy)
+ g_clear_pointer (&self->resolver_data, self->resolver_destroy);
+ self->resolver = NULL;
+ self->resolver_destroy = NULL;
g_clear_pointer (&self->symbols, g_hash_table_unref);
g_clear_pointer (&self->parent, tmpl_scope_unref);
g_slice_free (TmplScope, self);
@@ -99,6 +106,7 @@ tmpl_scope_get_full (TmplScope *self,
gboolean create)
{
TmplSymbol *symbol = NULL;
+ TmplScope *parent;
g_return_val_if_fail (self != NULL, NULL);
@@ -110,17 +118,22 @@ tmpl_scope_get_full (TmplScope *self,
}
/* Try to locate the symbol in a parent scope */
- if (symbol == NULL)
+ for (parent = self->parent; parent != NULL; parent = parent->parent)
{
- TmplScope *parent;
+ if (parent->symbols != NULL)
+ {
+ if ((symbol = g_hash_table_lookup (parent->symbols, name)))
+ return symbol;
+ }
+ }
- for (parent = self->parent; parent != NULL; parent = parent->parent)
+ /* Call our resolver helper to locate the symbol */
+ for (parent = self; parent != NULL; parent = parent->parent)
+ {
+ if (parent->resolver)
{
- if (parent->symbols != NULL)
- {
- if ((symbol = g_hash_table_lookup (parent->symbols, name)))
- return symbol;
- }
+ if (parent->resolver (parent, name, &symbol, parent->resolver_data) && symbol)
+ goto save_symbol;
}
}
@@ -128,15 +141,20 @@ tmpl_scope_get_full (TmplScope *self,
{
/* Define the symbol in this scope */
symbol = tmpl_symbol_new ();
- if (self->symbols == NULL)
- self->symbols = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify)tmpl_symbol_unref);
- g_hash_table_insert (self->symbols, g_strdup (name), symbol);
+ goto save_symbol;
}
return symbol;
+
+save_symbol:
+ if (self->symbols == NULL)
+ self->symbols = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)tmpl_symbol_unref);
+ g_hash_table_insert (self->symbols, g_strdup (name), symbol);
+
+ return symbol;
}
/**
@@ -166,3 +184,28 @@ tmpl_scope_peek (TmplScope *self,
{
return tmpl_scope_get_full (self, name, FALSE);
}
+
+void
+tmpl_scope_set_resolver (TmplScope *self,
+ TmplScopeResolver resolver,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (self != NULL);
+
+ if (resolver != self->resolver ||
+ user_data != self->resolver_data ||
+ destroy != self->resolver_destroy)
+ {
+ if (self->resolver && self->resolver_destroy && self->resolver_data)
+ {
+ g_clear_pointer (&self->resolver_data, self->resolver_destroy);
+ self->resolver_destroy = NULL;
+ self->resolver = NULL;
+ }
+
+ self->resolver = resolver;
+ self->resolver_data = user_data;
+ self->resolver_destroy = destroy;
+ }
+}
diff --git a/src/tmpl-scope.h b/src/tmpl-scope.h
index 60efd9a..12e1871 100644
--- a/src/tmpl-scope.h
+++ b/src/tmpl-scope.h
@@ -27,17 +27,26 @@
G_BEGIN_DECLS
+typedef gboolean (*TmplScopeResolver) (TmplScope *scope,
+ const gchar *name,
+ TmplSymbol **symbol,
+ gpointer user_data);
+
TmplScope *tmpl_scope_new (void);
-TmplScope *tmpl_scope_new_with_parent (TmplScope *parent);
-TmplScope *tmpl_scope_ref (TmplScope *self);
-void tmpl_scope_unref (TmplScope *self);
-TmplSymbol *tmpl_scope_peek (TmplScope *self,
- const gchar *name);
-TmplSymbol *tmpl_scope_get (TmplScope *self,
- const gchar *name);
-void tmpl_scope_set (TmplScope *self,
- const gchar *name,
- TmplSymbol *symbol);
+TmplScope *tmpl_scope_new_with_parent (TmplScope *parent);
+TmplScope *tmpl_scope_ref (TmplScope *self);
+void tmpl_scope_unref (TmplScope *self);
+TmplSymbol *tmpl_scope_peek (TmplScope *self,
+ const gchar *name);
+TmplSymbol *tmpl_scope_get (TmplScope *self,
+ const gchar *name);
+void tmpl_scope_set (TmplScope *self,
+ const gchar *name,
+ TmplSymbol *symbol);
+void tmpl_scope_set_resolver (TmplScope *self,
+ TmplScopeResolver resolver,
+ gpointer user_data,
+ GDestroyNotify destroy);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TmplScope, tmpl_scope_unref)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]